Skip to content
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

async.each callback could be called more than once when array is modified #557

Closed
mingqi opened this issue Jun 17, 2014 · 7 comments
Closed
Labels

Comments

@mingqi
Copy link

mingqi commented Jun 17, 2014

var async = require('async')

inputs = [1,2]
async.each(inputs,
    function (item, callback) {
        setTimeout(function(){callback()}, 1000)
    },
    function(err){
        console.log("async.each done")  
    })

inputs.splice(1,1)

/* output is:
async.each done
async.each done
*/

the problem is async use completed >= arr.length to check if call callback. however arr.length is less than async.each was called.

@aearly
Copy link
Collaborator

aearly commented Jun 17, 2014

Modifying an array while iterating over it is not recommended --- don't do that.

If you want to submit a patch to fix this, that would be great. Otherwise, if you do need to modify the array, just clone it before you pass it to an async method.

@lysdexia
Copy link

I'm new to node/async and made what is probably a very newbie mistake while using waterfall in the same way as the example above:

http://stackoverflow.com/questions/24289629/node-js-async-waterfall-more-than-one-callback-per-function

The weirdness to me is: it works for a while. :-D What is going on in the background that seemingly allows the multiple callback() calls to work?

@amv
Copy link

amv commented Jun 18, 2014

@lysdexia this issue does not deal with multiple callback calls within one iterator. The "series" function referenced here should already defend properly against multiple callbacks (but your code might otherwise do something wonky). This issue is only related to the iterated array being altered in place while the iterator is still working. If you alter the array to contain as many items as it had before, the "series" function works by accident.

The "each" function on the other hand does NOT defend against multiple callback calls. I've just made one issue for that with #559 which now references to an older pull request discussing the same thing.

As a reference - internally async has two "basic" iterators. "each" - which runs functions in parallel, and "series" - which runs functions one after another. Most of the other functions are implemented by using one of these or combining them. Both of these functions might behave in seemingly mysterious ways if A) the array given is altered in place while the iteration is still ongoing and B) if the callbacks of the iterator function are called more than one time (or less than one time). This means also the other functions that use these show the mysterious behaviour.

I have gotten the feeling that B is not seen as such a big deal as you are obviously using the system in the wrong way if you do not call the iterator callback functions once and only once.

I however think that A (which this issue is about and what my pull request addresses) is actually very hard for the programmer to infer as a requirement when using async - and thus defending against it would be an important change.

@aearly aearly added the bug label May 19, 2015
@aearly aearly changed the title async.each callback could be call more than once async.each callback could be called more than once when array is modified Jun 1, 2015
aearly pushed a commit that referenced this issue Jun 1, 2015
@aearly
Copy link
Collaborator

aearly commented Jun 1, 2015

This was fixed as a side effect of other changes.

@ORESoftware
Copy link
Contributor

Did async end up disallowing array modifications after the fact? I have a use case where it would be nice to modify the original array after the fact, so as to iterate on more elements than initially.

@aearly
Copy link
Collaborator

aearly commented Jun 25, 2017

Modifying the array causes undefined behavior. If you need to modify the array, use async.queue.

@ORESoftware
Copy link
Contributor

ok cool thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants