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 替换了它。如果失败请告诉我。
我 运行 遇到 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 替换了它。如果失败请告诉我。