我想要一个网址请求的网址数组。我想与promises异步调用Web请求,并继续完成任何已完成的承诺链。现在我正在做
.then((lines) => {
var tasks = [];
lines.forEach((line) => {
tasks.push(() => { return rp(BASE_URL + line); });
});
return Promise.map(tasks, (job) => { return job(); }, { concurrency: 5 });
})
.then((info) => {
inspect('info: ' + info);
})
然而,问题是它在调用下一个.then()
之前等待所有任务完成
我想知道是否可以为任何已经解决的任务调用.then()并继续链接?
我猜我可以这样做:
.then((lines) => {
lines.forEach((line) => {
rp(BASE_URL + line)
.then((info) => {
inspect(info);
});
});
})
.then((a) => {
// all requests have been made
})
这开始类似于回调地狱,因为我正在嵌套我的.then(),并且在我遇到同样问题的其他一些情况下可能需要这样做。
我正在寻找的是:
.then((lines) => {
lines.forEach((line) => {
yield return rp(BASE_URL + line);
});
})
.then((info) => {
// will call inspect on each yield
inspect('info: ' + info);
})
答案 0 :(得分:1)
我想要一个网址请求的网址数组。我想与promises异步调用Web请求,并继续完成任何已完成的承诺链。
你会如何在同步代码中执行此操作? Promises模拟同步代码。
您将处理整个单个请求的逻辑放在函数中,然后map
处理该函数:
.map(processLine);
function processLine(line) {
return rp(BASE_URL + line).then(inspect);
}
了解这不是工件而是promise代理模型的核心属性非常重要。 Promise代表回调等单一任务 - 而不是像事件发射器这样的复数任务。
如果您感兴趣,可能需要考虑一个可观察的或更具反应性的系统,您也可以使用异步迭代器(实际上是您的"期望的#34;语法)。我使用了observable,因为它们在这里更容易使用,但两者都有效:
new Observable(obs => {
let reqs = lines.map(x => rp(BASE_URL + line));
let counter = reqs.length;
for(let req of reqs) {
req.then(v => {
obs.onNext(v);
if(!--counter) obs.onCompleted();
});
}
}).map(u => { // every new value is available here
console.log(u); // use flatMap and return a promise if you want
// promise like chaining behavior
});
答案 1 :(得分:0)
你可以使用.map和.each来整理你的回调地狱版本,以减少一些嵌套级别
.map((line) => {
return rp(BASE_URL + line);
}, {concurrency: 5})
.each((info) =>
inspect(info);
})
.then((a) => {
// all requests have been made
})
请注意,这确实与您的版本略有不同。 .each
回调只会在所有请求完成后运行。转向基于流的处理模型可以避免这种情况。
答案 2 :(得分:0)
你的"回调地狱"根本不是地狱,而是一种平行运行多个异步链的优雅方式,没有同步的等价物。
您在版本中错过了一个关键return
- 为什么我会喜欢隐含的箭头函数返回{}
- 并且您忽略了映射。
在es6中我会:
.then(lines => Promise.all(lines.map(line =>
rp(BASE_URL + line).then(info => inspect(info)))));
})
.then(allInspectResults => {
// all requests and inspections have been made
})
.catch(e => console.error(e));