Promise 在循环调用提供者完成之前解决

Promise resolves before looping calls to provider finish

我 运行 遇到 Ionic 3 应用程序代码的问题。

基本上,我有一个对象列表,所有对象都具有唯一 ID。每个对象的唯一 ID 必须通过 GET 请求发送,以便我们可以从服务器为每个对象取回适当的数据。这必须在每个对象的基础上完成;我无法将它们捆绑到一个请求中,因为没有 API 端点。

因此对象都存储在一个数组中,所以我一直在尝试遍历数组并为每个对象调用提供程序。请注意,提供者正在 returning 一个 observable。

由于提供程序是一个异步函数,所以承诺将在循环结束之前解决,除非我使承诺解决超时。这违背了承诺的全部意义。

执行此操作的正确方法是什么,以便在 promise 解析之前完成循环提供程序调用?

如果我有一个内在承诺在循环完成时解决,它不会也过早解决吗?

我还读到说打开一堆 observables 是不好的。我是否应该使用 toPromise() 代替 return 每个可观察到的承诺?

这里是构建数据的代码:

asyncBuildData() {
    var promise = new Promise((resolve, reject) => {
        let completedRequests = 0;
        for (let i = 0; i < 10; i++) {
            this.provider.getStuffById(listOfStuff[i].id).subscribe(val => {
                list.push(val)
                completedRequests++;
            })
        }
        console.log('cp', completedRequests); // completedRequests = 0
        setTimeout(() => {
            console.log('cp', completedRequests); // completedRequests = 10
            let done = true;
            if (done) {
                resolve('Done');
            } else {
                reject('Not done');
            }
        }, 1500)
    })
    return promise;
}

提供商代码:

getStuffById(stuffId) {
    let url = url + stuffId;
    return this.http.get(url)
        .map(res => res.json());
}

即使您不能将它们捆绑到一个请求中,您仍然可以将它们捆绑到 一个 observable 中,其中这些请求是并行触发的,使用 .forkJoin():

buildData$() {
    let parallelRequests = listOfStuffs.map(stuff => this.provider.getStuffById(stuff.id));

    return Observable.forkJoin([...parallelRequests]);
}

然后在您的组件中,您可以调用:

buildData$.subscribe(val=>{
    //val is an array of all the results of this.provider.getStuffById()
    list =val;
})

请注意,Obersvable.forkJoin() 将在发出任何值之前完成所有请求。

如果我理解正确,那么下面的代码应该可以帮助您。这将为数组中的每个元素一次执行一个承诺。

        var ids = [1,2,3,4,5];

        ids.reduce(function (promise, id) {
            return promise.then(function () {
                let url = url + id;
                return this.http.get(url)
                           .map(res => res.json());
            });
        }, Promise.resolve()).then(function(last) {
            // handle last result
        }, function(err) {
            // handle errors
        });

我用 jQuery post 测试了这个,并用你的 Ionic 替换了它。如果失败请告诉我。