简体   繁体   English

使用 Google Cloud Functions Node.JS 等待多个异步函数的正确方法

[英]Proper way to await multiple async functions with Google Cloud Functions Node.JS

I am relatively new to the async world of Javascript.我对 Javascript 的异步世界比较陌生。 My function makes some calls to the Firebase Admin SDK and also some fetch requests to a third party API.我的 function 对 Firebase 管理员 SDK 进行了一些调用,并对第三方 ZDB974238DZ08A3 进行了一些获取请求。 The function works, but every once in a while I get a socket hang up error. function 工作,但每隔一段时间我就会收到一个socket hang up错误。 I essentially want to wait until all the await functions complete before sending res.end() , but it looks like I am doing something wrong in terms of my use of async/await .我基本上想等到所有 await 函数完成后再发送res.end() ,但看起来我在使用async/await方面做错了。

My function finishes (looks like it hits res.end() ) but it keeps continuing on:我的 function 完成(看起来像命中res.end() )但它继续:

在此处输入图像描述

And then strangely enough, an error from the same execution ID shows up in the following execution ID:然后奇怪的是,来自相同执行 ID 的错误出现在以下执行 ID 中:

在此处输入图像描述

Here is how I am structuring my code:这是我构建代码的方式:

exports.myFunction = async (req, res) => {

    // parse the body...

    // if it's a closed order 
    if (json.hasOwnProperty('closed_at')) {

        // get order object from orders directory
        await ordersRef.once("value", async function(snapshot) {
            var orderResponseObj = snapshot.val();

            // do some stuff with orderResponseObj

            // ** res.end() CALLED BEFORE THIS HAPPENS **
            await deleteRef.once("value", async function(snapshot) {
                var deleteResponseObj = snapshot.val();
                // do some stuff with the delete object
            });

            // get object from shop directory
            await shopInfoRef.once("value", async function(snapshot) {
                var firebaseResponseObj = snapshot.val();

                await updateInventory.updateInventory(); // do some fetch request to 3rd party API

                await deleteProduct.deleteProduct(); // do another fetch call to 3rd party API
            });
        });
    }
    // terminate the cloud function
    res.end();
}

So you have some nested promises that will not actually wait all of them to be completed, your structure is like this:所以你有一些嵌套的承诺,实际上不会等待所有承诺完成,你的结构是这样的:

|   1 exports.myFunction
|   |   1 ordersRef.once
|   |   |   1 deleteRef.once
|   |   |   2 shopInfoRef.once
|   |   |   |   1 updateInventory.updateInventory
|   |   |   |   2 deleteProduct.deleteProduct

The fact is that your async functions will only await for the first lower level promises, so for example deleteRef.once will just await for shopInfoRef.once , but not for updateInventory.updateInventory .事实上,您的异步函数只会等待第一个较低级别的承诺,例如deleteRef.once只会等待shopInfoRef.once ,而不是等待updateInventory.updateInventory This means that your top level exports.myFunction will wait only that ordersRef.once resolves, ignoring the rest.这意味着您的顶级exports.myFunction将只等待ordersRef.once解析,忽略rest。 The numbers indicate the order of the execution of the promises, since you are using await for all of them, we have no promise on the same level firing togheter (no duplicated numbers).数字表示承诺的执行顺序,因为您对所有承诺都使用等待,所以我们在同一级别上没有 promise 一起触发(没有重复的数字)。

Now in order to wait for the end of all the function cycles you can implement your own chain of promises.现在,为了等待所有 function 周期结束,您可以实现自己的承诺链。 Looking at your code, the very last promise to await is the deleteProduct.deleteProduct , because when you reach that point, any other promise is resolved, because of all the await keywords.查看您的代码,等待的最后一个 promise 是deleteProduct.deleteProduct ,因为当您到达该点时,由于所有await关键字,任何其他 promise 都已解决。

exports.myFunction = async (req, res) => {

    // parse the body...

    // if it's a closed order 
    if (json.hasOwnProperty('closed_at')) {
     let awaiter = new Promise((resolve) => {
        // get order object from orders directory
        await ordersRef.once("value", async function(snapshot) {
            var orderResponseObj = snapshot.val();

            // do some stuff with orderResponseObj

            // ** res.end() CALLED BEFORE THIS HAPPENS **
            await deleteRef.once("value", async function(snapshot) {
                var deleteResponseObj = snapshot.val();
                // do some stuff with the delete object
            });

            // get object from shop directory
            await shopInfoRef.once("value", async function(snapshot) {
                var firebaseResponseObj = snapshot.val();

                await updateInventory.updateInventory(); // do some fetch request to 3rd party API

                await deleteProduct.deleteProduct(); // do another fetch call to 3rd party API

                resolve(); // we put resolve in the very last point of the chain
            });
        });
      });

      // await make the execution of your async function
      // wait until the "resolve" function of our "awaiter"
      // promise is called, so at the very last of the chain
      await awaiter;
    }
    // terminate the cloud function
    res.end();
}

Obviously you can contract the code in a form like await new Promise(resolve => {... }) , but I divided the two sentences just for sake of clarity.显然,您可以以await new Promise(resolve => {... })之类的形式收缩代码,但为了清楚起见,我将这两个句子分开。

The new structure results like this:新结构结果如下:

|   1 exports.myFunction
|   |   1 awaiter
|   |   -   1 ordersRef.once
|   |   -   |   1 deleteRef.once
|   |   -   |   2 shopInfoRef.once
|   |   -   |   |   1 updateInventory.updateInventory
|   |   -   |   |   2 deleteProduct.deleteProduct
|   |   ----------> 3 awaiter.resolve

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM