https://www.cnblogs.com/liquanjiang/p/11409792.html 轉自
https://www.cnblogs.com/bear-blogs/p/10423759.html 參考
https://www.cnblogs.com/CandyManPing/p/9384104.html
await 操作符
MDN 是這樣描述 await 的:
await 表達式會暫停當前 async function 的執行,等待 Promise 處理完成。若 Promise 正常處理(fulfilled),其回調的resolve函數參數作為 await 表達式的值,繼續執行async function。若 Promise 處理異常(rejected),await 表達式會把 Promise 的異常原因拋出。另外,如果 await 操作符后的表達式的值不是一個 Promise,則返回該值本身。
阮一峰老師的解釋我覺得更容易理解:
async 函數返回一個 Promise 對象,當函數執行的時候,一旦遇到 await 就會先返回,等到觸發的異步操作完成,再接着執行函數體內后面的語句。
按照mdn解釋 await會暫停當前async 函數執行,並且await 后面是一個表達式,即這個await 等待的是一個表達式(這個表達式返回promise 對象或者一個具體的值):
- 假如這個表達式如果返回的是一個Promise 對象, 那么它的返回值,實際上就是 Promise 的回調函數 resolve 的參數,如果這個Promise rejected 了,await 表達式會把 Promise 的異常拋出。
- 假如這個表達式如果返回的是一個常量,那么會把這個常量轉為Promise.resolve(xx),同理如果沒有返回值也是Promise.resolve(underfind)
我的理解是,await表達式后面的promise狀態是成功,那么resolve函數的參數就是await表達式的值 ,然后繼續執行async function,但是如果promise狀態是rejected或者拋出異常,await表達式會吧promose的異常原因拋出,然后就不執行async function await之后的語句了
一、async
帶async關鍵字的函數,是聲明異步函數,返回值是promise對象,如果async關鍵字函數返回的不是promise,會自動用Promise.resolve()包裝。
async function test() {
return 'test'
}
test();
返回值為 Promise {<resolved>: "test"}。
二、await
await等待右側表達式的結果,這個結果是promise對象或者其他值。
如果它等到的不是一個 promise 對象,那 await 表達式的運算結果就是它等到的東西。
如果它等到的是一個 promise 對象,await 就忙起來了,它會阻塞后面的代碼,等着 promise 對象 resolve,然后得到 resolve 的值,作為 await 表達式的運算結果。
function test() {
return new Promise(resolve => {
setTimeout(() => resolve("test"), 2000);
});
}
const result = await test();
console.log(result);
console.log('end')
由於test()造成的阻塞,console.log('end')會等到兩秒后執行
所以為了避免造成阻塞,await 必須用在 async 函數中,async 函數調用不會造成阻塞。
function test() {
return new Promise(resolve => {
setTimeout(() => resolve("test"), 2000);
});
}
async function test2() {
const result = await test();
console.log(result);
}
test2();
console.log('end');
先執行console.log('end'),兩秒后執行console.log('test')
如果await用在普通函數中,會報錯,如下:

三、async/await的執行順序
遇到await會阻塞后面的代碼,先執行async外面的同步代碼,同步代碼執行完,再回到async內部,繼續執行await后面的代碼。以下面的代碼分析:
async function test1() {
console.log('start test1');
console.log(await test2());
console.log('end test1');
}
async function test2() {
console.log('test2');
return await 'return test2 value'
}
test1();
console.log('start async');
setTimeout(() => {
console.log('setTimeout');
}, 0);
new Promise((resolve, reject) => {
console.log('promise1');
resolve();
}).then(() => {
console.log('promise2');
});
console.log('end async');
執行的結果

· 首先執行宏任務,執行test1函數,執行console.log('statr test1')
· 遇到await,先執行右邊test2中的console.log('test2'),中斷了后面的代碼,執行test1外面的同步代碼
· 執行console.log('start async');
· 遇到setTimeout,推到到下個宏任務隊列中
· 執行Promise里面的同步代碼console.log('promise1')
· 運行到promise().then,發現是promise對象,推到微任務隊列中
· 執行console.log('end async')
· test1外面的同步代碼執行結束后,回到test1中,console.log(await test2())執行完成后返回Promise {<resolved>: "return test2 value"},是promise對象,推到微任務隊列中
· 此時第一個宏任務結束,執行所有的微任務,因為微任務隊列先進先出,所以先執行console.log('promise2'),后執行console.log('return test2 value')
· 執行test2完成后,后面的代碼不再阻塞,執行console.log('end test1');
· 執行下個宏任務,即執行console.log('setTimeout');
補充下有關宏任務和微任務的知識
宏任務和微任務都是隊列,宏任務有script、setTimeout、setInterval等,微任務有Promise.then catch finally、process.nextTick等,宏任務和微任務的關系如下:

