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

Ken*_*wok 1 javascript asynchronous promise

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

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

假设我有一个图书馆桌子。图书馆的桌子上有很多书。一本书有很多页。一个页面有很多照片。

我还使用 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"

        }

    ]
} 
Run Code Online (Sandbox Code Playgroud)

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

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

                })
        }
    })

}
Run Code Online (Sandbox Code Playgroud)

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

jfr*_*d00 5

不清楚您要问什么,但在for循环内,您可以用链接替换嵌套。所以像这样:

       asyncCallB(A)
        .then((B) => {
            asyncCallC(B)
            .then((C) => {
                asyncCallD(C)
            })
        })
Run Code Online (Sandbox Code Playgroud)

可以用这个替换:

       asyncCallB(A).then(B => {
         return asyncCallC(B);
       }).then(C => {
         return asyncCallD(C);
       });
Run Code Online (Sandbox Code Playgroud)

如果您希望一个for循环迭代等待前一个循环完成(尽管您没有显示从一个循环迭代到下一个循环迭代的任何依赖关系),那么您必须await与主循环承诺(以及父循环)一起使用函数必须被声明async) 或者你必须切换到不同的手动迭代方式而不是for循环。

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

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

    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
    });
Run Code Online (Sandbox Code Playgroud)

我还发现Bluebird promise 库对于迭代非常有用,因为它具有诸如Promise.map(), 之类的东西Promise.each()Promise.reduce()并且Promise.mapSeries()可以为您提供对迭代的一些控制(包括它是并行还是串行以及您想要允许的并发量)并执行更多为你工作。

相关回答:

在循环中将 Promise 与 fs.readFile 一起使用

蓝鸟承诺的正确 while() 循环(没有递归?)

如何同步一系列承诺?

条件是承诺的Javascript while循环

bluebirdjs 承诺包裹在 for 循环中

如何在 vanilla javascript 中的 for 循环中链接承诺

如何在循环中链接异步 ajax 函数

JavaScript:同步执行一系列承诺