Generator 使用Thunk 或co模块自动执行异步任务

问题:
有以下异步任务需要进行处理:
[a,b]: a任务执行完毕后再处理b任务;
[a,[b,c],d]: a任务处理完成后,等待b,c任务处理完成,再执行d任务
[a,[b,[c,d]],e]: 任务可相互嵌套,层级不限

概念

Generator 就是一个异步操作的容器。它的自动执行需要一种机制,当异步操作有了结果,能够自动交回执行权。两种方法可以做到这一点。

(1)回调函数。将异步操作包装成 Thunk 函数,在回调函数里面交回执行权。(使用Thunk 函数的自动流程管理)
(2)Promise 对象。将异步操作包装成 Promise 对象,用then方法交回执行权。(使用co模块)


JavaScript 语言的 Thunk 函数

JavaScript 语言是传值调用,它的 Thunk 函数含义有所不同。在 JavaScript 语言中,Thunk 函数替换的不是表达式,而是多参数函数,将其替换成一个只接受回调函数作为参数的单参数函数。

ES6 有了 Generator 函数,Thunk 函数现在可以用于 Generator 函数的自动流程管理。在回调函数里,将执行权交还给 Generator 函数。

使用Thunk 函数的自动流程管理:

使用Thunk 函数的自动流程管理:
//任务假定需要异步读取文件,此处创建6个txt文件,内容从1标记到6

const path = require('path')
const fs = require('fs');
var fsPath = [];
for(let i = 1; i< 7; i++) {
  fsPath[i-1] =  path.join(__dirname, './'+i+'.txt')
}

 //Thunk 函数转换器,将文件路径,字符编码方式,回调函数作为参数传给fs.readFile

var Thunk = function(fn){
  return function (){
    var args = Array.prototype.slice.call(arguments);
    args.push('utf-8');

    return function (callback){
      args.push(callback);
      return fn.apply(this, args);
    }
  };
};

/* Generator 函数的自动执行器。内部的next函数就是 Thunk 的回调函数。next函数先将指针移到 Generator 函数的下一步(gen.next方法),
然后判断 Generator 函数是否结束(result.done属性),如果没结束,就将next函数再传入 Thunk 函数(result.value属性),否则就直接退出。*/
function run(fn) {
  var gen = fn;

  function next(err, data) {
    var result = gen.next(data);
    if (result.done) return;
    result.value(next);
  }

  next();
}

//使用thunk转换器,生成fs.readFile的 Thunk 函数。
var readFileThunk = Thunk(fs.readFile);

/*在Generator 函数中遍历任务数组,当任务为数组(步骤需要等待多个任务完成),递归调用Generator,然后再对单个任务进行处理;否则
通过thunk 函数转换器直接读取文件内容*/
function* g(files) {
  var current;
  for (var i = 0; i < files.length; i++) {
    current = files[i];
    if(!current) {
      console.log(arr[i]);
      break;
    }
    if(current instanceof Array) {
      yield* g(current);
    } else {
      var desk = yield readFileThunk(current);
      console.log(desk)
    }
  }
}

//入口,Generator 函数作为参数传给run自动执行器
run(g([fsPath[0],[fsPath[1],fsPath[0]],[fsPath[5],[fsPath[2],fsPath[3]],fsPath[4]]]))
//1 2 1 6 3 4 5
使用co模块基于 Promise 对象的自动执行 
const co = require('co');
const path = require('path')
const fs = require('fs');
var fsPath = [];
for(let i = 1; i< 7; i++) {
  fsPath[i-1] =  path.join(__dirname, './'+i+'.txt')
}


//把fs模块的readFile方法包装成一个 Promise 对象
var readFile = function (fileName){
  return new Promise(function (resolve, reject){
    fs.readFile(fileName, 'utf-8', function(error, data){
      if (error) return reject(error);
      resolve(data);
    });
  });
};

function* gen(files) {
  var current;
  for(let i = 0; i < files.length; i++){
    current = files[i];
    if(!current) {
      console.log(current);
      break;
    }
    if(current instanceof Array) {
      yield* gen(current)
    } else {
      var res = yield readFile(current)
      console.log(res);
    }
  }
}

co(gen([fsPath[0],[fsPath[1],fsPath[0]],[fsPath[5],[fsPath[2],fsPath[3]],fsPath[4]]])).catch(function(err){
  console.log('err',err)
});
//1 2 1 6 3 4 5


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值