让人头痛的Generator 函数的异步应用真的有用吗?( 七 )


处理并发的异步操作co 支持并发的异步操作 , 即允许某些操作同时进行 , 等到它们全部完成 , 才进行下一步 。
这时 , 要把并发的操作都放在数组或对象里面 , 跟在yield语句后面 。
// 数组的写法co(function* () {var res = yield [Promise.resolve(1),Promise.resolve(2)];console.log(res);}).catch(onerror);// 对象的写法co(function* () {var res = yield {1: Promise.resolve(1),2: Promise.resolve(2),};console.log(res);}).catch(onerror);下面是另一个例子 。
co(function* () {var values = [n1, n2, n3];yield values.map(somethingAsync);});function* somethingAsync(x) {// do something asyncreturn y}上面的代码允许并发三个somethingAsync异步操作 , 等到它们全部完成 , 才会进行下一步 。
实例:处理 StreamNode 提供 Stream 模式读写数据 , 特点是一次只处理数据的一部分 , 数据分成一块块依次处理 , 就好像“数据流”一样 。 这对于处理大规模数据非常有利 。 Stream 模式使用 EventEmitter API , 会释放三个事件 。

  • data事件:下一块数据块已经准备好了 。
  • end事件:整个“数据流”处理完了 。
  • error事件:发生错误 。
使用Promise.race()函数 , 可以判断这三个事件之中哪一个最先发生 , 只有当data事件最先发生时 , 才进入下一个数据块的处理 。 从而 , 我们可以通过一个while循环 , 完成所有数据的读取 。
const co = require('co');const fs = require('fs');const stream = fs.createReadStream('./les_miserables.txt');let valjeanCount = 0;co(function*() {while(true) {const res = yield Promise.race([new Promise(resolve => stream.once('data', resolve)),new Promise(resolve => stream.once('end', resolve)),new Promise((resolve, reject) => stream.once('error', reject))]);if (!res) {break;}stream.removeAllListeners('data');stream.removeAllListeners('end');stream.removeAllListeners('error');valjeanCount += (res.toString().match(/valjean/ig) || []).length;}console.log('count:', valjeanCount); // count: 1120});
让人头痛的Generator 函数的异步应用真的有用吗?文章插图


推荐阅读