面試題 async/await

async 

async 函數是 Generator 函數的語法糖。使用 關鍵字 async 來表示,在函數內部使用await 代表當前函數是異步函數 不會阻塞線程致使後續代碼中止運行。
async function name([param[, param[, ... param]]]) { statements }複製代碼

async 函數的返回值很特殊: 無論在函數體內 return 了什麼值, async 函數的實際返回值老是一個 Promise 對象. javascript

詳細講就是:若在 async 函數中 return 了一個值 a, 無論 a 值是什麼類型, async 函數的實際返回值老是 Promise.resolve(a)
java

async function asyncFn() {
    return 'hello world';
}
console.log(asyncFn())
//Promise {<resolved>: "hello world"}複製代碼


由上可知 返回的是一個Promise對象ios

async function asyncFn() {
    return 'hello world';
}
asyncFn()
    .then(res => {
        console.log(res)
        //hello world
    })複製代碼
若是函數內部拋出異常或者是返回reject,都會使函數的promise狀態爲失敗reject。
async function asyncFn() {
    throw new Error('has Error');
}
asyncFn()
    .then(res => {
        console.log(res);
    })
    .catch(error => {
        console.log(error);
    })複製代碼


await

await意思是async wait(異步等待)。這個關鍵字只能在使用async定義的函數裏面使用。任何async函數都會默認返回promise,而且這個promise解析的值都將會是這個函數的返回值,而async函數必須等到內部全部的 await 命令的 Promise 對象執行完,纔會發生狀態改變


async function getJsonAsync() {
    let result = await axios.get('api/user');
    return result
}
getJsonAsync()
    .then(function (res) {
        console.log(res.data)
    })
    .catch(function (error) {
        console.log(error)
    })複製代碼

執行順序解讀

console.log(1);
async function asyncfn1(){
    console.log(2);
    await asyncfn2();
    console.log(3);
};
setTimeout(() => {
    console.log('setTimeout')
}, 0)

async function asyncfn2(){
    console.log(4)
};

asyncfn1();
console.log(5);複製代碼


分析:axios

  1. 打印 "1" 
  2. 遇到setTimeout,setTimeout是宏任務,將它放在宏任務隊列中 執行 asyncfn1 打印 "2"
  3. 遇到await關鍵字,先執行關鍵字後面的 asyncfn2函數 打印:"4",由於await關鍵字將這塊代碼asyncContext掛起並執行上級 上下文 因此先打印了"5",執行完後回到 async context 打印 "3"  
  4. 最後打印 "setTimeout"


加入Promiseapi

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')複製代碼


重點:promise

  1. 執行到 await async2(),發現 async2 也是個 async 定義的函數,因此直接執行了「console.log('async2')」,同時async2返回了一個Promise,劃重點:此時返回的Promise會被放入到回調隊列中等待,await會讓出線程(js是單線程還用我介紹嗎),接下來就會跳出 async1函數 繼續往下執行。
  2. 而後執行到 new Promise,前面說過了promise是當即執行的,因此先打印出來「promise1」,而後執行到 resolve 的時候,resolve這個任務就被放到回調隊列中等待,而後跳出Promise繼續往下執行,輸出「script end」。 
  3. 同步的事件都循環執行完了,調用棧如今已經空出來了,那麼事件循環就會去回調隊列裏面取任務繼續放到調用棧裏面了。

總結:bash

優先級: promise.Trick()>promise的回調>setTimeout>setImmediate


async/await 能代替Promise嗎

使用Async / Await時,咱們仍在使用Promise。從長遠來看,對Promise的良好理解實際上對您有很大的好處。 甚至有一些用例Async / Await並不能解決問題,咱們不得不回到Promise上 一個這樣的場景


const timeoutFn = function(value,timeout){
    return new Promise(function(resolve){
        return setTimeout(()=>{resolve(value)},timeout);
    });
}

async function getABC() {
    let A = await timeoutFn(2,2000); // 2 second to finish
    let B = await timeoutFn(2,2000); // 4 second to finish
    let C = await timeoutFn(3,3000); // 3 second to finish
    return A*B*C;
}
getABC()
    .then((res)=>{
        console.log(res)
        //12
    })複製代碼

上述7秒以後輸出12,由於三個變量A,B和C不相互依賴,每一個調用將等待前一個返回結果異步

Promise.all()。這將容許咱們同時發送全部請求。,但異步調用將並行觸發,而不是一個接一個地觸發,3秒以後返回借過12
async

const timeoutFn = function(value,timeout){
    return new Promise(function(resolve){
        return setTimeout(()=>{resolve(value)},timeout);
    });
}

async function getABC() {
    // Promise.all()容許咱們同時發送全部請求。
    let results = await Promise.all([ timeoutFn(2,2000), timeoutFn(2,2000), timeoutFn(3,3000) ]);
    return results.reduce((total,value) => total * value);
}
getABC()
    .then(res => {
        console.log(res)
        //12
    })複製代碼
相關文章
相關標籤/搜索