如果忘了什么是Thunk函数就来看这篇文章

832 阅读2分钟

前言

经常看到Thunk函数相关的字眼,但是对于Thunk又非常的陌生。最后还是下定决心去好好了解下。 Thunk函数在Javascript中,目的就是将多参数函数(入参中包含了callback函数)变成单参数版本的函数。而且单参数只能是callback函数。任何函数, 只要参数有回调函数, 就能写成Thunk函数的形式。 下⾯是⼀个简单的Thunk函数转换器。

Thunk理解例子

说了那么多,来个简单例子加深自己的理解

// 一个包含了callback函数为入参的多个入参函数
function testcallback(a, cb) {
  console.log(a);
  cb('callback')
}
// 一个callback函数
function cb(str) {
  console.log(str)
}
// Thunk 包装函数,fn是要被改造的函数
var Thunk = function (fn) {
// 返回一个函数,testThunk('aaaa')
  return function (...arg) {
  // 入参只有一个callback函数
    return function (callback) {
      fn.call(this, ...arg, callback);
    }
  }
}
// 转换为testThunk
let testThunk = Thunk(testcallback);
// 调用
testThunk('aaaa')(cb);

Thunk有什么用

其实Thunk最大的作用就是⽤于Generator函数的⾃动流程管理。

一般要让generator函数自动执行所有步骤可以这样

function* gen() {
  yield 1;
  yield 2;
  yield 3;
  return 4;
} 
var g = gen();
var res = g.next();
while (!res.done) {
  console.log(res.value);
  res = g.next();
}

但是, 这不适合异步操作。 如果必须保证前⼀步执⾏完, 才能执⾏后⼀步,上⾯的⾃动执⾏就不可⾏(对于这句话的理解,我其实没有很清楚,是说上面的这种方式不管上一个next是否是执行完,都会执行下一个next)。 这时, Thunk函数就能派上⽤处。(然鹅 我也没看出用Thunk和自动执行器 有什么区别?)

// ...承接最上面的代码

// Thunk函数真正的威⼒, 在于可以⾃动执⾏Generator函数
// generator 函数自动执行器
function run(fn) {
  var gen = fn();
  function next() {
    var result = gen.next();
    console.log('111', result);
    if (result.done) return;
    result.value(next);
  }
  next();
}

// 有了这个执⾏器, 执⾏Generator函数⽅便多了。 不管内部有多少个异步操
// 作, 直接把Generator函数传⼊ run 函数即可。 当然, 前提是每⼀个异步操
// 作, 都要是Thunk函数, 也就是说, 跟在 yield 命令后⾯的必须是Thunk函
// 数。因为需要传入回调函数
function* g() {
  yield testThunk('a');
  yield testThunk('aa');
  return testThunk('aaa');
}

run(g);

Thunk函数并不是Generator函数⾃动执⾏的唯⼀⽅案。 因为⾃动执⾏的关键 是, 必须有⼀种机制, ⾃动控制Generator函数的流程, 接收和交还程序的执 ⾏权。 回调函数可以做到这⼀点, Promise 对象也可以做到这⼀点。

如果想了解下Promise就可以看下 CO 模块,该库实现了不用写上面的自动执行器就可以直接自动执行generator函数。

CO 库