导图社区 es6-generator
es6, generator, es6, generator, es6, generator, es6, generator, es6, generator, es6, generator, es6, generator, es6, generator,
编辑于2020-08-05 18:03:58es6
迭代协议
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Iteration_protocols#iterable
可迭代协议
可迭代对象
要成为可迭代对象, 一个对象必须实现 @@iterator 方法。这意味着对象(或者它原型链上的某个对象)必须有一个键为 @@iterator 的属性,可通过常量 Symbol.iterator 访问该属性: 属性 值 [Symbol.iterator] 返回一个符合迭代器协议的对象的无参数函数。
内置可迭代对象
String
Array
TypedArray
Map
Set
自定义可迭代对象
接受可迭代对象的内置 API
new Map([iterable]) new WeakMap([iterable]) new Set([iterable]) new WeakSet([iterable])
Promise.all(iterable) Promise.race(iterable) Array.from(iterable)
需要可迭代对象的语法
for...of循环
...展开语法
yield*
解构赋值
格式不佳的可迭代对象
迭代器示例
简单迭代器
无穷迭代器
使用生成器
生成器对象,也就是 Generatator 对象
let aGeneratorObject = function* (){ yield 1; yield 2; yield 3; }(); typeof aGeneratorObject.next; // 返回"function", 因为有一个next方法,所以这是一个迭代器 typeof aGeneratorObject[Symbol.iterator]; // 返回"function", 因为有一个@@iterator方法,所以这是一个可迭代对象 aGeneratorObject[Symbol.iterator]() === aGeneratorObject; // 返回true, 因为@@iterator方法返回自身(即迭代器),所以这是一个格式良好的可迭代对象 [...aGeneratorObject]; // 返回[1, 2, 3] console.log(Symbol.iterator in aGeneratorObject) // 返回true, 因为@@iterator方法是aGeneratorObject的一个属性
生成器对象既是迭代器,也是可迭代对象
Generatator对象
生成器对象是由一个 generator function 返回的,并且它符合可迭代协议和迭代器协议。-- MDN https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Generator
语法
简介
基本概念
yield表达式
与 Iterator 接口的关系
next方法的参数
for...of循环
   function* fibonacci() { let [prev, curr] = [0, 1]; for (;;) { yield curr; [prev, curr] = [curr, prev + curr]; } } for (let n of fibonacci()) { if (n > 1000) break; console.log(n); } function* objectEntries(obj) { let propKeys = Reflect.ownKeys(obj); for (let propKey of propKeys) { yield [propKey, obj[propKey]]; } } let jane = { first: 'Jane', last: 'Doe' }; for (let [key, value] of objectEntries(jane)) { console.log(`${key}: ${value}`); } // first: Jane // last: Doe function* numbers () { yield 1 yield 2 return 3 yield 4 } // 扩展运算符 [...numbers()] // [1, 2] // Array.from 方法 Array.from(numbers()) // [1, 2] // 解构赋值 let [x, y] = numbers(); x // 1 y // 2 // for...of 循环 for (let n of numbers()) { console.log(n) } // 1 // 2
Generator.prototype.next()
返回一个由 yield表达式生成的值。
Generator.prototype.throw()
向生成器抛出一个错误。
Generator.prototype.return()
返回给定的值并结束生成器。
next()、throw()、return() 的共同点
yield*表达式
yield* 表达式用于委托给另一个generator 或可迭代对象。 yield* 是一个表达式,不是语句,所以它会有自己的值。 MDN参考链接: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/yield*
含义
Generator 与状态机
Generator 与协程
Generator 与上下文
应用
异步操作的同步化表达
举例,Ajax,逐行读取文件
Ajax 是典型的异步操作,通过 Generator 函数部署 Ajax 操作,可以用同步的方式表达。 function* main() { var result = yield request("http://some.url"); var resp = JSON.parse(result); console.log(resp.value); } function request(url) { makeAjaxCall(url, function(response){ it.next(response); }); } var it = main(); it.next(); 通过 Generator 函数逐行读取文本文件。 function* numbers() { let file = new FileReader("numbers.txt"); try { while(!file.eof) { yield parseInt(file.readLine(), 10); } } finally { file.close(); } }
控制流管理
同步操作管理
类似与ES5的数组
异步操作管理
这个是个难点,但是async函数的出现,基本放弃了generator函数处理异步流程
传统方法
回调函数
事件监听
发布/订阅
Promise对象
co模块
co 模块其实就是将两种自动执行器(Thunk 函数和 Promise 对象),包装成一个模块
Thunk函数
其实就是回调函数
基于 Thunk 函数的自动执行器
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 对象
基于Promise 对象的自动执行器
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);
co 模块的源码
https://github.com/tj/co/blob/master/index.js
TODO
处理并发的异步操作
// 数组的写法 co(function* () { var res = yield [ Promise.resolve(1), Promise.resolve(2) ]; console.log(res); }).catch(onerror); // 对象的写法 co(function* () { var res = yield { 1: Promise.resolve(1), 2: Promise.resolve(2), }; console.log(res); }).catch(onerror); co(function* () { var values = [n1, n2, n3]; yield values.map(somethingAsync); }); function* somethingAsync(x) { // do something async return y }
实例:处理 Stream
const co = require('co'); const fs = require('fs'); const stream = fs.createReadStream('./les_miserables.txt'); let valjeanCount = 0; co(function*() { while(true) { const res = yield Promise.race([ new Promise(resolve => stream.once('data', resolve)), new Promise(resolve => stream.once('end', resolve)), new Promise((resolve, reject) => stream.once('error', reject)) ]); if (!res) { break; } stream.removeAllListeners('data'); stream.removeAllListeners('end'); stream.removeAllListeners('error'); valjeanCount += (res.toString().match(/valjean/ig) || []).length; } console.log('count:', valjeanCount); // count: 1120 });
部署 Iterator 接口
参照Iterator 成为Iterator对象的两个条件,符合 可迭代协议 和 迭代器协议,实现了next方法,具体细则,参照MDN网站。
作为数据结构
个人简单理解: generator函数执行后,生成了Generator对象,该对象继承了Generator函数的原型方法,next,throw,return。 而且,Generator对象就是一个可迭代对象,也是一个迭代器,也就是说,就是迭代器数据结构。
异步应用
ES2015类class中的迭代器
迭代器协议
@@iterator方法
迭代器
生成器函数, 也就是generator函数
你也可以使用构造函数 GeneratorFunction 或 function* expression 定义生成器函数
function* expression(表达式)
GeneratorFunction构造器
GeneratorFunction构造器生成新的生成器函数 对象。在JavaScript中,生成器函数实际上都是GeneratorFunction的实例对象。 注意,GeneratorFunction并不是一个全局对象。它可以通过下面的代码获取。 Object.getPrototypeOf(function*(){}).constructor
async