Neo-Async 是一个为异步 JavaScript (也有同步) 提供一些方法的库。它被认为是 Async 的替代品,几乎完全覆盖了Async的功能,而且运行速度更快。
Neo-Async 库提供的所有方法,如map、parallel、series、waterfall
...诸如此类,都遵循Node.js约定,拥有一个以 Error 为第一个参数的回调方法。这个回调会作为最后一个参数传给该方法的异步函数参数,并且只能被调用一次。文字阐述有点绕,我们以 neo-async 的 each 为例,用 code 来说明:
我们参考下 async.each() 的文档,neo-async.each 相当于它的升级版,不仅同样能完成集合 (几乎任何类型) 的异步迭代,还可以直接给 iterator (迭代器参数) 传数组的 index 或对象的 key (可选),而 async 要借助 eachOf 才能实现。
语法:each(coll, iteratee, callback)
将 iteratee 函数并行 (不能保证按顺序) 地应用于 coll 中的每一项 (item)。iteratee 除了 item 还可以接收一个回调(即 each 的第三个参数 -- callback 方法) 作为参数。如果 iteratee 传递一个值给这个回调 (通常是错误),则会立即调用这个 each 的 callback。不传递参数 callback 则会在所有 item 被 iteratee 处理完后执行。
参数:
coll
:<Array | Iterable | AsyncIterable | Object>
一个需要迭代的集合
iteratee
:<AsyncFunction> :function(item, [index|key], callback)
一个应用于集合(coll
)每一项(item
)的异步函数,默认接收item, callback
两个参数。若需要在iteratee
中接收 Array 的 index 或 Object 的 key,传给第二个可选参数即可。
在iteratee
内手动调用callback([sth])
即可执行 each 第三个参数方法 (主callback)。
callback
:<Function> :function(err)
当所有 iteratee 处理完成或发生错误时调用的回调。接收一个 (err
) 参数。
在 iteratee 内调用 callback(err)
const async = require('neo-async')
var array = [1, 2, 3]
// 假设这是一个异步方法,用 setTimeout 模拟
var someAsyncFun = (data, cb) =>
setTimeout(() => {
if (data > 2) return cb('err: 数字不能大于2')
const newData = data * 2
cb(null, newData)
}, Math.random() * 1000)
// 应用于每一项的迭代器函数
var iterator = function (item, callback) {
someAsyncFun(item, (err, result) => {
console.log(result) // 拿到异步返回结果
callback(err, result) // 把`err`传递给回调并执行
})
}
async.each(array, iterator, (err, res) => {
console.log('回调执行:', err, res)
})
这时,我们发现当 callback 被调用时传递了参数,each 的第三个参数(即主 callback)就会立即执行,并且拿到的 err 就是我们传递的值。文档中 callback 只接收一个参数,实测传了第二个参数在执行的时候永远是 undefined。
当传递了错误,主 callback 立即执行 第三个参数 callback 执行的时间取决于何时callback带参在 iteratee 内调用 callback()
这次我们写个简化版。
callback 不放在 iteratee 异步方法内最后调用可能会出现不可预期的结果,且本意是等项目的迭代函数全部执行完再调用 (不报错的情况),因此我们应该保证将其写在其他语句之后。neo-async.each 例子中 iteratee 的 callback 参数都用 done 来代替以表明语义。
// 相同部分省略
async.each(
array,
(item, callback) => {
setTimeout(() => {
const newData = item * 2
console.log(newData)
// if (err) return callback(err) // 如果多次回调,的推荐写法
// 举例:if (item === 2) return callback('err: 数字不能等于2')
callback()
}, Math.random() * 1000)
},
err => {
console.log('回调执行:', err)
}
)
callback() 也能实现手动执行回调,执行时机是所有项目被 iteratee 迭代处理完成之后。
image.png注意⚠️:因为回调在 iteratee 内只能被调用一次,如果出于条件判断等因素需要多次 callback() ,则在前面加上 return 比较稳妥,如:
var iterator = function(item, callback) {
someAsyncFun(item, (err, result) => {
if (err) return callback(err)
callback(null, result)
});
};
当然如果是上面的 each 方法传了这个 iterator 函数,callback 只接收一个 err 参数。
网友评论