先執行第一個宏任務,執行結束后,執行所有的微任務,然后執行下個宏任務。
四、async/await的優缺點
1. 優點
相對於promise,async/await處理 then 的調用鏈,代碼要清晰很多,幾乎和同步代碼一樣
2. 缺點
濫用 await 可能會導致性能問題,因為 await 會阻塞代碼
五、處理reject
1. try/catch
async function fn() {
try {
await new Promise((resolve, reject) => {
setTimeout(() => {
reject('err3');
}, 1000);
})
} catch (err){
alert(err)
}
}
fn()
2. catch
async function fn() {
await new Promise((resolve, reject) => {
setTimeout(() => {
reject('err');
}, 1000);
})
}
fn().catch(alert)
1、首先需要理解async 和 await的基本含義
async 是一個修飾符,async 定義的函數會默認的返回一個Promise對象resolve的值,因此對async函數可以直接進行then操作,返回的值即為then方法的傳入函數
// 0. async基礎用法測試
async function fun0() {
console.log(1)
return 1
}
fun0().then( x => { console.log(x) }) // 輸出結果 1, 1,
async function funa() {
console.log('a')
return 'a'
}
funa().then( x => { console.log(x) }) // 輸出結果a, a,
async function funo() {
console.log({})
return {}
}
funo().then( x => { console.log(x) }) // 輸出結果 {} {}
async function funp() {
console.log('Promise')
return new Promise(function(resolve, reject){
resolve('Promise')
})
}
funp().then( x => { console.log(x) }) // 輸出promise promise
await 也是一個修飾符,
await 關鍵字 只能放在 async 函數內部, await關鍵字的作用 就是獲取 Promise中返回的內容, 獲取的是Promise函數中resolve或者reject的值
// 如果await 后面並不是一個Promise的返回值,則會按照同步程序返回值處理
// await 關鍵字 只能放在 async 函數內部, await關鍵字的作用 就是獲取 Promise中返回的內容, 獲取的是Promise函數中resolve或者reject的值
// 如果await 后面並不是一個Promise的返回值,則會按照同步程序返回值處理,為undefined
const bbb = function(){ return 'string'}
async function funAsy() {
const a = await 1
const b = await new Promise((resolve, reject)=>{
setTimeout(function(){
resolve('time')
}, 3000)
})
const c = await bbb()
console.log(a, b, c)
}
funAsy() // 運行結果是 3秒鍾之后 ,輸出 1, time , string,
// 2.如果不使用promise的方法的話
function log2(time) {
setTimeout(function(){
console.log(time)
return 1
}, time)
}
async function fun1() {
const a = await log2(5000)
const b = await log2(10000)
const c = log2(2000)
console.log(a)
console.log(1)
}
fun1()
// 以上運行結果為: 立刻輸出undefined 立刻輸出1 2秒后輸出2000 5秒后輸出5000 10秒后輸出10000
2、那么由此看來async / await的綜合用法如下
// 1.定義一個或多個普通函數,函數必須返回Promise對象,如果返回其他類型的數據,將按照普通同步程序處理
function log(time) {
return new Promise((resolve, reject)=> {
setTimeout(function(){
console.log(time)
resolve()
}, time)
})
}
async function fun() {
await log(5000)
await log(10000)
log(1000)
console.log(1)
}
fun()
// 3. async / await的重要應用
const asy = function(x, time) {
return new Promise((resolve, reject) =>{
setTimeout(()=>{
resolve(x)
}, time)
})
}
const add = async function() {
const a = await asy(3, 5000)
console.log(a)
const b = await asy(4, 10000)
console.log(b)
const c = await asy(5, 15000)
console.log(a,b,c)
const d = a + b +c
console.log(d)
}
add();
// 5秒后輸出3 又10秒后輸出4 又15秒后輸出5 然后立刻輸出3,4,5,然后輸出12

