neo-async each

2021-06-01  本文已影响0人  AizawaSayo

GitHub地址

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 参数。

上一篇下一篇

猜你喜欢

热点阅读