// With function declaration
async function myFn() {
// await ...
}
// With arrow function
const myFn = async () => {
// await ...
}
function myFn() {
// await fn(); (Syntax Error since no async)
}
Async 插入在函數宣告的最開始處,如果是箭頭函數,則插入在「=」號和括號之間。
這些函數可以作為方法放置在物件中,也可以在類別聲明中使用。
// As an object's method
const obj = {
async getName() {
return fetch('https://www.example.com');
}
}
// In a class
class Obj {
async getResource() {
return fetch('https://www.example.com');
}
}
注意! 值得記住的是,類別建構子和 getter/setter 不能是異步的。
語意和執行規則
非同步函數與標準 JS 函數基本相似,但也有例外。
因此,非同步函數總是傳回 Promise:
async function fn() {
return 'hello';
}
fn().then(console.log)
// hello
// utility function to cause delay
// and get random value
const delayAndGetRandom = (ms) => {
return new Promise(resolve => setTimeout(
() => {
const val = Math.trunc(Math.random() * 100);
resolve(val);
}, ms
));
};
async function fn() {
const a = await 9;
const b = await delayAndGetRandom(1000);
const c = await 5;
await delayAndGetRandom(1000);
return a + b * c;
}
// Execute fn
fn().then(console.log);
這裡是 fn 函數如何運作的描述。
呼叫後,第一行由 const a = wait 9; 轉換而來。 在 const a = wait Promise.resolve(9); 中。
const wait = (i, ms) => new Promise(resolve => setTimeout(() => resolve(i), ms));
// Implementation One (Using for-loop)
const printNumbers = () => new Promise((resolve) => {
let pr = Promise.resolve(0);
for (let i = 1; i <= 10; i += 1) {
pr = pr.then((val) => {
console.log(val);
return wait(i, Math.random() * 1000);
});
}
resolve(pr);
});
// Implementation Two (Using Recursion)
const printNumbersRecursive = () => {
return Promise.resolve(0).then(function processNextPromise(i) {
if (i === 10) {
return undefined;
}
return wait(i, Math.random() * 1000).then((val) => {
console.log(val);
return processNextPromise(i + 1);
});
});
};
這是使用非同步函數的解決方案。
async function printNumbersUsingAsync() {
for (let i = 0; i < 10; i++) {
await wait(i, Math.random() * 1000);
console.log(i);
}
}
錯誤處理
未處理的錯誤包含在被拒絕的承諾中。 但是,非同步函數可以使用 try/catch 來同步處理錯誤。
async function canRejectOrReturn() {
// wait one second
await new Promise(res => setTimeout(res, 1000));
// Reject with ~50% probability
if (Math.random() > 0.5) {
throw new Error('Sorry, number too big.')
}
return 'perfect number';
}