Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/34.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 当任何承诺完成时,是否有可能履行承诺?_Javascript_Node.js_Promise - Fatal编程技术网

Javascript 当任何承诺完成时,是否有可能履行承诺?

Javascript 当任何承诺完成时,是否有可能履行承诺?,javascript,node.js,promise,Javascript,Node.js,Promise,我有一个URL数组,我想对其进行web请求。我想用承诺异步调用web请求,并为任何已完成的承诺继续链。现在我正在做 .then((lines) => { var tasks = []; lines.forEach((line) => { tasks.push(() => { return rp(BASE_URL + line); }); }); return Promise.map(tasks, (job) => { ret

我有一个URL数组,我想对其进行web请求。我想用承诺异步调用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((lines) => {
    lines.forEach((line) => {
        yield return rp(BASE_URL + line);
    });
})
.then((info) => {
    // will call inspect on each yield
    inspect('info: ' + info);
})
当我嵌套.then()时,这就开始了类似于回调地狱的事情,在其他一些遇到相同问题的情况下,可能需要这样做

我要找的是:

.then((lines) => {
    lines.forEach((line) => {
        rp(BASE_URL + line)
            .then((info) => {
                inspect(info);
            });
    });
})
.then((a) => {
    // all requests have been made
})
.then((lines) => {
    lines.forEach((line) => {
        yield return rp(BASE_URL + line);
    });
})
.then((info) => {
    // will call inspect on each yield
    inspect('info: ' + info);
})

您可以使用和稍微整理一下回调地狱版本,以降低一些嵌套级别

.map((line) => {
    return rp(BASE_URL + line);
}, {concurrency: 5})
.each((info) =>
    inspect(info);
})
.then((a) => {
    // all requests have been made
})
请注意,这与您的版本有点不同。
。每个
回调将仅在完成所有请求后运行。转向基于流的处理模型可以避免这种情况

我有一个URL数组,我想对其进行web请求。我想用承诺异步调用web请求,并为任何已完成的承诺继续链

您将如何在同步代码中实现它?承诺模拟同步代码

您可以将处理整个单个请求的逻辑放在一个函数中,然后
map

.map(processLine);

function processLine(line) {
    return rp(BASE_URL + line).then(inspect);
}
重要的是要理解,这不是一个工件,而是promise代理模型的核心属性。承诺表示回调之类的单个任务,而不是事件发射器之类的多个任务

你可能想考虑一个可观察的或反应性更强的系统,如果你感兴趣的话,你也可以使用异步迭代器(有效的你的“期望的”语法)。我使用可观测数据,因为它们在这里更容易使用,但两者都可以工作:

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
});
您的“回调地狱”根本不是地狱,而是一种并行运行多个异步链的优雅方式,这是同步所无法比拟的

但是,您的版本中缺少了一个关键的
返回
,这就是为什么我开始喜欢无
{}
的箭头函数的隐式返回,而您忽略了映射

在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));

你可以实现你自己的承诺。可以将其命名为
PromiseGroup
PromiseList
。然后,该类型的对象将表示任意数量的承诺。然后你可以写,例如,
PromiseGroup(行)。然后(行=>rp(BASE_URL+line))。然后(info=>inspect('info:'+info))
你的“回调地狱”版本是正确的。承诺使您不必为多个回调保持嵌套缩进级别,但如果您需要在链的“顶层”执行操作,嵌套承诺很好在看到Benjamin的解决方案后,我不得不说,可观测值看起来是一个很好的解决方案。因此,也许你可以使用一个名为
arrayObservable
的函数或类似的函数来将
转换为一个可观察的。如果(!--counter)或者
如果(--counter==0)
,这不应该是
吗?很好的捕获,应该是
可观察的。从(行)。映射(x=>rp(BASE\u URL+line)).flatMap(x=>x)
而不是那种明确的结构。这似乎是我试图避免的基本问题。如果rp()需要很长时间,但我需要它的结果,然后发出另一个阻塞调用,然后我需要它的结果发出另一个阻塞调用,依此类推,那么我必须等待a全部完成后才能调用b,然后等待b全部完成后才能调用c,等等。。我需要能够在a的某个项目完成时调用b(a)。
rp
是异步的,对吗?那么就没有阻塞了。假设有5行,那么
rp()
将被一个接一个地调用5次,希望每个调用立即返回,然后
inspect
调用将立即执行,直到您有5个承诺。从现在开始,等待所有5件事情完成的唯一事情就是
allInspectResults
。5个
inspect
调用中的每一个都只取决于相应
rp
调用的承诺,它们被调用的顺序取决于哪个
rp
调用首先完成。
rp
调用的异步部分并行运行。