【问题标题】:How to wait until callback is called如何等到回调被调用
【发布时间】:2019-05-22 20:59:59
【问题描述】:

我有一个执行长时间计算的函数,一旦完成,就会调用一个作为参数传递的回调函数。 我在 Koa 路由器中查询这个函数,需要将长时间计算的结果返回给浏览器。函数来自库,我无法更改其接口(即,我可以更改回调的代码,但无法更改 someLongComputation 以返回承诺)

当前代码集ctx.body 立即返回,someLongComputation 立即返回。知道如何等到回调被调用,然后才使用回调的结果设置ctx.body

router.post(`/abc`, async (ctx) => {
  try {
      someLongComputation(function(err, res) {
          if(err) {
              console.log(err);
          }
      }
      ctx.body = {
        status: 'success',
        data: {'res' : ""}, 
        errors: []
      };
  } catch (err) {
      console.log(err)
  }
})

【问题讨论】:

  • 是的,您可以更改 someLongComputation() 以使用承诺:require('util').promisify(someLongComputation) 返回您可以使用 await 的函数版本。
  • 为简单起见,我省略了 someLongComputation 函数的实际名称。我正在尝试使用在调整大小后运行的 graphicsmagic 流函数来做到这一点: gm(request(photo)).resize(size[0], size[1]).stream 。在该代码上使用 promisify 似乎会返回错误:TypeError: format.split is not a function

标签: node.js koa async.js


【解决方案1】:

你有两个选择。

1。从您的回调中发送响应

router.post(`/abc`, async (ctx) => {
  try {
    someLongComputation(function(err, res) {
      if (err) {
        console.log(err);
        // you might want to send error response here
      }
      // send response from callback
      ctx.body = {
        status: 'success',
        data: { res: '' },
        errors: []
      };
    });
  } catch (err) {
    console.log(err);
    // you might want to send error response here as well
  }
});

2。从您的库函数中创建一个承诺并使用async/await

const doLongComputation = () => {
  return new Promise((resolve, reject) => {
    try {
      someLongComputation(function(err, res) {
        if (err) {
          console.log(err);
          reject(err);
        }
        resolve(res);
      });
    } catch (err) {
      console.log(err);
      reject(err);
    }
  });
};

router.post(`/abc`, async (ctx) => {
  try {
    const res = await doLongComputation();
    ctx.body = {
      status: 'success',
      data: { res: '' },
      errors: []
    };
  } catch (err) {
    console.log(err);
    // send error response here
  }
});

【讨论】:

    【解决方案2】:

    如果您想使用 async/await 并假设 longcomputation 函数可以返回一个 Promise,您可以更改您的代码以等待该函数的返回。

    router.post(`/abc`, async (ctx) => {
      try {
        const result = await someLongComputation();
        // do whatever you want with result
    
      } catch (err) {
        console.log(err)
      }
    })
    

    另一种选择是在函数的回调中使用变量

    router.post(`/abc`, async (ctx) => {
      try {
        someLongComputation(function(err, res) {
          if(err) {
              console.log(err);
          }
          //moved setting the body to inside the callback for the computation
          ctx.body = {
            status: 'success',
            data: {'res' : ""}, 
            errors: []
          };
        }
      } catch (err) {
        console.log(err)
      }
    })
    

    【讨论】:

    • 谢谢彼得的回答。您的第一个解决方案将不起作用,因为我无法更改功能。我已经更新了我的问题以明确说明它的库函数。我刚刚测试了第二种解决方案,代码立即返回 404。
    • @user1217406 你是说你无法修改提供给someLongComputation()的匿名回调函数?总的来说,我很难弄清楚你认为什么是你可以修改的代码和你不能修改的代码
    • 进一步编辑了问题。我可以更改回调,但我无法更改 someLongComputation 以使用承诺或以任何其他方式更改其接口。
    • 如果您在回调中设置响应,我不确定为什么它会返回 404。另一个选项在下面的答案中。将您长期运行的函数包装在一个返回承诺然后等待该结果的函数中。我不知道引用另一个人的答案的礼仪是什么,但遵循@DaneshPandiyan 概述的答案应该会有所帮助
    猜你喜欢
    • 2017-09-03
    • 1970-01-01
    • 2021-01-25
    • 2021-08-01
    • 1970-01-01
    • 2014-02-06
    • 2018-09-19
    • 1970-01-01
    • 2011-06-27
    相关资源
    最近更新 更多