我应该如何构建处理多个依赖异步任务的承诺?

时间:2017-11-05 15:15:53

标签: javascript asynchronous promise

我读了一些示例,如何重构代码以适应承诺的风格,但似乎they可能需要其他承诺库的帮助。

我的问题是我有多个异步任务,其中一些可能依赖于另一个调用的某些信息。 所以我的代码看起来像这样:

我们说我有一张图书馆桌子。图书馆表有很多书。一本书有很多页面。一页有很多照片。

我也在使用LoopBack为这些表创建实例。

我有一个这种格式的库对象数组。

{
    "location": "Hong Kong Island",
    "size": "25sq meter",
    "availableBooks" : [
        {
            "bookName": "Harry Potter",
            "pages": 235,
            "author": "J R Rowling"
            "pages": [
                {
                    "page": 1,
                    "content": "XXX",
                    "photos": [
                        {
                            "urlLink": "https://someLink",
                            "size": "360X250"
                        },
                        {
                            "urlLink": "https://google",
                            "size": "650X250"
                        }

                    ]
                }
                ,
                {
                    "page": 2,
                    "content": "XXX"
                }
            ]
        },
        {
            "bookName": "Lord Of The Rings",
            "pages": 335,
            "author": "J. R. R. Tolkien"

        }

    ]
} 

对于伪代码,它看起来像这样。

for(something){
    asyncCallA()
    .then((A) => {
        for(something){
            asyncCallB(A)
                .then((B) => {
                    for(something){
                        asyncCallC(B)
                        .then((C) => {
                            for(something){
                                asyncCallD(C)
                            }
                        })
                    }

                })
        }
    })

}

对于常见情况,我了解如何使用promise来链接异步操作。但是在这种情况下异步调用相互依赖并且调用很多for循环,我不知道如何扁平化调用。任何人都可以提供一些见解吗?感谢。

2 个答案:

答案 0 :(得分:3)

目前还不清楚你在问什么,但在for循环中,你可以用链接代替嵌套。所以像这样:

       asyncCallB(A)
        .then((B) => {
            asyncCallC(B)
            .then((C) => {
                asyncCallD(C)
            })
        })

可以替换为:

       asyncCallB(A).then(B => {
         return asyncCallC(B);
       }).then(C => {
         return asyncCallD(C);
       });

如果你想要一个for循环迭代等待前一个迭代完成(虽然你不会显示从一个循环迭代到下一个循环迭代的任何依赖),那么你必须要么将await与主循环承诺一起使用(并且必须将父函数声明为async),或者必须切换到手动迭代而不是for循环的其他方式。

    for(...) {
       let loopResult = await asyncCallB(A).then(B => {
         return asyncCallC(B);
       }).then(C => {
         return asyncCallD(C);
       });
    }

或者,很多时候,循环的各种迭代可以并行进行,但是你想知道它们何时完成:

    let promises = [];
    for(...) {
       let p = asyncCallB(A).then(B => {
         return asyncCallC(B);
       }).then(C => {
         return asyncCallD(C);
       });
       promises.push(p)
    }
    Promise.all(promises).then(results => {
       // all promises in the loop done now
    });

我还发现Bluebird promise library对于迭代非常有用,因为它提供的内容包括Promise.map()Promise.each()Promise.reduce()Promise.mapSeries()你可以控制迭代(包括它的并行或串行以及你想要允许多少并发),并为你做更多的工作。

相关答案:

Using Promises with fs.readFile in a loop

Proper while() loop for bluebird promises (without recursion?)

How to synchronize a sequence of promises?

Javascript while loop where condition is a promise

bluebirdjs promises wrapped inside a for loop

How to chain promises in for loop in vanilla javascript

How to chain an async ajax function in a loop

JavaScript: Perform a chain of promises synchronously

答案 1 :(得分:1)

如果您使用的是ES7,则可以使用async / await。这是一个例子:

for(something){
    let A = await asyncCallA();
    for(something){
        let B = await asyncCallB(A);
    }
}

Node.JS 7.4.0及之后支持此项而没有任何实验性标志。