You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Promise在返回前resolve?Node.js异步请求问题求助

问题排查与修复方案

兄弟,我一眼就看出你遇到的核心问题——递归调用getPing时没正确衔接Promise链,导致最初创建的Promise一直处于Pending状态,自然触发不了.then()回调。咱们一步步拆解问题和解决办法:

问题根源分析

  1. 当index < o.TotalCollectionSize时,你直接调用了getPing(id, index),但这个新生成的Promise和外层(第一次调用getPing返回的)Promise完全没关联。外层Promise既没被resolve也没被reject,客户端的.then()永远不会执行。
  2. 还有几个隐藏坑:如果响应没有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')
    }
  }
}

关键修改点说明

  1. 衔接递归Promise链:递归调用getPing时,通过getPing(id, index).then(resolve).catch(reject)把新Promise的结果传递给外层Promise,让整个调用链的状态能正确流转。
  2. 修复排序逻辑:原来的sort回调返回布尔值是错误的,改成返回a.Ping - b.Ping才能实现Ping值从低到高的正确排序。
  3. 补全异常分支:增加了请求错误、非gzip响应、空服务器数组等边界情况的reject处理,彻底避免Promise“挂死”。
  4. 优化代码结构:把重复的响应解析逻辑抽成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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:25:24