Open yaofly2012 opened 4 years ago
var a = 0
var b = async () => {
a = a + await 10
console.log('2', a)
}
b()
a++
console.log('1', a)
异步函数执行会保存调用栈上下文,变量a
又是个值变量。看下引用类型的:
var a = { num: 0 }
var b = async () => {
a.num = a.num + await 10
console.log('2', a.num)
}
b()
a.num++
console.log('1', a.num)
输出结果并没有变化,可以推断调用栈里保存的引用的变量值。 修改下调用顺序:
var a = 0
var b = async () => {
let c = await 10
a = a + c
console.log('2', a) // 2 11
}
b()
a++
console.log('1', a) // 1 1
这又是为啥呢?
执行到 await 的时候会保留 堆栈中的东西,这个时候变量a并没有使用,所以并没有保留 a = 0;当 await 结束后,再使用变量a,此时a的值经过 a++ 已经变成了 1 了。所以最后输出的是11。
可以推断await
(本质是yiled
)把异步函数(生成器函数)分割成一段段可单独执行的代码片段,形成的调用栈也是单独的(要深入理解协程概念了)。
Promise.resolve()
.then(() => {
console.log(1);
})
.then(() => {
console.log(2);
})
;(async function() {
console.log('a')
await 1;
console.log('b')
})()
Promise.resolve()
.then(() => {
console.log(3);
})
a1b32
async function f3() {
var y = await 20;
console.log(y); // 20
}
f3();
Promise.resolve()
.then(() => {
console.log(1)
})
async function f3() {
var y = await Promise.resolve(20);
console.log(y); // 20
}
f3();
Promise.resolve()
.then(() => {
console.log(1)
})
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function () {
console.log('setTimeout');
}, 0);
async1();
new Promise(function (resolve) {
console.log('promise1');
resolve();
}).then(function () {
console.log('promise2');
});
console.log('script end');
一、
async/await
语法1.1
async
函数(异步函数)async
修饰的函数就是异步函数async
要放在function
前面而不是在其后面,它是修饰函数的。并且任何可以是函数的地方(无论是函数声明语句还是函数表达式)都可以使用async
修饰。async
函数会做两件事:Promise
对象:await
。如果函数返回值本身就是个
Promise
对象,则也是会包裹成Promise
var p = null;
async function opA() { return p = wait(5000); }
;(async () => { var r = opA(); console.log(r === p) // false })();
await
只能用在async
函数里,它让async
函数暂停执行,一直到Promise
对象进入终态;Promise
对象的终态对await
行为的影响:await
表达式的值;reason
作为异常值;本质上
await
后面可以是任意表达式,await
会把后面表达式值包裹为一个fulfilled
的 Promise对象(即使表达式的值是
Promise`对象)func();
规范里应该是采用
new Promise(resolve => resolve())
,但是实现中有些进行了优化,即采用Promise.resolve
,目前测试下来 Chrome(v81)已经优化了。但是总体各浏览器/nodejs存在实现差异。 扩展:1.3 串行和并行问题
首先记住同一个函数作用域的
await
表达式都是依次执行,只有前面的await的Promise进行终态,才会执行下一个await。如果要让多个异步操作“并行”,则需要把await
放在不同的函数作用域里。 MDN上面的例子很好,要好好看看:就是把多个
await
表达式包装在多个匿名的异步函数里,这样他们就不在同一个函数作用域了,就不会产生依赖关系。 总结一句话: 只把存在前后依赖的await
放在同一个函数作用域里。大部分使用 async/await 困境也都是因为没弄清楚同步异步问题导致的。二、异常处理
2.1 基础
async
函数永远不会对外抛异常,它把内部异常转成返回值Promise的rejected的reason;await
会抛异常。2.2 关于异常处理
没有组好的方式,只有更适合的方式。 还有中写法(个人比较喜欢的方式):在调用链最外层try-catch,内部不用try-catch或内部try-catch处理后直接往外再抛。
三、为啥要使用async/await 进行异步流程管理 ?
async/await = Generator + Promise
Promise
的书写格式;参考