What version of async are you using?
3.1.0
Which environment did the issue occur in (Node version/browser version)
node 12.9.1, npm 6.10.2, browser N/A
What did you do? Please include a minimal reproducable case illustrating issue.
Issue has a thread in stackoverflow
https://stackoverflow.com/questions/57622495/async-maplimit-with-promise/57659221#57659221
Basically, I have this code:
async = require('async');
let numPromise = async.mapLimit(['1','2','3','4','5'], 3, function(num, callback){
setTimeout(function(){
num = num * 2,
console.log(num);
callback(null, num);
},
2000);
})
numPromise
.then((result) => console.log("success:" + result))
.catch(() => console.log("no success"));
What did you expect to happen?
Execute without errors, 'numPromise' should contain a Promise. console should log '2,4,6,8,10' and 'success:2,4,6,8,10'
What was the actual result?
It throws an error: TypeError: Cannot read property 'then' of undefined
Note: When I use the 'promise-async' module instead of 'async' then this code works well. Documentation says that async.mapLimit (and others) return a Promise when no callback is supplied, but I get undefined. Couldn't find any working sample yet (please also see my suggestion on the 'need samples' issue).
const async = require('async');
const delay = require('util').promisify(setTimeout);
const numPromise = async.mapLimit(['1','2','3','4','5'], 3, async num => delay(200).then(() => num*2))
// or const numPromise = async.mapLimit(['1','2','3','4','5'], 3, async num => {
// await delay(200);
// return num*2;
// })
numPromise.then(console.log)
Thx a lot, reasonable example. Unfortunately, gives me "SyntaxError: await is only valid in async function" (for 'await async.mapLimit')
Anything else I have to consider?
The error message says it all, await is only valid in an async function, until top-level-await proposal is implemented
Yip, was looking for a fully working example, as this is really the part I struggled with. Never mind though, got it up and running finally:
const myAsyncFunction = async function(){
//const numPromise = await async.mapLimit(['1','2','3','4','5'], 3, async num => delay(200).then(() => num*2))
const numPromise = await async.mapLimit(['1','2','3','4','5'], 3, async num => {
await delay(2000);
console.log(num*2);
return num*2;
})
//numPromise.then(console.log)
return numPromise;
}
myAsyncFunction()
.then((result) => console.log(result));
I'm not really sure yet what is different to earlier tries, but will validate and add some more conclusion on this.
In any case, my point is that this is all not fully intuitive, I believe, so examples like this can help!
And... I still don't fully understand why we need to wrap all the async/awaits around it, when async.mapLimit should just return a plain Promise by itself...
oops I forgot an await in my previous code, edited
Alright, now I fully confirm :-) So probably the main issue was that the iteratee function wasn't fully asynchronous?
Anyway, this works like a charm it seems and is probably a great example as well! Thx for staying on this with me!!
See https://github.com/caolan/async/issues/1673 for why
async.mapLimit(['1','2','3','4','5'], 3, async num => delay(200).then(() => num*2)) // works
async.mapLimit(['1','2','3','4','5'], 3, num => delay(200).then(() => num*2)) // doesn't work
Promise.all(['1','2','3','4','5'].map(num => delay(200).then(() => num*2))) // works (plain promises)
I see, you're completely with me, i.e. had the same issues.
I guess my main point really is the following - documentation just states "Returns: a Promise if no callback is passed" - so, when I have the callback variant, and then simply leave that out, how would I come to think that I need to add the 'async' keyword when it worked without that in the callback version. Plus, using the 'promise-async' module it works exactly like I expected.
In addition, I haven't yet grasped why the 'Promise.all' example above works... this is really confusing to me.
The iteratee function being async
or using a callback shouldn't affect returning a promise if the final callback is omitted. This is a bug.
I'll bet you this is related to #1685
I'll bet you this is related to #1685
I definitely remember having had that issue before in some version of my code samples as well. I assumed obviously it was caused by some wrong coding. So, interesting to see that it appears in a different flavour as well.
I looked into this more.
mapLimit
is working as intended. I would wager any issues people see here are due to the limitations of detecting promise-returning functions, or compilers (e.g. babel, typescript) not preserving async
functions.
I looked into this more.
mapLimit
is working as intended. I would wager any issues people see here are due to the limitations of detecting promise-returning functions, or compilers (e.g. babel, typescript) not preservingasync
functions.
What's the best way of handling such scenarios where async
is not preserved on compilations?
Wrap the async
function in asyncify
. http://caolan.github.io/async/v3/global.html#AsyncFunction
Most helpful comment