JavaScript Promise问题求助:http.get回调未执行及await实现疑问
问题原因分析
1. 同步循环阻塞事件循环
你的do-while是同步循环,移除break后会瞬间创建25000个Promise并发起HTTP请求。Node.js的事件循环机制中,同步代码优先执行,所有同步循环逻辑跑完前,http.get这类异步I/O的回调根本没机会被处理。同时,Node.js HTTP客户端默认对每个域名限制5个并发连接,瞬间发起上万请求会耗尽socket池,导致请求发不出去,服务器收不到请求、回调自然也不会执行。
2. 无效的"等待"逻辑
你用blnNext试图控制循环,但同步代码不会因为异步操作暂停——blnNext = false后,continue不会等Promise完成,循环直接进入下一轮,完全达不到"等上一个请求完成再发下一个"的目的。
3. 带break时能执行一次的原因
当有break时,循环只执行一次,同步代码很快跑完,事件循环有机会处理http.get的异步回调,所以能完成一次请求。
用async/await实现可控循环请求
下面提供两种常见实现方式,按需选择:
方案1:串行请求(逐个完成再发起下一个)
适合需要按顺序处理响应、或不想给服务器造成过大压力的场景:
const http = require('http'); // 确保引入http模块 async function runRequests() { const totalRequests = 25000; for (let intRequest = 1; intRequest <= totalRequests; intRequest++) { try { info.msg(`Request#${intRequest}`); info.msg("Creating promise"); // await等待当前请求完成 const data = await new Promise((myResolve, myError) => { const cstrURI = "http://localhost:8000/" + "?cn=Tesla&cy=2024&cm=1&cd=8&ds=clickcomp&rt=10&u=1"; http.get(cstrURI, res => { let data = []; const headerDate = res.headers && res.headers.date ? res.headers.date : 'no response date'; info.msg('Status Code:', res.statusCode); info.msg('Date in Response header:', headerDate); res.on("data", chunk => { data.push(chunk); }); res.on('end', () => { info.msg('Response ended: '); // 将Buffer数组转为字符串,方便查看内容 myResolve(Buffer.concat(data).toString()); }); }).on("error", err => { const strMsg = `ERROR:${err.message}`; info.msg(defs.RED + strMsg + defs.RESET); myError(strMsg); }); }); console.log(`myPromise.resolve(${data})`); } catch (strError) { console.log(`myPromise.reject(${strError})`); // 可选:遇到错误是否继续循环,这里选择继续执行后续请求 continue; } } } // 启动执行 runRequests();
方案2:可控并发请求(同时发起N个请求)
如果需要更高执行效率,又不想压垮服务器,可以限制并发数:
const http = require('http'); async function runConcurrentRequests(totalRequests, concurrency = 10) { // 用信号量控制并发数 const semaphore = new Array(concurrency).fill(Promise.resolve()); for (let intRequest = 1; intRequest <= totalRequests; intRequest++) { // 找到信号量中已完成的位置,复用它发起新请求 const availableIndex = semaphore.findIndex(p => p.isFulfilled || p.isRejected); semaphore[availableIndex] = semaphore[availableIndex].then(async () => { try { info.msg(`Request#${intRequest}`); info.msg("Creating promise"); const data = await new Promise((myResolve, myError) => { const cstrURI = "http://localhost:8000/" + "?cn=Tesla&cy=2024&cm=1&cd=8&ds=clickcomp&rt=10&u=1"; http.get(cstrURI, res => { let data = []; const headerDate = res.headers && res.headers.date ? res.headers.date : 'no response date'; info.msg('Status Code:', res.statusCode); info.msg('Date in Response header:', headerDate); res.on("data", chunk => { data.push(chunk); }); res.on('end', () => { info.msg('Response ended: '); myResolve(Buffer.concat(data).toString()); }); }).on("error", err => { const strMsg = `ERROR:${err.message}`; info.msg(defs.RED + strMsg + defs.RESET); myError(strMsg); }); }); console.log(`myPromise.resolve(${data})`); } catch (strError) { console.log(`myPromise.reject(${strError})`); } }); } // 等待所有请求完成 await Promise.all(semaphore); } // 启动执行:总请求25000,并发10个 runConcurrentRequests(25000, 10);
关键说明
async/await必须在async函数中使用,通过await等待Promise完成,让异步代码逻辑更清晰,同时正确控制执行顺序。- 串行请求简单易维护,但执行速度慢;并发请求效率更高,但要根据服务器承受能力设置合理的并发数。
- 原代码中
data是Buffer数组,建议用Buffer.concat(data).toString()转为字符串,方便查看响应内容。
内容的提问来源于stack exchange,提问作者SPlatten
相关产品推荐
相关产品推荐

