这篇文章多看几遍加深理解
async function 声明定义了一个异步函数,它返回一个AsyncFunction对象。异步函数 是指通过 事件循环(event loop) 异步执行的函数,通过返回一个隐式的 Promise 作为其结果。使用异步函数的代码的语法和结构更像使用标准同步功能。(The async function declaration defines an asynchronous function, which returns an AsyncFunction object. An asynchronous function is a function which operates asynchronously via the event loop, using an implicit Promise to return its result. But the syntax and structure of your code using async functions is much more like using standard synchronous functions.
)
async function name([param[, param[, ... param]]]) { statements }
参数:
返回值:返回一个promise
对象,将返回异步函数返回的值(如果异步函数是resolved则返回resolved的值;如果抛出异常,则rejected从异步函数中抛出的异常)。(A Promise which will be resolved with the value returned by the async function, or rejected with an uncaught exception thrown from within the async function.)
异步函数可以包含await
表达式,该表达式暂停异步函数的执行 并等待 Promise的执行结果返回,结果返回后就恢复异步函数的执行。
await 关键字只在异步函数(async functions)内有效。如果在异步函数外使用它,会抛出语法错误。
当异步函数暂停时,它调用的函数仍会继续执行。
举例一:
function resolveAfter5Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 5000);
});
}
async function asyncCall() {
console.log('calling');
let result = await resolveAfter5Seconds();
console.log(result); // 5s之后输出结果
}
asyncCall(); //返回的是一个promise对象
// console.log(asyncCall()); // Promise { }
let resolveAfter6Second = function () {
console.log('start slow promise');
return new Promise(resolve => {
setTimeout(() => {
resolve('slow');
console.log('slow promise is done');
}, 6000);
})
}
let resolveAfter4Second = function () {
console.log('start fast promise');
return new Promise(resolve => {
setTimeout(() => {
resolve('fast');
console.log('fast promise is done');
}, 4000);
})
}
let sequentialStart = async function () {
console.log('sequential start');
const slow = await resolveAfter6Second();
console.log(slow);
const fast = await resolveAfter4Second();
console.log(fast);
}
sequentialStart()
//立即输出
// sequential start
// start slow promise
//再过6秒后输出
// slow promise is done
// slow
// start fast promise
//再过4秒后输出
// fast promise is done
// fast
运行效果:
换一种await
的写法,结果完全不同:两个计时器被同时创建
let resolveAfter6Seconds = function () {
console.log('start slow promise');
return new Promise(resolve => {
setTimeout(() => {
resolve('slow');
console.log('slow promise is done');
}, 6000);
})
}
let resolveAfter4Seconds = function () {
console.log('start fast promise');
return new Promise(resolve => {
setTimeout(() => {
resolve('fast');
console.log('fast promise is done');
}, 4000);
})
}
let concurrentStart = async function () {
console.log('concurrent start');
let slow = resolveAfter6Seconds();
let fast = resolveAfter4Seconds();
console.log(await slow);
console.log(await fast);
}
setTimeout(() => {
concurrentStart();
}, 2000);
//2秒后执行
// concurrent start
// start slow promise
// start fast promise
//再过4秒后执行
// fast promise is done
//再过2秒后执行
// slow promise is done
// slow
// fast
运行效果:
在 concurrentStart 中,两个计时器被同时创建,接着执行await。等待的是 promise的resolve回调,resolve后面的代码( console.log(‘fast promise is done’);)会继续执行。
这两个计时器同时运行。但是 await 仍旧是顺序执行的,第二个 await 还是得等待第一个执行完。在这个例子中,这使得先运行结束的输出出现在最慢的输出之后。
也可以把 concurrentStart 改写成如下,运行效果一样:
let resolveAfter6Seconds = function () {
console.log('start slow promise');
return new Promise(resolve => {
setTimeout(() => {
resolve('slow');
console.log('slow promise is done');
}, 6000);
})
}
let resolveAfter4Seconds = function () {
console.log('start fast promise');
return new Promise(resolve => {
setTimeout(() => {
resolve('fast');
console.log('fast promise is done');
}, 4000);
})
}
let concurrentPromise = async function () {
console.log('concurrent start');
return Promise.all([resolveAfter6Seconds(), resolveAfter4Seconds()]).then((messages) => {
console.log(messages[0]); // slow
console.log(messages[1]); // fast
});
}
setTimeout(() => {
concurrentPromise();
}, 2000);
//2秒后输出
// concurrent start
// start slow promise
// start fast promise
//再过6秒后输出
// fast promise is done
//再过2秒后输出
// slow promise is done
// slow
// fast
并行执行两个或更多的任务,如下例所示:
let resolveAfter6Seconds = function () {
console.log('start slow promise');
return new Promise(resolve => {
setTimeout(() => {
resolve('slow');
console.log('slow promise is done');
}, 6000);
})
}
let resolveAfter4Seconds = function () {
console.log('start fast promise');
return new Promise(resolve => {
setTimeout(() => {
resolve('fast');
console.log('fast promise is done');
}, 4000);
})
}
let parallel = async function () {
console.log('start paralel');
await Promise.all([
(async () => console.log(await resolveAfter6Seconds()))(),
(async () => console.log(await resolveAfter4Seconds()))()
]);
}
setTimeout(parallel, 2000);
//2秒后输出
// start paralel
// start slow promise
// start fast promise
//再过4秒后输出
// fast promise is done
// fast
//再过2秒后输出
// slow promise is done
// slow
运行效果:
如果希望并行执行两个或更多的任务,你必须像在parallel中一样使用await Promise.all([job1(), job2()])
也可以把parallel改写成如下,运行效果一样:
let resolveAfter6Seconds = function(){
console.log('start slow promise');
return new Promise(resolve => {
setTimeout(() => {
resolve('slow');
console.log('slow promise is done');
}, 6000);
});
}
let resolveAfter4Seconds = function(){
console.log('start fast promise');
return new Promise(resolve =>{
setTimeout(() => {
resolve('fast');
console.log('fast promise is done');
}, 4000);
})
}
let parallelPromise = function(){
console.log('parallelPromise start');
resolveAfter6Seconds().then(msg => console.log(msg));
resolveAfter4Seconds().then(msg => console.log(msg));
}
setTimeout(() => {
parallelPromise();
}, 2000);
//2秒后输出
// parallelPromise start
// start slow promise
// start fast promise
//再过4秒后输出
// fast promise is done
// fast
//再过2秒后输出
// slow promise is done
// slow
async/await和Promise#then对比以及错误处理:
大多数异步函数(async functions )也可以使用 Promises函数 编写。然而,当涉及到错误处理时,异步函数不太容易出错。
上面例子中的concurrentStart函数和concurrentPromise函数在功能上都是等效的。在concurrentStart函数中,如果任一awaited调用失败,它将自动捕获异常,异步函数执行中断,并通过隐式返回Promise将错误传递给调用者。
在Promise例子中这种情况同样会发生,函数必须负责返回一个捕获函数完成的Promise。在concurrentPromise函数中,这意味着它从Promise.all([]).then()中返回一个Promise。事实上,在此示例的先前版本忘记了这样做!
但是,async函数仍有可能然可能错误地忽略错误。
以parallel异步函数为例。 如果它没有等待await(或 return)Promise.all([])调用的结果,则不会传播任何错误。
虽然parallelPromise函数示例看起来很简单,但它根本不会处理错误! 这样做需要一个类似于return Promise.all([])处理方式。(详见)
返回 Promise的 API 将会产生一个 promise 链,它将函数分解成许多部分。例如下面的代码:
function getProcessedData(url) {
return downloadData(url)// returns a promise
.catch(e => {
return downloadFallbackData(url);// returns a promise
})
.then(v => {
return processDataInWorker(v);// returns a promise
})
}
可以重写为单个async函数:
async function getProcessedData(url) {
let v;
try {
v = await downloadData(url);
} catch (e) {
v = await downloadFallbackData();
}
return processDataInWorker(v);
}
在上述示例中,return 语句中没有 await 操作符,因为 async function 的返回值将被隐式地传递给 Promise.resolve。
return await promiseValue;
与 return promiseValue;
的比较返回值隐式的传递给Promise.resolve
,并不意味着return await promiseValue;
,只是在功能上等同于返回return promiseValue;
。
重写的上面代码,在processDataInWorker抛出异常时返回null:
async function getProcessedData(url) {
let v;
try {
v = await downloadData(url);
} catch(e) {
v = await downloadFallbackData(url);
}
try {
return await processDataInWorker(v); // 注意 `return await` 和单独 `return` 的比较
} catch (e) {
return null;
}
}
简单地写上return processDataInworker(v);将导致在processDataInWorker(v)出错时function返回值为Promise而不是返回null。
return foo;
和return await foo;
有一些细微的差异:
return foo;
不管foo是promise还是rejects都将会直接返回foo。相反地,如果foo是一个Promise,return await foo;将等待foo执行(resolve)或拒绝(reject),如果是拒绝,将会在返回前抛出异常。