【问题标题】:callback to make sure the async api request is complete回调以确保异步 api 请求完成
【发布时间】:2026-02-13 17:05:02
【问题描述】:

我知道已经有数十万个关于这个主题的线程,我已经研究这个问题几天了,但我仍然不明白如何应用我的例子'已经处理了我的案子。

我从这样的 API 调用开始:

const getReleaseUrl = (discogsId) => { 
  db.getRelease(discogsId, (err, data) => {
    return data.uri
  }) 
}

console.log(getReleaseUrl("53130"));
// => undefined

如何确保我的应用首先接收数据,防止 undefined 返回?我是否需要以某种方式确保 db 被定义并首先使用我的客户端 ID 连接到远程数据库?我是否需要编写一个函数以某种方式捕获undefined 结果并不断运行 API 调用,直到结果有所不同?设置超时似乎不是一个好的永久解决方案。我尝试编写这样的 Promise 链并得到 TypeError: db.getRelease(...).then is not a function 错误:

const getReleaseUrl = (discogsId) => { 
  db.getRelease(discogsId, (err, data) => {
    return data
  })
  .then((data) => {
    return data.uri
  })   
}

console.log(getReleaseUrl("53130"));

【问题讨论】:

标签: javascript node.js asynchronous


【解决方案1】:

按照您的编码方式,您的控制台消息不可能返回除undefined 之外的任何内容。

首先,您的方法没有返回语句。当然,回调有一个 return 语句,但这并不重要。没有返回声明,没有什么可记录的。使用您定义的方法,您能做的最好的就是在回调中放置一个控制台消息

const getReleaseUrl = (discogsId) => { 
  db.getRelease(discogsId, (err, data) => {
    console.log(data.uri);
    return data.uri
  }) 
}

getReleaseUrl("53130");

更好的选择是重写您的函数以接受回调作为参数:

const getReleaseUrl = (discogsId, callback) => { 
  db.getRelease(discogsId, callback);
}

getRelaseUrl("53130", (err, data) => {
  console.log(data.uri);
});

在这里,您将有关如何处理返回数据的逻辑移出主函数,这为您提供了更大的灵活性。它还确保在数据准备好之前不会调用日志消息。

【讨论】:

  • 好的,但最终这个逻辑将进入路由定义,它只需要返回值,没有控制台日志记录。我知道 OP 中的代码以控制台日志结尾,但这更多是为了查看代码输出的内容。 console.log(getReleaseUrl('53130', (err, data) => { return data.uri })) 再次给出 undefined
  • 当然返回未定义。您必须了解异步函数的工作方式与同步函数不同。它们不返回直接值。您必须使用此回调模式或承诺。无论哪种方式,您都将定义一个稍后将调用的函数。没有办法解决这个问题。
  • 好的,我现在明白了,但您的主要回复中没有解释
【解决方案2】:

查看db.getRelease之前添加的返回:

使用node.js util 承诺db.getRelease

var util = require('util');
var getRelease = util.promisify(db.getRelease);

返回整个数据:

const getReleaseUrl = (discogsId) => {       
  return getRelease(discogsId); 
}

或返回特定的:

const getReleaseUrl = (discogsId) => {       
      return getRelease(discogsId)
             .then(function(data){ 
                  return data.uri;
             }); 
}        

【讨论】:

  • 返回我的 Discogs 客户端数据,而不是 discogsId 的音乐发布数据
  • 是的——它会返回你可以调用的promise .then(function(data){// access data here })
  • 我不得不取消选中你的答案,因为它对我来说并不能一直有效,毕竟。我有var apiGetCall = util.promisify(db.getRelease(discogsId))return apiGetCall 给出The "original" argument must be of type Function 错误。
【解决方案3】:

您可以通过回调或使用 Promise。 让我们看一下 promise 选项:

const getReleaseUrl = (discogsId) => {
  return new Promise((resolve, reject) => {
    db.getRelease(discogsId, (err, data) => {
      if (err) {
        reject(err);
      }

      resolve(data);
    });
  });
};

getReleaseUrl("53130")
  .then(console.log);
  .catch(console.error);

问题在于,正如您所说,对 db.getRelease 的调用是异步的,因此 getReleaseUrl 不会返回任何内容。 查看 Pop-A-Stash 对回调选项的回答。

【讨论】:

    【解决方案4】:

    看起来 db.getRelease 已经接受了回调,因此您可以在那里处理成功和错误。

    您的 getReleaseUrl 函数不返回任何内容。从箭头函数中删除花括号或添加返回语句。

    【讨论】:

      【解决方案5】:

      使用承诺

      var promise1 = new Promise(function(resolve, reject) {
      resolve('Success!');
      });
      
      promise1.then(function(value) {
      console.log(value);
      // expected output: "Success!"
      });
      

      按照此处的步骤操作: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then

      【讨论】: