async function(面試小難點?)

async function

:用來定義一個返回 AsyncFunction 對象的異步函數。異步函數是指經過事件循環異步執行的函數,它會經過一個隱式的 Promise 返回其結果。若是你在代碼中使用了異步函數,就會發現它的語法和結構會更像是標準的同步函數。promise

  • 你還可使用 異步函數表達式 來定義異步函數。
function resolveAfter2Seconds() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('resolved');
    }, 2000);
  });
}

async function asyncCall() {
  console.log('calling');
  var result = await resolveAfter2Seconds();
  console.log(result);
  // expected output: 'resolved'
}

asyncCall();

複製代碼

async function 語法:

async function name([param[, param[, ... param]]]) { statements }bash

參數

  • name 函數名稱。
  • param 要傳遞給函數的參數。
  • statements 函數體語句。

返回值

返回的Promise對象會運行執行(resolve)異步函數的返回結果,或者運行拒絕(reject)——若是異步函數拋出異常的話。異步

描述

異步函數能夠包含await指令,該指令會暫停異步函數的執行,並等待Promise執行,
  而後繼續執行異步函數,並返回結果。
複製代碼
  • 記住,await 關鍵字只在異步函數內有效。若是你在異步函數外使用它,會拋出語法錯誤。

注意,當異步函數暫停時,它調用的函數會繼續執行(收到異步函數返回的隱式Promise)async

  • async/await的目的是簡化使用多個 promise 時的同步行爲,並對一組 Promises執行某些操做。正如Promises相似於結構化回調,async/await更像結合了generators和 promises。

示例

var resolveAfter2Seconds = function() {
  console.log("starting slow promise");
  return new Promise(resolve => {
    setTimeout(function() {
      resolve("slow");
      console.log("slow promise is done");
    }, 2000);
  });
};

var resolveAfter1Second = function() {
  console.log("starting fast promise");
  return new Promise(resolve => {
    setTimeout(function() {
      resolve("fast");
      console.log("fast promise is done");
    }, 1000);
  });
};

var sequentialStart = async function() {
  console.log('==SEQUENTIAL START==');

  // 1. Execution gets here almost instantly
  const slow = await resolveAfter2Seconds();
  console.log(slow); // 2. this runs 2 seconds after 1.

  const fast = await resolveAfter1Second();
  console.log(fast); // 3. this runs 3 seconds after 1.
}

var concurrentStart = async function() {
  console.log('==CONCURRENT START with await==');
  const slow = resolveAfter2Seconds(); // starts timer immediately
  const fast = resolveAfter1Second(); // starts timer immediately

  // 1. Execution gets here almost instantly
  console.log(await slow); // 2. this runs 2 seconds after 1.
  console.log(await fast); // 3. this runs 2 seconds after 1., immediately after 2., since fast is already resolved
}

var concurrentPromise = function() {
  console.log('==CONCURRENT START with Promise.all==');
  return Promise.all([resolveAfter2Seconds(), resolveAfter1Second()]).then((messages) => {
    console.log(messages[0]); // slow
    console.log(messages[1]); // fast
  });
}

var parallel = async function() {
  console.log('==PARALLEL with await Promise.all==');
  
  // Start 2 "jobs" in parallel and wait for both of them to complete
  await Promise.all([
      (async()=>console.log(await resolveAfter2Seconds()))(),
      (async()=>console.log(await resolveAfter1Second()))()
  ]);
}

// This function does not handle errors. See warning below!
var parallelPromise = function() {
  console.log('==PARALLEL with Promise.then==');
  resolveAfter2Seconds().then((message)=>console.log(message));
  resolveAfter1Second().then((message)=>console.log(message));
}

sequentialStart(); // after 2 seconds, logs "slow", then after 1 more second, "fast"

// wait above to finish
setTimeout(concurrentStart, 4000); // after 2 seconds, logs "slow" and then "fast"

// wait again
setTimeout(concurrentPromise, 7000); // same as concurrentStart

// wait again
setTimeout(parallel, 10000); // truly parallel: after 1 second, logs "fast", then after 1 more second, "slow"

// wait again
setTimeout(parallelPromise, 13000); // same as parallel
複製代碼

await and parallelism(並行)

  • 在sequentialStart中,程序在第一個await停留了2秒,而後又在第二個await停留了1秒。直到第一個計時器結束後,第二個計時器才被建立。程序須要3秒執行完畢。函數

  • 在 concurrentStart中,兩個計時器被同時建立,而後執行await。這兩個計時器同時運行,這意味着程序完成運行只須要2秒,而不是3秒,即最慢的計時器的時間。ui

  • 可是 await 仍舊是順序執行的,第二個 await 仍是得等待第一個執行完。在這個例子中,這使得先運行結束的輸出出如今最慢的輸出以後。this

  • 若是你但願並行執行兩個或更多的任務,你必須像在parallel中同樣使用await Promise.all([job1(), job2()])。url

async/await和Promise#then對比以及錯誤處理

  • 大多數異步函數也可使用Promises編寫。可是,在錯誤處理方面,async函數更容易捕獲異常錯誤spa

  • 上面例子中的concurrentStart函數和concurrentPromise函數在功能上都是等效的。在concurrentStart函數中,若是任一awaited調用失敗,它將自動捕獲異常,異步函數執行中斷,並經過隱式返回Promise將錯誤傳遞給調用者。code

  • 在Promise例子中這種狀況一樣會發生,該函數必須負責返回一個捕獲函數完成的Promise。在concurrentPromise函數中,這意味着它從Promise.all([]).then()返回一個Promise。事實上,在此示例的先前版本忘記了這樣作!

  • 可是,async函數仍有可能然可能錯誤地忽略錯誤。

  • 以parallel異步函數爲例。若是它沒有等待await(或返回)Promise.all([])調用的結果,則不會傳播任何錯誤。雖然parallelPromise函數示例看起來很簡單,但它根本不會處理錯誤! 這樣作須要一個相似於return Promise.all([])處理方式。

使用async函數重寫 promise 鏈

  • 返回 Promise的 API 將會產生一個 promise 鏈,它將函數肢解成許多部分。例以下面的代碼:
function getProcessedData(url) {
  return downloadData(url) // 返回一個 promise 對象
    .catch(e => {
      return downloadFallbackData(url)  // 返回一個 promise 對象
    })
    .then(v => {
      return processDataInWorker(v); // 返回一個 promise 對象
    });
}
複製代碼
  • 能夠重寫爲單個async函數:
async function getProcessedData(url) {
  let v;
  try {
    v = await downloadData(url); 
  } catch (e) {
    v = await downloadFallbackData(url);
  }
  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),若是是拒絕,將會在返回前拋出異常。

參考文檔:developer.mozilla.org/zh-CN/docs/…

標題黨?????

歡迎投稿 歡迎吐槽 感謝支持 ღ( ´・ᴗ・` )比心

相關文章
相關標籤/搜索