如何让Promise在返回前resolve?Node.js异步请求问题求助
问题排查与修复方案
兄弟,我一眼就看出你遇到的核心问题——递归调用getPing时没正确衔接Promise链,导致最初创建的Promise一直处于Pending状态,自然触发不了.then()回调。咱们一步步拆解问题和解决办法:
问题根源分析
- 当
index < o.TotalCollectionSize时,你直接调用了getPing(id, index),但这个新生成的Promise和外层(第一次调用getPing返回的)Promise完全没关联。外层Promise既没被resolve也没被reject,客户端的.then()永远不会执行。 - 还有几个隐藏坑:如果响应没有
gzip编码,整个Promise会直接“挂死”;要是games.gameservers为空,随机选服务器的代码会报错。
修复后的代码
修正getPing函数
var getPing = function (id, index) { return new Promise(function (resolve, reject) { var keepAliveAgent = new https.Agent({ keepAlive: true }) options.agent = keepAliveAgent index = index || 0; var r = https.request(options, function (res) { var data = [] res.on('data', function (d) { data.push(d) }).on('end', function () { var buf = Buffer.concat(data) var encodingheader = res.headers['content-encoding'] // 处理非gzip编码的情况,避免Promise挂死 if (!encodingheader || encodingheader !== 'gzip') { try { var o = JSON.parse(buf.toString()) handleResponse(o, index, resolve, reject) } catch (err) { reject('Failed to parse non-gzip response: ' + err.message) } return } zlib.gunzip(buf, function (err, buffer) { if (err) { reject('Gunzip error: ' + err.message) return } try { var o = JSON.parse(buffer.toString()) handleResponse(o, index, resolve, reject) } catch (err) { reject('Failed to parse gzipped response: ' + err.message) } }) }) }) // 处理请求错误,避免Promise挂死 r.on('error', function(err) { reject('Request error: ' + err.message) }) r.end() }) // 把响应处理逻辑抽成单独函数,更清晰 function handleResponse(o, index, resolve, reject) { if (o.TotalCollectionSize - 20 <= index) { console.log(o.TotalCollectionSize - 20, '<=', index) // 增加空数组判断,避免报错 if (games.gameservers.length === 0) { reject('No valid game servers found') return } var selectedserver = games.gameservers[Math.floor(Math.random() * games.gameservers.length)] console.log(selectedserver) resolve(selectedserver) return; } if (index < o.TotalCollectionSize) { index = index + 10; console.log(index, o.TotalCollectionSize) o.Collection.sort(function (a, b) { return a.Ping - b.Ping // 这里修正排序逻辑,原来返回布尔值是错误的,要返回数值差 }) if (typeof o.Collection[0] !== "undefined") { var playerscapacity = o.Collection[0].PlayersCapacity.charAt(0) if (playerscapacity !== o.Collection[0].Capacity) { games.gameservers.push(o.Collection[0]) } } // 关键修改:递归调用后,把新Promise的结果传递给外层Promise getPing(id, index).then(resolve).catch(reject) } else { // 处理index超出范围但未满足结束条件的情况 reject('Index exceeds TotalCollectionSize without finding valid server') } } }
关键修改点说明
- 衔接递归Promise链:递归调用
getPing时,通过getPing(id, index).then(resolve).catch(reject)把新Promise的结果传递给外层Promise,让整个调用链的状态能正确流转。 - 修复排序逻辑:原来的
sort回调返回布尔值是错误的,改成返回a.Ping - b.Ping才能实现Ping值从低到高的正确排序。 - 补全异常分支:增加了请求错误、非gzip响应、空服务器数组等边界情况的
reject处理,彻底避免Promise“挂死”。 - 优化代码结构:把重复的响应解析逻辑抽成
handleResponse函数,可读性和维护性都更好。
服务器端代码小优化
在getPing调用的.catch里加上响应结束逻辑,避免客户端一直等待:
getPing(game.placeId, 0).then(function (r) { console.log(r) res.end(JSON.stringify(r)) }).catch(function (e) { console.log(e) res.writeHead(500, { 'Content-Type': 'application/json' }) res.end(JSON.stringify({ error: e })) })
这样修改后,你的Promise链就能正确传递状态,.then()回调也能正常触发了。
内容的提问来源于stack exchange,提问作者netsocket
相关产品推荐
相关产品推荐

