[每日一題]面試官問:Async/Await 如何經過同步的方式實現異步?

關注「鬆寶寫代碼」,精選好文,每日一題vue

​時間永遠是本身的git

每分每秒也都是爲本身的未來鋪墊和增值es6

做者:saucxs | songEagle

1、前言

2020.12.23 日剛立的 flag,每日一題,題目類型不限制,能夠是:算法題,面試題,闡述題等等。面試

本文是「每日一題」第 6 題:面試官問:Async/Await 如何經過同步的方式實現異步?算法

每日一題

往期「每日一題」:數組

2、Async/Await 如何經過同步的方式實現異步?

這個題目自己不是特別難,只能說是做爲社招的基礎面試題,可是若是想回答好這道題也不是很容易。瀏覽器

不信接着往下看:服務器

一、歸納的說

一個函數若是加上 async ,那麼該函數就會返回一個 Promise。網絡

await 只能在 async 函數中使用,能夠把 async 當作將函數返回值使用 Promise.resolve() 包裹了下。數據結構

async 和 await 相比直接使用 Promise 來講,優點在於處理 then 的調用鏈,可以更清晰準確的寫出代碼。缺點在於濫用 await 可能會致使性能問題,由於 await 會阻塞代碼,也許以後的異步代碼並不依賴於前者,但仍然須要等待前者完成,致使代碼失去了併發性。

咱們來看一下代碼實例:

async function test() {
  return "1";
}
console.log(test()); // -> Promise {<resolved>: "1"}

咱們再來看一下這個實例:

function sleep() {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log('finish')
      resolve("sleep");
    }, 2000);
  });
}
async function test() {
  let value = await sleep();
  console.log("object");
}
test()

上面代碼會先打印 finish 而後再打印 object 。由於 await 會等待 sleep 函數 resolve ,因此即便後面是同步代碼,也不會先去執行同步代碼再來執行異步代碼。

二、亮點回答

首先,js 是單線程的(重複三遍),所謂單線程,

意思就是說:執行代碼是一行一行的往下走(即所謂的同步),

若是上面的沒執行完,那就只能等着。

仍是舉個例子:

function test() {
  let d = Date.now();
  for (let i = 0; i < 1e8; i++) {}
  console.log(Date.now() - d); // 62ms左右
}
function test1() {
  let d = Date.now();

  console.log(Date.now() - d); // 0
}
test();
test1();

上面僅僅是一個 for 循環,而在實際應用中,會有大量的網絡請求,它的響應時間是不肯定的,這種狀況下也要等待嗎?

顯然是不行的,於是 js 設計了異步,即 發起網絡請求(諸如 IO 操做,定時器),因爲須要等服務器響應,就先不理會,而是去作其餘的事兒,等請求返回告終果的時候再說(即異步)。

那麼如何實現異步呢?其實咱們平時已經在大量使用了,那就是 callback,實現異步的核心就是回調鉤子,將 cb 做爲參數傳遞給異步執行函數,當有告終果後在觸發 cb。想了解更多,能夠去看看 event-loop 機制。

以前這種函數嵌套,大量的回調函數,使代碼閱讀起來晦澀難懂,不直觀,形象的稱之爲回調地獄(callback hell),因此爲了在寫法上能更通俗一點,es6+陸續出現了 Promise、Generator、Async/await,力求在寫法上簡潔明瞭,可讀性強。

async/await 是參照 Generator 封裝的一套異步處理方案,能夠理解爲 Generator 的語法糖,

因此瞭解 async/await 就不得不講一講 Generator,之後咱們能夠講一下這個。

而 Generator 又依賴於迭代器Iterator,之後咱們能夠講一下這個。

終於找到源頭了:單向鏈表,之後能夠講一下這個。

能夠看到,async function 代替了 function*,await 代替了 yield,同時也無需本身手寫一個自動執行器 run 了

如今再來看看async/await 的特色:

  • 當 await 後面跟的是 Promise 對象時,纔會異步執行,其它類型的數據會同步執行
  • 返回的仍然是個 Promise 對象,上面代碼中的 return 'done'; 會直接被下面 then 函數接收到

三、進階回答

async/await 是參照 Generator 封裝的一套異步處理方案,能夠理解爲 Generator 的語法糖,

因此瞭解 async/await 就不得不講一講 Generator,

而 Generator 又依賴於迭代器Iterator,

因此就得先講一講 Iterator,

而 Iterator 的思想呢又來源於單向鏈表,

終於找到源頭了:單向鏈表

3.1 什麼是單向鏈表?

