我希望使用 bluebird 循环执行一些任务,只是将超时用作实验机制。 [不打算使用异步或任何其他库]
var Promise = require('bluebird');
var fileA = {
1: 'one',
2: 'two',
3: 'three',
4: 'four',
5: 'five'
};
function calculate(key) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(fileA[key]);
}, 500);
});
}
Promise.map(Object.keys(fileA), function (key) {
calculate(key).then(function (res) {
console.log(res);
});
}).then(function () {
console.log('finish');
});
结果是
finish,
one,
two,
three,
four,
five,
我需要循环在每次超时完成时只迭代一次,然后在完成时触发最后一个 thenable。
最佳答案
在传递给Promise.map的函数对象中,需要返回一个Promise对象,这样所有的Promises都会被resolve,并且可以将resolved值的数组传递给下一个 then 函数。在您的情况下,由于您没有明确返回任何内容,因此 undefined 将默认返回,而不是 promise 。因此,带有 finish 的 thenable 函数被执行,因为 Promises.map 的 Promise 被 undefined 解析。你可以这样确认
...
}).then(function (result) {
console.log(result);
console.log('finish');
});
会打印
[ undefined, undefined, undefined, undefined, undefined ]
finish
one
two
three
four
five
所以,你的代码应该有一个像这样的return语句
Promise.map(Object.keys(fileA), function (key) {
return calculate(key).then(function (res) {
console.log(res);
});
}).then(function () {
console.log('finish');
});
现在,您将看到代码按顺序打印事物,因为我们返回 Promise 对象,并且在所有 Promise 都已解决后调用带有 finish 的 thenable 函数。但它们都没有按顺序解决。如果发生这种情况,每个数字都会在指定的时间过去后打印出来。这就把我们带到了第二部分。
Promise.map 将执行作为参数传递的函数,一旦数组中的 Promises 被解析。引用文档,
The mapper function for a given item is called as soon as possible, that is, when the promise for that item's index in the input array is fulfilled.
因此,数组中的所有值都被转换为 Promises,Promises 由相应的值解析,并且将立即为每个值调用该函数。因此,他们都同时等待 500 毫秒并立即解决。这不会按顺序发生。
由于您希望它们顺序执行,因此需要使用 Promise.each 。引用文档,
Iteration happens serially. .... If the iterator function returns a promise or a thenable, the result for the promise is awaited for before continuing with next iteration.
由于 Promise 是连续创建的,并且在继续之前等待解决,因此结果的顺序是有保证的。所以你的代码应该变成
Promise.each(Object.keys(fileA), function (key) {
return calculate(key).then(function (res) {
console.log(res);
});
}).then(function () {
console.log('finish');
});
补充说明:
如果顺序无关紧要,按照 Benjamin Gruenbaum 的建议,您可以使用 Promise.map 本身,使用 concurrency limit ,像这样
Promise.map(Object.keys(fileA), function (key) {
return calculate(key).then(function (res) {
console.log(res);
});
}, { concurrency: 1 }).then(function () {
console.log('finish');
});
concurrency 选项基本上限制了在创建更多 promise 之前可以创建和解析的 promise 数量。因此,在这种情况下,由于限制为 1,它会创建第一个 Promise,当达到限制时,它会等到创建的 Promise 解决,然后再继续下一个 Promise。
如果使用 calculate 的全部目的是引入延迟,那么我会推荐 Promise.delay ,可以这样使用
Promise.each(Object.keys(fileA), function (key) {
return Promise.delay(500).then(function () {
console.log(fileA[key]);
});
}).then(function () {
console.log('finish');
});
delay 可以透明地将 Promise 的 resolved 值链接到下一个 thenable 函数,因此代码可以缩短为
Promise.each(Object.keys(fileA), function (key) {
return Promise.resolve(fileA[key]).delay(500).then(console.log);
}).then(function () {
console.log('finish');
});
因为 Promise.delay 接受一个动态值,你可以简单地写成相同的
Promise.each(Object.keys(fileA), function (key) {
return Promise.delay(fileA[key], 500).then(console.log);
}).then(function () {
console.log('finish');
});
如果 Promise 链自己到这里结束,最好使用 .done() 方法来标记它,像这样
...
}).done(function () {
console.log('finish');
});
一般注意事项:如果您不打算在 thenable 函数中进行任何处理,而只是使用它来跟踪进度或跟踪流程,那么您最好将它们更改为 Promise.tap .所以,你的代码会变成
Promise.each(Object.keys(fileA), function (key) {
return Promise.delay(fileA[key], 500).tap(console.log);
}).then(function () {
// Do processing
console.log('finish');
});
关于javascript - 循环遍历任务 waterfall - promises bluebird,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29590078/
我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时
我脑子里浮现出一些关于一种新编程语言的想法,所以我想我会尝试实现它。一位friend建议我尝试使用Treetop(Rubygem)来创建一个解析器。Treetop的文档很少,我以前从未做过这种事情。我的解析器表现得好像有一个无限循环,但没有堆栈跟踪;事实证明很难追踪到。有人可以指出入门级解析/AST指南的方向吗?我真的需要一些列出规则、常见用法等的东西来使用像Treetop这样的工具。我的语法分析器在GitHub上,以防有人希望帮助我改进它。class{initialize=lambda(name){receiver.name=name}greet=lambda{IO.puts("He
我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代
如何使用RSpec::Core::RakeTask初始化RSpecRake任务?require'rspec/core/rake_task'RSpec::Core::RakeTask.newdo|t|#whatdoIputinhere?endInitialize函数记录在http://rubydoc.info/github/rspec/rspec-core/RSpec/Core/RakeTask#initialize-instance_method没有很好的记录;它只是说:-(RakeTask)initialize(*args,&task_block)AnewinstanceofRake
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg
所以这可能有点令人困惑,但请耐心等待。简而言之,我想遍历具有特定键值的所有属性,然后如果值不为空,则将它们插入到模板中。这是我的代码:属性:#===DefaultfileConfigurations#default['elasticsearch']['default']['ES_USER']=''default['elasticsearch']['default']['ES_GROUP']=''default['elasticsearch']['default']['ES_HEAP_SIZE']=''default['elasticsearch']['default']['MAX_OP
我写了一个非常简单的rake任务来尝试找到这个问题的根源。namespace:foodotaskbar::environmentdoputs'RUNNING'endend当在控制台中执行rakefoo:bar时,输出为:RUNNINGRUNNING当我执行任何rake任务时会发生这种情况。有没有人遇到过这样的事情?编辑上面的rake任务就是写在那个.rake文件中的所有内容。这是当前正在使用的Rakefile。requireFile.expand_path('../config/application',__FILE__)OurApp::Application.load_tasks这里
我是Ruby的新手,有些闭包逻辑让我感到困惑。考虑这段代码:array=[]foriin(1..5)array[5,5,5,5,5]这对我来说很有意义,因为i被绑定(bind)在循环之外,所以每次循环都会捕获相同的变量。使用每个block可以解决这个问题对我来说也很有意义:array=[](1..5).each{|i|array[1,2,3,4,5]...因为现在每次通过时都单独声明i。但现在我迷路了:为什么我不能通过引入一个中间变量来修复它?array=[]foriin1..5j=iarray[5,5,5,5,5]因为j每次循环都是新的,我认为每次循环都会捕获不同的变量。例如,这绝对
我们有一个字符串:“”这个正则表达式://i如何从当前字符串中获取所有匹配项? 最佳答案 "".scan(//)参见scan在ruby-docs上 关于ruby-如何遍历Ruby中所有正则表达式匹配的字符串?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/6857852/