理解通过thunk函数自动执行generator函数

今天又看了一遍阮一峰老师的《Thunk 函数的含义和用法》,这里整理一下自己的理解:

在 JavaScript 语言中,Thunk 函数替换的不是表达式,而是多参数函数,将其替换成单参数的版本,且只接受回调函数作为参数。

// 正常版本的readFile(多参数版本)
fs.readFile(fileName, callback);

// Thunk版本的readFile(单参数版本)
var readFileThunk = Thunk(fileName);
readFileThunk(callback);

var Thunk = function (fileName){
  return function (callback){
    return fs.readFile(fileName, callback); 
  };
};

以读取文件为例。下面的 Generator 函数封装了两个异步操作。

var fs = require('fs');
var thunkify = require('thunkify');
var readFile = thunkify(fs.readFile);

var gen = function* (){
  var r1 = yield readFile('/etc/fstab'); // 2. 读取文件一
  console.log(r1.toString());
  var r2 = yield readFile('/etc/shells');// 5. 读取文件二
  console.log(r2.toString());
};

手动执行方式:

var g = gen();// 0. 初始化

var r1 = g.next();// 1. 执行下一步,返回的r1就是generator指针:{value, done},而这里的value其实就是一个thunk函数,这个thunk函数以回调函数作为参数
r1.value(function(err, data){// 3. 文件一读取完成的回调函数
  if (err) throw err;
  var r2 = g.next(data);// 4. 执行下一步
  r2.value(function(err, data){ // 文件二读取完成的回调函数
    if (err) throw err;
    g.next(data);
  });
});

总的来说,其实就是利用thunk函数,把需要做的操作和对应的回调函数,从fn(operation, callback)改成了fn(operation)(callback)的形式。

为什么要这么做?
是因为generator函数在yield返回后,不会自动往下执行,如果写成:

var gen = function* (){
  var r1 = yield readFile('/etc/fstab', gen.next()); // 这时gen还没有初始化,不是一个generator指针,所以没有next方法,而gen() !== gen(),所以也不能写成gen().next()
  console.log(r1.toString());
};

也没法自动执行,所以将回调函数分离到第二步,然后在回调函数里(这时generator肯定已经初始化完了,不然没法执行到回调函数)执行generator指针的next方法,走到下一步。


总结:执行value方法本质上相当于注册一个回调函数,而generator函数结合thunk函数就是一种更直观的注册回调函数的方式。generator函数负责异步执行(交出执行权),而thunk函数负责注册回调(返回执行权,执行下一步),两者结合从而自动执行generator函数。

如果有任何理解不妥当的地方,欢迎指正交流。

你可能感兴趣的:(异步编程,generator,thunkify,javascript)