-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Promise.map
calls callback synchronously in bluebird v3.x
#1148
Comments
Prototype method also calls the callback synchronously if called on a resolved promise in bluebird v3.x: Promise.resolve( [1, 2, 3] ).map( function(v) {
console.log(v);
} );
console.log('next sync statement'); var p = Promise.resolve( [1, 2, 3] ).tap( function() {} );
setImmediate( function() {
p.map( function(v) {
console.log(v);
} );
console.log('next sync statement');
} ); Both of the above produce output:
|
@benjamingr I see you've labelled this issue as a bug. Does that mean that the synchronous calling of callbacks is not the intended behavior? I'm working on a new shim of bluebird to support CLS https://github.com/overlookmotel/cls-bluebird/tree/refactor and it'd be useful to know how to handle this. |
Yes it is a bug instead of an intended change in 3.x |
@petkaantonov Thanks for your answer. If it's going to be fixed, would this be considered a semver major change? I mean while I do think it can be considered a bug and so only requiring a semver patch release, it's not specified in the docs whether the callback is meant to execute sync or async - so from that point of view it's ambiguous. But, more importantly, it's quite possible fixing this will break peoples' code. |
I've changed my mind on whether this should be a semver major change. I now think this should be considered a bug and could be fixed in v3.x. It seems to me that the fundamental rule of Promises A+ spec is that callbacks chained onto a promise are called async (avoiding Zalgo). Although bluebird docs do not specify whether I think the following two should be considered as equivalent: Promise.resolve( 1 ).then( function( value ) { console.log( value ); } );
Promise.resolve( [ 1 ] ).map( function( value ) { console.log( value ); } ); Therefore, my conclusion is that the fact they behave differently should be considered a violation of the spirit of the Promises A+ spec, and so could be fixed in a v3.x patch release. What do you think @petkaantonov @benjamingr? |
I am leaning towards patch because it's a pretty "obvious" bug and not many people can be relying on the order being essentially random. |
OK brilliant. If you can point me to the vaguely right area of the code, I can try to make a fix. I'd like to contribute fixes rather than just raising issues all the time, but I'm just rather terrified by the complexity of the codebase and fear changing something which would unintentionally break something else. |
It should be enough to create in map.js: MappingPromiseArray.prototype._asyncInit = function() {
this._init$(undefined, RESOLVE_ARRAY);
}; And then replace the async.invoke(this._asyncInit, this, undefined); To get reference to |
I think the place where this could break peoples' code is where they're iterating over an array that contains only literal values (i.e. not promises) and rely on the callback being run sync: var total = 0;
Promise.map( [1, 2, 3], function(num) {
// do something sync
total += num;
// now do something async
return fs.readFileAsync( 'file' + num + '.txt' );
} );
console.log( 'total:', total ); So at present this outputs The above example doesn't rely on randomness, but predictable sync. |
Thanks for the suggestions on how to fix. I'll have a go in next few days. |
`.map` callback called async (closes #1148)
Thanks! |
No, thank you! I'm pleased to be able to actually contribute fixes rather than just raising endless issues. |
v3.0.0-3.4.1
Node v6.2.1, OS X 10.9.5
No
Promise.map()
calling callback sync/asyncThe behavior of
Promise.map()
seems to have changed between bluebird v2.10.2 and v3.0.0.In v2.x, the callback is always called asynchronously; in v3.0.0-3.4.1 the callback is called synchronously for literal values of the array.
With bluebird v2.10.2:
With bluebird v3.x:
Resolved promises in the array are also mapped over synchronously. e.g.
arr = [ 1, Promise.resolve(2), 3 ]
, gives the same result.But any unresolved promises in the array are awaited before calling the callback on that item. This causes some puzzling behavior:
Outputs:
And also:
This behavior is the same with
Promise.filter()
too.Questions
Promise.mapSeries()
doesn't call the callback syncronously for the first round?The text was updated successfully, but these errors were encountered: