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


你可能感兴趣的:(Generator 使用Thunk 或co模块自动执行异步任务)