这里写目录标题
- 一、基本概念
- 二、代码
- 三、Generator 函数的异步应用
- 三级目录
一、基本概念
- Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同,Generator 函数有多种理解角度。
- 语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态。
执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。 - 形式上,Generator函数是一个普通函数,但是有两个特征。一是, function 关键字与函数名之间有一个星号;二是,函数体内部使用 yield 表达式,定义不同的内部状态( yield 在英语里的意思就是“产出”)。
- 由于 Generator 函数返回的遍历器对象,只有调用 next 方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield表达式就是暂停标志。
二、代码
//生成器函数:function关键字和函数名之间有一个*function* add(){console.log('start');let x = yield '2';console.log('one:'+2);let y = yield '3';console.log('two:'+y);return x+y;}// 返回一个遍历器对象let fn=add();// next() 恢复执行标志console.log(fn.next());// 当 next() 传入参数时,该参数就会被当作上一个 yield 表达式的返回值 ,即 x = 20, y = 3console.log(fn.next(20));// one:20 {value: '3', done: false}console.log(fn.next(30));// two:30 {value: '50', done: true}
- 使用场景:为不具备 Iterator 接口的对象提供了遍历操作
- 利用for…of循环,可以写出遍历任意对象(object)的方法。原生的 JavaScript 对象没有遍历接口(不具备 Symbol.iterator方法),无法使用for…of循环,通过 Generator 函数为它加上这个接口,即将 Generator 函数加到对象的Symbol.iterator属性上面,就可以用了。
//Gemerator 生成器函数function* objectEntries(obj) {//获取对象的所有key保存到数组const propKeys = Object.keys(obj);for (const propkey of propKeys) {yield [propkey, obj[propkey]]}}const obj = {book: 'ES6学习',price: 18}// 把 Generator 生成器函数赋值给对象的Symbol.iterator属性, 为该对象加上遍历器接口obj[Symbol.iterator] = objectEntries;console.log(obj);//{book: 'ES6学习', price: 18, Symbol(Symbol.iterator):// objectEntries(obj) 等价于 obj[Symbol.iterator](obj) for (let [key, value] of objectEntries(obj)) {console.log(`${key}: $value`);}
三、Generator 函数的异步应用
Generator 函数在ajax请求的异步应用,让异步代码同步化
Generator 函数在加载页面的异步应用
//Generator 函数在加载页面的异步应用// 1.加载 Loading...页面// 2.数据加载完成...(异步操作)// 3.Loading 关闭掉function loadUI() {console.log('加载 Loading...页面');}function showData() {// 模拟数据加载异步操作setTimeout(() => {console.log('数据加载完成');}, 1000);}function hideUI() {console.log('隐藏 Loading...页面');}loadUI();showData();hideUI();
上述代码执行后效果:
加载 Loading...页面
隐藏 Loading...页面
数据加载完成
实际需求是加载数据完成后才关闭页面,但由于三个函数函数是同步执行的,数据加载需要时间,在数据未加载完成时,就已经隐藏loading页面。通过 Generator 函数可以解决这个问题。
function* load(){loadUI();yield showData(); hideUI()}const itLoad = load();itLoad.next();function loadUI() {console.log('加载 Loading...页面');}function showData() {// 模拟数据加载异步操作setTimeout(() => {console.log('数据加载完成');itLoad.next();}, 1000);}function hideUI() {console.log('隐藏 Loading...页面');}