generator函数与async/await
理解async函数就要先理解generator函数,因为async就是Generator函数的语法糖
Generator 函数
Generator 函数是 ES6 提供的一种异步编程解决方案,可以先理解为一个状态机,封装了多个内部状态,执行Generator函数返回一个遍历器对象,通过遍历器对象,可以依次遍历 Generator 函数内部的每一个状态
语法上,Generator 函数是一个普通函数,但是有两个特征。
一是,function关键字与函数名之间有一个星号;
二是,函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”);
function* helloGenerator() {
yield 'hello'
yield 'Generator'
return 'ending'
}
let Generator = helloGenerator()
调用Generator函数后并不执行,返回的也不是函数运行结果而是一个指向内部状态的指针对象,也就是遍历器对象(Iterator Object)。
必须调用遍历器对象的next方法,使得指针移向下一个状态。
console.log(Generator.next()) // {value: 'hello', done: false}
console.log(Generator.next()) // {value: 'Generator', done: false}
console.log(Generator.next()) // {value: 'ending', done: true}
第一次调用next方法,Generator函数开始执行,直到遇到yield表达式为止。next方法返回一个对象,value属性就是当前yield表达式的值hello,done属性的值false,表示遍历还没有结束。
第二次调用next方法,Generator 函数从上次yield表达式停下的地方,一直执行到下一个yield表达式
继续调用next方法直到done属性值为true或者执行到return语句(如果没有return语句就执行到函数结束),表示遍历已经结束
如果再次调用next方法,此时Generator函数已经运行完毕,next方法返回对象的value属性为undefined,done属性为true。以后再调用next方法,返回的都是这个值
yield 表达式
可以理解为暂停的标志,遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。yield表达式与return语句都能返回紧跟在语句后面的那个表达式的值。区别在于每次遇到yield,函数暂停执行,下一次再从该位置继续向后执行,而return语句不具备位置记忆的功能。一个函数里面,只能执行一次return语句,但是可以执行多次yield表达式。从另一个角度看,也可以说 Generator 生成了一系列的值,这也就是它的名称的来历(英语中,generator 这个词是“生成器”的意思)。另外需要注意,yield表达式只能用在 Generator 函数里面,用在其他地方都会报错。
next方法的参数
next方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值
function* foo(x) {
let y = yield x + 1
let k = yield y + 2
yield k / 2
return k
}
let a = foo(1)
console.log(a.next()) // {value: 2, done: false}
console.log(a.next(3)) // {value: 5, done: false}
console.log(a.next(8)) // {value: 4, done: false}
console.log(a.next()) // {value: 8, done: true}
第一次运行next方法时,返回1+1的值2;第二次调用next方法,将上一次yield表达式的值设为3,y等于3,返回y + 2的值5;第三次调用next方法,将上一次yield表达式的值设为8,k等于8,返回k/2的值4
注意,由于next方法的参数表示上一个yield表达式的返回值,所以在第一次使用next方法时,传递参数是无效的。
next()、throw()、return()
除了next方法还有throw()、return()两个方法,这三个方法本质上是同一件事,可以放在一起理解。它们的作用都是让 Generator 函数恢复执行,并且使用不同的语句替换yield表达式。
next()是将yield表达式替换成一个值。
throw()是将yield表达式替换成一个throw语句。
const g = function* (x, y) {
let result = yield x + y;
return result;
};
const gen = g(1, 2);
gen.throw(new Error('出错了')); // Uncaught Error: 出错了
// 相当于将 let result = yield x + y 替换成 let result = throw(new Error('出错了'));
return()是将yield表达式替换成一个return语句。
gen.return(2); // {value: 2, done: true}
// 相当于将 let result = yield x + y替换成 let result = return 2;
yield* 表达式
ES6提供了yield*表达式,用来在一个Generator函数里面执行另一个Generator函数。
function* foo(x) {
yield 1
yield* bar()
yield 4
}
function* bar() {
yield 2
yield 3
}
let a = foo()
console.log(a.next()) // {value: 1, done: false}
console.log(a.next()) // {value: 2, done: false}
console.log(a.next()) // {value: 3, done: false}
console.log(a.next()) // {value: 4, done: false}
console.log(a.next()) // {value: undefined, done: true}
由于yield* bar()语句得到的值,是一个遍历器,所以要用星号表示。运行结果就是使用一个遍历器,遍历了多个Generator函数,有递归的效果。
yield*后面的 Generator 函数(没有return语句时),等同于在 Generator 函数内部,部署一个for...of循环。
async/await
ES7 中引入了 async/await,async 是一个通过异步执行并隐式返回 Promise 作为结果的函数。async 函数的实现原理,就是将 Generator函数和自动执行器,包装在一个函数里。
根据阮一峰老师的介绍,async函数就是Generator函数的语法糖,并对Generator函数进行了改进。
上面代码async函数就是将Generator函数的星号(*)替换成async,将yield替换成await,仅此而已
async函数对 Generator 函数的改进,体现在以下四点
- 内置执行器
Generator 函数的执行必须靠执行器,需要调用next方法,才能真正执行,得到最后结果。 - 更好的语义
async和await,比起星号和yield,语义更加清楚。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。 - 更广的适用性
co模块约定,yield命令后面只能是 Thunk 函数或 Promise 对象,而async函数的await命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象) - 返回值是promise
async函数的返回值是Promise对象,比Generator函数的返回值是Iterator对象方便多了。可以用then方法指定下一步的操作。
async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。
generator函数与async/await的更多相关文章
- vue 钩子函数 使用async await
示例: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <tit ...
- Generator function vs Async/Await
Generator function vs Async/Await generator async /await refs xgqfrms 2012-2020 www.cnblogs.com 发布文章 ...
- ES6 Generator vs ES6 async/await
ES6 Generator vs ES6 async/await next yield promise refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允 ...
- ES6入门十一:Generator生成器、async+await、Promisify
生成器的基本使用 生成器 + Promise async+await Promise化之Promisify工具方法 一.生成器的基本使用 在介绍生成器的使用之前,可以简单理解生成器实质上生成的就是一个 ...
- [转] Understanding JavaScript’s async await
PS:Promise的用处是异步调用,这个对象使用的时候,call then函数,传一个处理函数进去,处理异步调用后的结果 Promise<Action>这样的对象呢,异步调用后的结果是一 ...
- promise async await使用
1.Promise (名字含义:promise为承诺,表示其他手段无法改变) Promise 对象代表一个异步操作,其不受外界影响,有三种状态: Pending(进行中.未完成的) Resolved( ...
- JavaScript中的Generator函数
1. 简介 Generator函数时ES6提供的一种异步编程解决方案.Generator语法行为和普通函数完全不同,我们可以把Generator理解为一个包含了多个内部状态的状态机. 执行Genera ...
- Promise和async await详解
本文转载自Promise和async await详解 Promise 状态 pending: 初始状态, 非 fulfilled 或 rejected. fulfilled: 成功的操作. rejec ...
- Async/Await替代Promise的6个理由
译者按: Node.js的异步编程方式有效提高了应用性能:然而回调地狱却让人望而生畏,Promise让我们告别回调函数,写出更优雅的异步代码:在实践过程中,却发现Promise并不完美:技术进步是无止 ...
随机推荐
- Spring Boot 整合 Apache Ignite
关于Ignite的介绍,这边推荐三个链接进行学习了解. https://ignite.apache.org/,首选还是官网,不过是英文版,如果阅读比较吃力可以选择下方两个链接. https://www ...
- JavaScript兼容性汇总
一般兼容性问都体现到DOM和事件上 只聊ie6+版本浏览器,希望小伙伴们别纠结更低版本浏览器哈^_^ DOM 获取元素 document.getElementsByclassName 不兼容ie6 ...
- Postman实现SHA256withRSA签名
@ 目录 获取pmlib 引入依赖bundle.js,有以下两种方式: 使用Pre-request Script对请求进行加签(具体加签字段请看自己项目) 获取pmlib 引入依赖bundle.js, ...
- 【UE4 C++】 UDataAsset、UPrimaryDataAsset 的简单使用
UDataAsset 简介 用来存储数据,每一个DataAsset 都是一份数据 可以派生,系统自带派生 UPrimaryDataAsset 方便数据对象的加载和释放 可以引用其他的 UDataAss ...
- kiyv Button参数属性
from kivy.uix.button import Button from kivy.uix.floatlayout import FloatLayout from kivy.app import ...
- RBAC 权限管理模型
一.RBAC模型--基于角色的访问控制 什么是RBAC RBAC(Role-Based Access Control)基于角色的访问控制.这是从传统的权限模型的基础之上,改进而来并且相当成熟的权限模型 ...
- [Beta]the Agiles Scrum Meeting 2
会议时间:2020.5.11 20:00 1.每个人的工作 今天已完成的工作 成员 已完成的工作 yjy 修复bug将自动评测改为异步HTTP请求 tq 实现查看.删除测试点功能的后端将自动评测改为异 ...
- TVS管性能及选型总结
https://wenku.baidu.com/view/5b5bda5526fff705cc170af8.html
- 洛谷 P5785 [SDOI2012] 任务安排
链接: P5785 弱化版:P2365 题意: 有 \(n\) 个任务待完成,每个任务有一个完成时间 \(t_i\) 和费用系数 \(f_i\),相邻的任务可以被分成一批.从零时刻开始这些任务会被机器 ...
- vim vi 高亮第80列 Python PEP8规范 行最大长度设置
命令模式下 :set cc=80 或者 打开 vim的配置 文件 .vimrc vim ~/.vimrc 接着你会看到你的配置文件 在配置文件中加上这样行配置代码 set cc=80 ok 现在退出v ...