【问题标题】:Node.js and Express: wait for asynchronous operation before responding to HTTP requestNode.js 和 Express:在响应 HTTP 请求之前等待异步操作
【发布时间】:2019-09-30 19:32:56
【问题描述】:

假设有一个 HTTP GET 回调定义为:

router.get('/latestpost', function(req, res, next) {

    var data = new FbData();
    get_latest_post (data);
    get_post_image (data);

    res.json(data);
};

两个get_ 函数都使用fb package 生成HTTP 请求并在完成时执行回调。如何修改上述 GET 回调以等待 Facebook 的响应,然后才向客户端发送响应?

当时我通过连续执行get_ 函数并将res(响应)参数传递给它们来解决问题,最后一个函数发送响应:

router.get('/latestpost', function(req, res, next) {
    var data = new FbData();
    get_latest_post (res, data);
};


function get_latest_post (res, data) {

    FB.api(_url, function (res_fb) {

        if(!res_fb || res_fb.error) {
            console.log(!res_fb ? 'error occurred' : res_fb.error);
            return;
        }

        // Do stuff with data

        get_post_image (res, data);
    });
}


function get_post_image (res, data) {

    FB.api(_url, function (res_fb) {

        if(!res_fb || res_fb.error) {
            console.log(!res_fb ? 'error occurred' : res_fb.error);
            return;
        }

        // Do stuff with data

        /* At the end send the post data to the client */
        res.json(data);
    });
}

我找到了a similar question,但我正在考虑它,因为我找不到将解决方案应用于我的问题的正确方法。我曾尝试使用in this manual 描述的模式,但我无法使用 Promise 或 async/await 来执行它。有人可以指出我正确的方向吗?

【问题讨论】:

    标签: javascript node.js express promise async-await


    【解决方案1】:

    您的 API 可以轻松修改以返回一个承诺:

     function get_post_image (res, data) {
       return new Promise((resolve, reject) => {
        FB.api(_url, function (res_fb) {
          if(!res_fb || res_fb.error) {
            reject(res_fb && res_fb.error);
          } else resolve(res_fb/*?*/);
       });
     }
    

    既然你有一个承诺,你可以等待它:

     router.get('/latestpost', async function(req, res, next) {
       const data = new FbData();
       const image = await get_post_image (data);
    
       res.json(data);
    });
    

    【讨论】:

    • 最好将await 包装在try 中并将捕获的错误传递给next(),这样您就不会遇到未捕获的被拒绝承诺。但是您不能使用util.callbackify(),因为它会调用next(),并带有两个关于成功的参数,这是不需要的。
    • 可以定义const callbackify = fn => Object.defineProperty( (...args) => fn(...args.slice(0, -1)).catch(args.pop()), 'length', { value: fn.length + 1, configurable: true } );来处理express根据函数的arity推断中间件类型的方式,避免在每个@987654330中显式地try...catch @中间件。
    • 非常正确。我可能会考虑在我的下一个项目中使用它。
    • @patrick 我承认我还没有使用太多...我主要使用 Express 和一些自烘焙的包装器...
    猜你喜欢
    • 1970-01-01
    • 2020-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多