priorityQueue
where it didn't wait for the result. (#1725)unshiftAsync
was included in priorityQueue
. (#1790)queueMicrotask
if available to the environment (#1761)priorityQueue
(#1727)func.name
name
property on wrapped functions.q.pushAsync
and q.unshiftAsync
, analagous to q.push
and q.unshift
, except they always do not accept a callback, and reject if processing the task errors. (#1659)q.push
and q.unshift
when a callback is not passed now resolve even if an error ocurred. (#1659)autoInject
with complicated function bodies (#1663)queue
and cargo
would be completely flattened. (#1645)The async
/await
release!
There are a lot of new features and subtle breaking changes in this major version, but the biggest feature is that most Async methods return a Promise if you omit the callback, meaning you can await
them from within an async
function.
const results = await async.mapLimit(urls, 5, async url => {
const resp = await fetch(url)
return resp.body
})
await
-able! (#1572)queue
, priorityQueue
, cargo
and cargoQueue
, the "event"-style methods, like q.drain
and q.saturated
are now methods that register a callback, rather than properties you assign a callback to. They are now of the form q.drain(callback)
. If you do not pass a callback a Promise will be returned for the next occurrence of the event, making them await
-able, e.g. await q.drain()
. (#1586, #1641)callback(false)
will cancel an async method, preventing further iteration and callback calls. This is useful for preventing memory leaks when you break out of an async flow by calling an outer callback. (#1064, #1542)during
and doDuring
have been removed, and instead whilst
, doWhilst
, until
and doUntil
now have asynchronous test
functions. (#850, #1557)limits
of less than 1 now cause an error to be thrown in queues and collection methods. (#1249, #1552)memoize
no longer memoizes errors (#1465, #1466)applyEach
/applyEachSeries
have a simpler interface, to make them more easily type-able. It always returns a function that takes in a single callback argument. If that callback is omitted, a promise is returned, making it awaitable. (#1228, #1640)cargoQueue
, a queue with both concurrency
and payload
size parameters. (#1567)queue
now have a Symbol.iterator
method, meaning they can be iterated over to inspect the current list of items in the queue. (#1459, #1556)async.mjs
is included in the async
package. This is described in the package.json
"module"
field, meaning it should be automatically used by Webpack and other compatible bundlers.npm audit
warnings. (#1532, #1533)async-es
more optimized for webpack users (#1517)require('async/find')
or use async.anyLimit
. (#1483)queue
performance. (#1448, #1454)concatLimit
, the Limit
equivalent of concat
(#1426, #1430)concat
improvements: it now preserves order, handles falsy values and the iteratee
callback takes a variable number of arguments (#1437, #1436)queue
where there was a size discrepancy between workersList().length
and running()
(#1428, #1429)tryEach
, for running async functions in parallel, where you only expect one to succeed. (#1365, #687)parallel
and waterfall
(#1395)queue.remove()
, for removing items in a queue
(#1397, #1391)eval
, preventing Async from running in pages with Content Security Policy (#1404, #1403)asyncify
ed function's callback being caught by the underlying Promise (#1408)queue.empty()
(#1367)async
functions. Wherever you can pass a Node-style/CPS function that uses a callback, you can also pass an async
function. Previously, you had to wrap async
functions with asyncify
. The caveat is that it will only work if async
functions are supported natively in your environment, transpiled implementations can't be detected. (#1386, #1390)groupBy
, and the Series
/Limit
equivalents, analogous to _.groupBy
(#1364)transform
bug when callback
was not passed (#1381)reflect
to parallel
docs (#1385)auto
bug when function names collided with Array.prototype (#1358)some
, every
and find
where processing would continue after the result was determined.some
, every
and find
filter
in array case.detect
, some
, every
on large inputs (#1293).retry
and retryable
now support an optional errorFilter
function that determines if the task
should retry on the error (#1256, #1261)race
, cargo
, queue
, and priorityQueue
(#1253)each
, map
, filter
, etc (#1245, #1246, #1247).Lots of changes here!
First and foremost, we have a slick new site for docs. Special thanks to @hargasinski for his work converting our old docs to jsdoc
format and implementing the new website. Also huge ups to @ivanseidel for designing our new logo. It was a long process for both of these tasks, but I think these changes turned out extraordinary well.
The biggest feature is modularization. You can now require("async/series")
to only require the series
function. Every Async library function is available this way. You still can require("async")
to require the entire library, like you could do before.
We also provide Async as a collection of ES2015 modules. You can now import {each} from 'async-es'
or import waterfall from 'async-es/waterfall'
. If you are using only a few Async functions, and are using a ES bundler such as Rollup, this can significantly lower your build size.
Major thanks to @Kikobeats, @aearly and @megawac for doing the majority of the modularization work, as well as @jdalton and @Rich-Harris for advisory work on the general modularization strategy.
Another one of the general themes of the 2.0 release is standardization of what an "async" function is. We are now more strictly following the node-style continuation passing style. That is, an async function is a function that:
There were several cases where Async accepted some functions that did not strictly have these properties, most notably auto
, every
, some
, filter
, reject
and detect
.
Another theme is performance. We have eliminated internal deferrals in all cases where they make sense. For example, in waterfall
and auto
, there was a setImmediate
between each task -- these deferrals have been removed. A setImmediate
call can add up to 1ms of delay. This might not seem like a lot, but it can add up if you are using many Async functions in the course of processing a HTTP request, for example. Nearly all asynchronous functions that do I/O already have some sort of deferral built in, so the extra deferral is unnecessary. The trade-off of this change is removing our built-in stack-overflow defense. Many synchronous callback calls in series can quickly overflow the JS call stack. If you do have a function that is sometimes synchronous (calling its callback on the same tick), and are running into stack overflows, wrap it with async.ensureAsync()
.
Another big performance win has been re-implementing queue
, cargo
, and priorityQueue
with doubly linked lists instead of arrays. This has lead to queues being an order of magnitude faster on large sets of tasks.
require()
d from the main package. (require('async/auto')
) (#984, #996)async-es
package. (import {forEachSeries} from 'async-es'
) (#984, #996)race
, analogous to Promise.race()
. It will run an array of async tasks in parallel and will call its callback with the result of the first task to respond. (#568, #1038)each
, map
, parallel
, etc.. (#579, #839, #1074)mapValues
, for mapping over the properties of an object and returning an object with the same keys. (#1157, #1177)timeout
, a wrapper for an async function that will make the task time-out after the specified time. (#1007, #1027)reflect
and reflectAll
, analagous to Promise.reflect()
, a wrapper for async tasks that always succeeds, by gathering results and errors into an object. (#942, #1012, #1095)constant
supports dynamic arguments -- it will now always use its last argument as the callback. (#1016, #1052)setImmediate
and nextTick
now support arguments to partially apply to the deferred function, like the node-native versions do. (#940, #1053)auto
now supports resolving cyclic dependencies using Kahn's algorithm (#1140).autoInject
, a relative of auto
that automatically spreads a task's dependencies as arguments to the task function. (#608, #1055, #1099, #1100)auto
tasks. (#635, #637)retryable
, a relative of retry
that wraps an async function, making it retry when called. (#1058)retry
now supports specifying a function that determines the next time interval, useful for exponential backoff, logging and other retry strategies. (#1161)retry
will now pass all of the arguments the task function was resolved with to the callback (#1231).q.unsaturated
-- callback called when a queue
's number of running workers falls below a threshold. (#868, #1030, #1033, #1034)q.error
-- a callback called whenever a queue
task calls its callback with an error. (#1170)applyEach
and applyEachSeries
now pass results to the final callback. (#1088)waterfall
. If you were relying on this behavior, you should more accurately represent your control flow as an event emitter or stream. (#814, #815, #1048, #1050)auto
task functions now always take the callback as the last argument. If a task has dependencies, the results
object will be passed as the first argument. To migrate old task functions, wrap them with _.flip
(#1036, #1042)setImmediate
calls have been refactored away. This may make existing flows vulnerable to stack overflows if you use many synchronous functions in series. Use ensureAsync
to work around this. (#696, #704, #1049, #1050)map
used to return an object when iterating over an object. map
now always returns an array, like in other libraries. The previous object behavior has been split out into mapValues
. (#1157, #1177)filter
, reject
, some
, every
, detect
and their families like {METHOD}Series
and {METHOD}Limit
now expect an error as the first callback argument, rather than just a simple boolean. Pass null
as the first argument, or use fs.access
instead of fs.exists
. (#118, #774, #1028, #1041){METHOD}
and {METHOD}Series
are now implemented in terms of {METHOD}Limit
. This is a major internal simplification, and is not expected to cause many problems, but it does subtly affect how functions execute internally. (#778, #847)retry
's callback is now optional. Previously, omitting the callback would partially apply the function, meaning it could be passed directly as a task to series
or auto
. The partially applied "control-flow" behavior has been separated out into retryable
. (#1054, #1058)whilst
, until
, and during
used to be passed non-error args from the iteratee function's callback, but this led to weirdness where the first call of the test function would be passed no args. We have made it so the test function is never passed extra arguments, and only the doWhilst
, doUntil
, and doDuring
functions pass iteratee callback arguments to the test function (#1217, #1224)q.tasks
array has been renamed q._tasks
and is now implemented as a doubly linked list (DLL). Any code that used to interact with this array will need to be updated to either use the provided helpers or support DLLs (#1205).q.saturated()
callback in a queue
has been modified to better reflect when tasks pushed to the queue will start queueing. (#724, #1078)iterator
method in favour of ES2015 iterator protocol which natively supports arrays (#1237)auto
& autoInject
(#1147).asyncify
with Promises
could resolve twice (#1197).someSeries
and everySeries
for symmetry, as well as a complete set of any
/anyLimit
/anySeries
and all
//allLmit
/allSeries
aliases.find
as an alias for detect. (as well as
findLimitand
findSeries`).Thank you @aearly and @megawac for taking the lead on version 2 of async.
"constructor"
as an argument in memoize
(#998)auto
dependency checking fails (#994)pause
in queue
with concurrency enabled (#946)while
and until
now pass the final result to callback (#963)auto
will properly handle concurrency when there is no callback (#966)auto
will no. properly stop execution when an error occurs (#988, #993)transform
, analogous to _.transform
(#892)map
now returns an object when an object is passed in, rather than array with non-numeric keys. map
will begin always returning an array with numeric indexes in the next major release. (#873)auto
now accepts an optional concurrency
argument to limit the number o. running tasks (#637)queue#workersList()
, to retrieve the lis. of currently running tasks. (#891)detectLimit
method (#866)asyncify
now supports promises (#840)Limit
versions of filter
and reject
(#836)Limit
versions of detect
, some
and every
(#828, #829)some
, every
and detect
now short circuit early (#828, #829)whilst
now called with arguments from iterator (#823)during
now gets called with arguments from iterator (#824)New Features:
constant
asyncify
/wrapSync
for making sync functions work with callbacks. (#671, #806)during
and doDuring
, which are like whilst
with an async truth test. (#800)retry
now accepts an interval
parameter to specify a delay between retries. (#793)async
should work better in Web Workers due to better root
detection (#804)whilst
, doWhilst
, until
, and doUntil
(#642)Bug Fixes:
cargo
now exposes the payload
size, and cargo.payload
can be changed on the fly after the cargo
is created. (#740, #744, #783)Bug Fix:
eachSeries
with a 1-element array. Before 1.1.0, eachSeries
's callback was called on the same tick, which this patch restores. In 2.0.0, it will be called on the next tick. (#782)New Features:
timesLimit
(#743)concurrency
can be changed after initialization in queue
by setting q.concurrency
. The new concurrency will be reflected the next time a task is processed. (#747, #772)Bug Fixes:
each
and family with empty arrays that have additional properties. (#775, #777)Bug Fix:
eachSeries
with a 1-element array. Before 1.1.0, eachSeries
's callback was called on the same tick, which this patch restores. In 2.0.0, it will be called on the next tick. (#782)New Features:
cargo
now supports all of the same methods and event callbacks as queue
.ensureAsync
- A wrapper that ensures an async function calls its callback on a later tick. (#769)map
, eachOf
, and waterfall
families of functionsnull
or undefined
array to map
, each
, parallel
and families will be treated as an empty array (#667).compose
and seq
. (#618)nyc
and coveralls
(#768)Bug Fixes:
forever
will no longer stack overflow with a synchronous iterator (#622)eachLimit
and other limit functions will stop iterating once an error occurs (#754)null
in callbacks when there is no error (#439)drain()
after pushing an empty data set to a queue (#668)each
and family will properly handle an empty array (#578)eachSeries
and family will finish if the underlying array is modified during execution (#557)queue
will throw if a non-function is passed to q.push()
(#593)No known breaking changes, we are simply complying with semver from here on out.
Changes:
forEachOf
for iterating over Objects (or to iterate Arrays with indexes available) (#168 #704 #321)auto
(#663)0
(#714)queue.resume()
(#758)setImmediate
(#609 #611)_each
, _map
and _keys
functions.