微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ES6实现generator的自动调用

简述

首先我们知道generator的内部实现采用了一种类似于协程的方法,即在在函数执行的过程之中遇到yield关键字时,就会暂时退出堆栈,但是并不消失,里面的所有变量和对象会冻结在当前状态。等到对它执行next命令时,这个上下文环境又会重新加入调用栈,冻结的变量和对象恢复执行。

同步任务

对于同步任务而言,我们只需要保证执行完毕即可,不需要确保执行的顺序问题

直接使用for...of...循环 或者使用递归实现

异步任务

JavaScript 语言对异步编程的实现,就是回调函数

如果我们能在回调函数之中重新激活generator中的被冻结的调用栈,不断重复,直至全部调用完成,这样就实现了generator的自动调用

自动执行的关键是,必须有一种机制,自动控制 Generator 函数的流程,接收和交还程序的执行权

对于回调函数的处理主要下面介绍Thunk 函数和promise两种方法

Thunk 函数

在 JavaScript 语言中通过Thunk函数,把一个具有回调函数包装成一个只接受回调函数作为参数的单参数函数

例如

fs.readFile(fileName, callback);

// Thunk版本的readFile(单参数版本)
var Thunk = function (fileName) {
  return function (callback) {
    return fs.readFile(fileName, callback);
  };
};

var readFileThunk = Thunk(fileName);
readFileThunk(callback);

我们可以把任何的函数都写成Thunk 函数

function thunkify(fn) {
    return function() {
      var args = new Array(arguments.length);
      var ctx = this;
  
      for (var i = 0; i < args.length; ++i) {
        args[i] = arguments[i];
      }
  
      return function (done) {
        var called;
  
        args.push(function () {
          if (called) return;
          called = true;
          done.apply(null, arguments);
        }); // 确保回调函数只会执行一次
  
        try {
          fn.apply(ctx, args);
        } catch (err) {
          done(err);
        }
      }
    }
  };

根据上述的包装后的函数generator自动调用实现如下

function run(fn) {
  var gen = fn();

  function next(err, data) {
    var result = gen.next(data);// 得到当次的执行结果
    if (result.done) return;
    result.value(next);// 在回调函数中继续调用直到完成
  }

  next();
}

function* g() {
  // ...
}

run(g);

Promise实现如下

基于promise1的自动执行其实就是在then的回调函数中,不断的调用执行,直到结束

function run(gen){
  var g = gen();

  function next(data){
    var result = g.next(data);
    if (result.done) return result.value;
    result.value.then(function(data){
      next(data);
    });
  }

  next();
}

run(gen);

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