发展由来
- Promise写起来代码较为冗余 总是要return new Promise和then拉链
- Generator手动控制在何处等待何处执行(一般都是等待异步操作)
- async/await是自动Generator
yield与neet参数
重点:yield作为分界线,如果有 var a = yield exp,还没执行赋值就返回exp了,而exp会根据下一次next的参数改变
遍历器对象的next方法的运行逻辑如下:
(1)遇到yield语句,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。
(2)下一次调用next方法时,再继续往下执行,直到遇到下一个yield语句。
(3)如果没有再遇到新的yield语句,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。
(4)如果该函数没有return语句,则返回的对象的value属性值为undefined。
next方法可以带一个参数,该参数就会被当作上一个yield语句的返回值。
function * f() {
for( let i =0; true; i++){
let reset = yield i;
if(reset){
i = -1;
}
}
}
let g = f();
console.log(g.next());
console.log(g.next());
console.log(g.next(true)); //yield返回值被设置为true,导致reset被赋值为true
输出结果:
{ value: 0, done: false }
{ value: 1, done: false }
{ value: 0, done: false }
可以看到最后的一步,我们使用next传入的true替代了i的值,最后导致i= -1 + 1 = 0.
我们再看一个例子:
function * f2(x){
var y = 2 * ( yield ( x + 1));
var z = yield (y / 3);
return (x + y + z);
}
var r1= f2(5);
console.log(r1.next());
console.log(r1.next());
console.log(r1.next());
var r2= f2(5);
console.log(r2.next());
console.log(r2.next(12));
console.log(r2.next(13));
输出结果:
{ value: 6, done: false }
{ value: NaN, done: false }
{ value: NaN, done: true }
{ value: 6, done: false }
{ value: 8, done: false }
{ value: 42, done: true }
注意,yield句本身没有返回值,或者说总是返回undefined,等到再一次next时,next的参数只是重新赋值yield后面的表达式的值,从而忽略yield。也就是说,如果next不传值的话,yield本身是没有返回值的,所以我们会得到NaN。但是如果next传入特定的值,则该值会替换该yield,成为真正的返回值。
async/await
简单的说async函数就相当于自执行的Generator函数,相当于自带一个状态机,在await的部分等待返回, 返回后自动执行下一步。而且相较于Promise,async的优越性就是把每次异步返回的结果从then中拿到最外层的方法中,不需要链式调用,只要用同步的写法就可以了。更加直观而且,更适合处理并发调用的问题。但是async必须以一个Promise对象开始 ,所以async通常是和Promise结合使用的。
async函数用法
上面说了async不过是Generator函数的语法糖,那为什么要取这个名字呢?自然是有理由的。 async是“异步”,而await是async wait的简写,即异步等待。所以应该很好理解async用于声明一个function是异步的,await用于等待一个异步方法执行完成
下面来看一个例子理解async命令的作用
async function test() {
return "async 有什么用?";
}
const result = test();
console.log(result)
输出:
Promise { 'async 有什么用?' }
可以看到,输出的是一个Promise对象**!**
所以,async函数返回的是一个Promise对象,如果直接return 一个直接量,async会把这个直接量通过PromIse.resolve()封装成Promise对象
注意点
一般来说,都认为await是在等待一个async函数完成,确切的说等待的是一个表示式,这个表达式的计算结果是Promise对象或者是其他值(没有限定是什么)
即await后面不仅可以接Promise,还可以接普通函数或者直接量。
同时,我们可以把async理解为一个运算符,用于组成表达式,表达式的结果取决于它等到的东西
- 等到非Promise对象 表达式结果为它等到的东西
- 等到Promise对象 await就会阻塞后面的代码,等待Promise对象resolve,取得resolve的值,作为表达式的结果
//回调写法
function fun1(value) {
retrun new Promise((resolve,reject)=> {
setTimeout(function(callback){
resolve(value++)
},2000);
})
}
fun1(0).then((value)=> {
return new Promise((resolve,reject)=> {
setTimeout(function(callback){
resolve(value++)
},2000);
}).then((value)=> {
return new Promise((resolve,reject)=> {
setTimeout(function(callback){
resolve(value++)
},2000);
}).then(value)=>{
console.log(value)
} // 4
//async函数写法
function fun1(value) {
retrun new Promise((resolve,reject)=> {
setTimeout(function(callback){
resolve(value++)
},2000);
})
} //返回promise实例
async function asy() {
let v = 0
v = await fun1(v) //等待promise的resolve值作为=右边的结果
v = await fun1(v)
v = await fun1(v)
console.log(v)
}
asy() //4