async 函数
含义
ES2017 标准引入了 async 函数,使得异步操作变得更加方便。
async 函数是什么?一句话,它就是 Generator 函数的语法糖。
生成器
function* foo() {
yield setTimeout(()=>{console.log("第一步耗时操作 开始执行")},1000)
yield setTimeout(()=>{console.log("第二步耗时操作 执行中")},2000)
yield setTimeout(()=>{console.log("第三步耗时操作 执行结束")},3000)
}
gen = foo()
gen.next()
gen.next()
gen.next()
for (let arrayElement of gen) {}
// async 语法糖 简写生成器的调用
async function foo() {
await setTimeout(()=>{console.log("第一步耗时操作 开始执行")},1000)
await setTimeout(()=>{console.log("第二步耗时操作 执行中")},2000)
await setTimeout(()=>{console.log("第三步耗时操作 执行结束")},3000)
}
foo()
一比较就会发现,async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已。
async函数对 Generator 函数的改进,体现在以下四点。
(1)内置执行器。
Generator 函数的执行必须靠执行器而async函数自带执行器。也就是说,async函数的执行,与普通函数一模一样,只要一行。
上面的代码调用了函数,然后它就会自动执行,输出最后结果。这完全不像 Generator 函数,需要调用next方法,或者用forof,才能真正执行,得到最后结果。
(2)更好的语义。
async和await,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。
(3)更广的适用性。
async函数的await命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。
(4)返回值是 Promise。
async函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then方法指定下一步的操作。
进一步说,async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。
语法
async函数的语法规则总体上比较简单,难点是错误处理机制。
返回 Promise 对象
async函数返回一个 Promise 对象。
async函数内部return语句返回的值,会成为then方法回调函数的参数。
async function f() {
return 'hello world';
}
f().then(v => console.log(v))
// "hello world"
# async也可以理解为是promimse的语法糖
async function foo() {
let num = Math.random()
console.log(num)
if(num < 0.5){
return "num < 0.5"
}else {
return "num >= 0.5"
}
}
function goo(){
return new Promise(resolve => {
let num = Math.random()
console.log(num)
if(num < 0.5){
resolve("num < 0.5")
}else {
resolve("num > 0.5")
}
})
}
foo().then((res)=>{
console.log(res)
})
上面代码中,函数foo内部return命令返回的值,会被then方法回调函数接收到。
async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态。抛出的错误对象会被catch方法回调函数接收到。
async function f() {
throw new Error('出错了');
}
f().then(
v => console.log('resolve', v),
e => console.log('reject', e)
)
//reject Error: 出错了
await 命令
正常情况下,await命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。
async function f() {
// 等同于
// return 123;
return await 123;
}
f().then(v => console.log(v))
// 123
上面代码中,await命令的参数是数值123,这时等同于return 123。
JavaScript 一直没有休眠的语法,但是借助await命令就可以让程序停顿指定的时间。下面给出了一个简化的sleep实现。
function sleep(interval) {
return new Promise(resolve => {
setTimeout(resolve, interval);
})
}
// 用法
async function one2FiveInAsync() {
for(let i = 1; i <= 5; i++) {
console.log(i);
await sleep(1000);
}
}
one2FiveInAsync();
错误处理
如果await后面的异步操作出错,那么等同于async函数返回的 Promise 对象被reject。
async function f() {
await new Promise(function (resolve, reject) {
throw new Error('出错了');
});
}
f()
.then(v => console.log(v))
.catch(e => console.log(e))
// Error:出错了
上面代码中,async函数f执行后,await后面的 Promise 对象会抛出一个错误对象,导致catch方法的回调函数被调用,它的参数就是抛出的错误对象。具体的执行机制,可以参考后文的“async 函数的实现原理”。
防止出错的方法,也是将其放在try...catch代码块之中。
async function f() {
try {
await new Promise(function (resolve, reject) {
throw new Error('出错了');
});
} catch(e) {
}
return await('hello world');
}
如果有多个await命令,可以统一放在try...catch结构中。
async function main() {
try {
const val1 = await firstStep();
const val2 = await secondStep(val1);
const val3 = await thirdStep(val1, val2);
console.log('Final: ', val3);
}
catch (err) {
console.error(err);
}
}
异步编程在JavaScript中变得更为简洁,ES2017引入的async函数是Generator函数的语法糖,提供了内置执行器和更好的语义。async函数返回Promise,其内的await关键字用于等待Promise结果,如果遇到错误,会返回reject状态的Promise。通过async/await,开发者可以更清晰地编写异步代码,避免回调地狱。

2681

被折叠的 条评论
为什么被折叠?



