什么是Generator 如何定义
Generator 是一个带星号的“函数”(它并不是真正的函数,下面的代码会为你验证),可以配合 yield 关键字来暂停或者执行函数。
function* gen() {
console.log("enter");
let a = yield 1;
let b = yield (function () {return 2})();
return 3;
}
var g = gen() // 阻塞住,不会执行任何语句
console.log(g.next())
console.log(g.next())
console.log(g.next())
console.log(g.next())
// output:
// { value: 1, done: false }
// { value: 2, done: false }
// { value: 3, done: true }
// { value: undefined, done: true }
是怎么工作的
- 生成器不一定会执行生成器函数体,通过创建迭代器对象,可以与生成器通信
- 迭代器用于控制生成器的执行。迭代对象暴露的最基本接口是next方法迭,这方法可以用来向生成器请求一个值, 从而控制生成器
- next函数调用后,生成器就开始执行代码,当代码执行到yield关键字时,就会生成一个中间结果(生成值序列中的一项),然后返回一一个**新对象,**其电封装了结果健一个指示完成的指示器。
- 每当生成一个当前值后,生成器就会非阻塞地挂起执行,随后耐心等待下一次值滑求的到达。这是普通函数完全不具有的强大特性,后续的例子中它还会起到更大的作用。
Generator的内部构成
我们已经知道了调用一个生 成器不会实际执行它。相反,它创建了一一个新的迭代器,通过该迭代器我们才能从生成器中请求值在生成器生成(或让渡)了一个值后,生成器会挂起执行并等待下一一个请求的到来。在某种方面来说,生成器的工作更像是一个小 程序,一个在状态中运 动的状态机。
-
挂起开始创建了一个生成器后,它最先以这种状态开始。其中的任何代码都未执行。
-
执行生成器中的代码执行的状态。执行要么是刚开始,要么是从上次挂起的时候继续的。当生成器对应的迭代器调用了next方法,并且当前存在可执行的代码时,生成器都会转移到这个状态,
-
挂起让渡——当生成器在执行过程中遇到了一个yield表达式,它会创建一个包含着返回值的新对象,随后再挂起执行。生成器在这个状态暂停并等待继续执行。
-
完成——在生成器执行期间,如果代码执行到return 语句或者全部代码执行完毕,生成器就进入该状态。
与生成器的交互
- 作为生成器函数参数发送值
- 使用next方法向生成器发送值
yield基本介绍
yield 同样也是 ES6 的新关键词,配合 Generator 执行以及暂停。yield 关键词最后返回一个迭代器对象,该对象有 value 和 done 两个属性,其中 done 属性代表返回值以及是否完成。yield 配合着 Generator,再同时使用 next 方法,可以主动控制 Generator 执行进度。
什么是thunk函数
thunk函数的作用非常简单 其实就是把一个函数的 执行参数 和 回调分成两个函数(可以把函数本身也进行包装) 只要是有回调函数的 就可以用thunk进行包装
thunk定义
fn(args, callback)--->变成--->thunk(fn)(args)(callback)
Generator和thunk如何结合
因为thunk的执行函数和回调函数是分开的,会造成
- 代码逻辑里面上面来说不符合常规逻辑
- 回调函数里面嵌套逻辑处理太多的话,那thunk的优势就没了
执行函数执行-->等待回调函数传回数据-->用户对于获取的数据进行操作
- 把所有的执行函数放入generator函数里面,利用generator函数的yield对执行函数的流程控制
- 把函数执行权移出函数到对应的回调函数,获取数据后再把数据返回来
- 等到下次再遇到next()函数,函数执行权又回到生成器
var fs = require('fs');
var thunkify = require('thunkify');
var readFile = thunkify(fs.readFile);
//发现执行参数的函数在一起
var gen = function* () {
var data1 = yield readFile('./a.txt');
//用户获取数据后自定义写在这里
console.log(data1.toString());
var data2 = yield readFile('./b.txt');
//用户获取数据后自定义写在这里
console.log(data2.toString());
}
//写个执行函数
//发现callback在一起 而且调用的形式都一样
var g = gen();
//var d1 = g.next();
//执行value 实际为执行总函数 -->回调函数
// d1.value(function(err, data) {
// if (err) throw err;
// //传回数据
// var d2 = g.next(data);
// d2.value(function(err, data2) {
// if (err) throw err;
// g.next(data2);
// });
// });
//下面是利用thunk对函数进行总结书写
function run(gen){
const next = (err, data) => {
let res = gen.next(data);
if(res.done) return;
res.value(next);
}
next();
}
run(g)