任何承诺完成后,是否有可能履行承诺?

时间:2016-01-10 09:00:10

标签: javascript node.js promise

我想要一个网址请求的网址数组。我想与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);
})

3 个答案:

答案 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));