咱們看一下wiki的說明:鏈表(Linked list)是一種常見的基礎數據結構,是一種線性表,可是並不會按線性的順序儲存數據,而是在每個節點裏存到下一個節點的指針(Pointer)。因爲沒必要須按順序儲存,鏈表在插入的時候能夠達到 o(1)的複雜度,比另外一種線性表順序錶快得多,可是查找一個節點或者訪問特定編號的節點則須要 o(n)的時間,而順序表響應的時間複雜度分別是 o(logn)和 o(1)。

總結一下鏈表優勢:

  • 無需預先分配內存
  • 插入/刪除節點不影響其餘節點,效率高(典型的例子:git commit)

單向鏈表:是鏈表中最簡單的一種,它包含兩個域,一個信息域和一個指針域。這個連接指向列表中的下一個節點,而最後一個節點則指向一個空值。

lianbiao

一個單向鏈表包含兩個值: 當前節點的值和一個指向下一個節點的連接

單鏈特色:節點的連接方向是單向的;相對於數組來講,單鏈表的的隨機訪問速度較慢,可是單鏈表刪除/添加數據的效率很高。

理解 js 原型鏈/做用域鏈的話,理解這個很容易,他們是相通的。

3.2 Iterator

Iterator 翻譯過來就是迭代器(遍歷器)讓咱們先來看看它的遍歷過程(相似於單向鏈表):

  • 建立一個指針對象,指向當前數據結構的起始位置:
  • 第一次調用指針對象的 next 方法,將指針指向數據結構的第一個成員
  • 第二次調用指針對象的 next 方法,將指針指向數據結構的第二個成員
  • 不斷的調用指針對象的 next 方法,直到它指向數據結構的結束位置

一個對象要變成可迭代的,必須實現 @@iterator 方法,即對象(或它原型鏈上的某個對象)必須有一個名字是 Symbol.iterator 的屬性(原生具備該屬性的有:字符串、數組、類數組的對象、Set 和 Map):

當一個對象須要被迭代的時候(好比開始用於一個 for..of 循環中),它的 @@iterator 方法被調用而且無參數,而後返回一個用於在迭代中得到值的迭代器

3.3 Generator

Generator:生成器對象是生成器函數(GeneratorFunction)返回的,它符合可迭代協議和迭代器協議,既是迭代器也是可迭代對象,能夠調用 next 方法,但它不是函數,更不是構造函數.

調用一個生成器函數並不會立刻執行它裏面的語句,而是返回一個這個生成器的迭代器對象,當這個迭代器的 next() 方法被首次(後續)調用時,其內的語句會執行到第一個(後續)出現 yield 的位置爲止(讓執行處於暫停狀),yield 後緊跟迭代器要返回的值。或者若是用的是 yield*(多了個星號),則表示將執行權移交給另外一個生成器函數(當前生成器暫停執行),調用 next() (再啓動)方法時,若是傳入了參數,那麼這個參數會做爲上一條執行的 yield 語句的返回值,

咱們來總結一下 Generator 的本質,暫停,它會讓程序執行到指定位置先暫停(yield),而後再啓動(next),再暫停(yield),再啓動(next),而這個暫停就很容易讓它和異步操做產生聯繫,由於咱們在處理異步時:開始異步處理(網絡求情、IO 操做),而後暫停一下,等處理完了,再該幹嗎幹嗎。不過值得注意的是,js 是單線程的(又重複了三遍),異步仍是異步,callback 仍是 callback,不會由於 Generator 而有任何改變。

3.4 Async/Await

async/await 是 Generator 的語法糖,就是一個自執行的generate函數。利用generate函數的特性把異步的代碼寫成「同步」的形式。

以爲這樣是否是能夠清晰點了。

Reference

各類福利

一、字節內推福利

回覆「校招」獲取內推碼

回覆「社招」獲取內推

回覆「實習生」獲取內推

後續會有更多福利

二、學習資料福利

回覆「算法」獲取算法學習資料

三、每日一題

謝謝支持

鬆寶寫代碼

一、喜歡的話能夠「分享,點贊,在看」三連哦。

二、做者暱稱:saucxs,songEagle,鬆寶寫代碼。「鬆寶寫代碼」公衆號做者,每日一題,實驗室等。一個愛好折騰,致力於全棧,正在努力成長的字節跳動工程師,星辰大海,將來可期。內推字節跳動各個部門各個崗位。

三、長按下面圖片,關注「鬆寶寫代碼」,是獲取開發知識體系構建,精選文章,項目實戰,實驗室,每日一道面試題,進階學習,思考職業發展,涉及到JavaScript,Node,Vue,React,瀏覽器,http等領域,但願能夠幫助到你,咱們一塊兒成長~

相關文章
相關標籤/搜索