thunkify源码分析:逐步分析

自己实现一个简单的 thunkify 来了解一下原理
更新于: 2021-12-19 12:57:29

个人的结

  1. Thunk是专业领域大家已知的概念
  2. 这个是类似于  promise 一类的定制标准的东西,符合这套标准,结合一个  run 方法 + generator,就能轻松实现一套处理异步的语法糖出来
  3. 我自己曾经也实现过一套类似的东西:afeiship/next-async-queue 也是定义了一套简单的标准,来实现异步 task 的语法糖

先看一下使用

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

read('package.json', 'utf8')(function (err, str) {});

实现思路

  1. 入参:一个函数,且最后一个参数为回调函数
  2. 2层执行,说明有2层回调
function thunk(fn){

  // 原函数的参数部分
  return function () {
  
    // 原函数的回调部分
    return function (done) {};
  };
}

简单的实现(ryf

var thunk = function(fn){
  return function (){
    // 1. 获取函数参数(除 callback 部分)
    var args = Array.prototype.slice.call(arguments);
    
    return function (callback){
      // 2. 将用户的 callback 也加进入
      args.push(callback);
      
      // 3. 真实的执行用户 function: fn
      return fn.apply(this, args);
    }
  };
};

有什么用

在没有 for..of 之前,可以自己写一个很简单的 run 方法,来实现 generator 函数 的自执行,从而实现异步流程类似于同步的写法

import $ from 'jquery';
import thunkify from 'thunkify';

function ajax(url, cb) {
  $.ajax({
    url: url,
    success: cb,
  });
}

const getData = thunk(ajax);

// 创建 Generator
const gen = function* () {
  const data1 = yield getData('https://jsonplaceholder.typicode.com/todos/1');
  console.log(data1); // 获取数据后自定义操作
  const data2 = yield getData('https://jsonplaceholder.typicode.com/todos/2');
  console.log(data2);
  const data3 = yield getData('https://jsonplaceholder.typicode.com/todos/3');
  console.log(data3);
};

// 自动执行 Generator
function run(fn) {
  var g = fn();
  function next(data) {
    var result = g.next(data);
    // 让 result.value 可以接收下一步执行的回调函数,这个就是 Thunk 的意义
    if (result.done) return;
    result.value(next);
  }
  next();
}

run(gen);

参考

https://es6.ruanyifeng.com/#docs/generator-async#Thunkify-%E6%A8%A1%E5%9D%97