<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Async/Await 如何通過同步的方式實現(xiàn)異步?

          共 3992字,需瀏覽 8分鐘

           ·

          2021-06-13 04:58

          點擊上方 程序員成長指北,關注公眾號

          回復1,加入高級 Node 進階交流群

          ??  點擊上方卡片關注

          二、Async/Await 如何通過同步的方式實現(xiàn)異步?

          這個題目本身不是特別難,只能說是作為社招的基礎面試題,但是如果想回答好這道題并且驚艷面試官也不是很容易。

          不信接著往下看:

          1、概括的說

          一個函數(shù)如果加上 async ,那么該函數(shù)就會返回一個 Promise。

          await 只能在 async 函數(shù)中使用,可以把 async 看成將函數(shù)返回值使用 Promise.resolve() 包裹了下。

          async 和 await 相比直接使用 Promise 來說,優(yōu)勢在于處理 then 的調(diào)用鏈,能夠更清晰準確的寫出代碼。缺點在于濫用 await 可能會導致性能問題,因為 await 會阻塞代碼,也許之后的異步代碼并不依賴于前者,但仍然需要等待前者完成,導致代碼失去了并發(fā)性。

          我們來看一下代碼實例:

          1. async function test() {

          2. return "1";

          3. }

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

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

          1. function sleep() {

          2. return new Promise(resolve => {

          3. setTimeout(() => {

          4. console.log('finish')

          5. resolve("sleep");

          6. }, 2000);

          7. });

          8. }

          9. async function test() {

          10. let value = await sleep();

          11. console.log("object");

          12. }

          13. test()

          上面代碼會先打印 finish 然后再打印 object 。因為 await 會等待 sleep 函數(shù) resolve ,所以即使后面是同步代碼,也不會先去執(zhí)行同步代碼再來執(zhí)行異步代碼。

          2、亮點回答

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

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

          如果上面的沒執(zhí)行完,那就只能等著。

          還是舉個例子:

          1. function test() {

          2. let d = Date.now();

          3. for (let i = 0; i < 1e8; i++) {}

          4. console.log(Date.now() - d); // 62ms左右

          5. }

          6. function test1() {

          7. let d = Date.now();


          8. console.log(Date.now() - d); // 0

          9. }

          10. test();

          11. test1();

          上面僅僅是一個 for 循環(huán),而在實際應用中,會有大量的網(wǎng)絡請求,它的響應時間是不確定的,這種情況下也要等待嗎?

          顯然是不行的,因而 js 設計了異步,即 發(fā)起網(wǎng)絡請求(諸如 IO 操作,定時器),由于需要等服務器響應,就先不理會,而是去做其他的事兒,等請求返回了結果的時候再說(即異步)。

          那么如何實現(xiàn)異步呢?其實我們平時已經(jīng)在大量使用了,那就是 callback,實現(xiàn)異步的核心就是回調(diào)鉤子,將 cb 作為參數(shù)傳遞給異步執(zhí)行函數(shù),當有了結果后在觸發(fā) cb。想了解更多,可以去看看 event-loop 機制。

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

          async/await 是參照 Generator 封裝的一套異步處理方案,可以理解為 Generator 的語法糖,

          所以了解 async/await 就不得不講一講 Generator,以后我們可以講一下這個。

          而 Generator 又依賴于迭代器Iterator,以后我們可以講一下這個。

          終于找到源頭了:單向鏈表,以后可以講一下這個。

          可以看到,async function 代替了 function*,await 代替了 yield,同時也無需自己手寫一個自動執(zhí)行器 run 了

          現(xiàn)在再來看看async/await 的特點:

          • 當 await 后面跟的是 Promise 對象時,才會異步執(zhí)行,其它類型的數(shù)據(jù)會同步執(zhí)行

          • 返回的仍然是個 Promise 對象,上面代碼中的 return 'done'; 會直接被下面 then 函數(shù)接收到

          3、進階回答

          async/await 是參照 Generator 封裝的一套異步處理方案,可以理解為 Generator 的語法糖,

          所以了解 async/await 就不得不講一講 Generator,

          而 Generator 又依賴于迭代器Iterator,

          所以就得先講一講 Iterator,

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

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

          3.1 什么是單向鏈表?

          我們看一下wiki的說明:鏈表(Linked list)是一種常見的基礎數(shù)據(jù)結構,是一種線性表,但是并不會按線性的順序儲存數(shù)據(jù),而是在每一個節(jié)點里存到下一個節(jié)點的指針(Pointer)。由于不必須按順序儲存,鏈表在插入的時候可以達到 o(1)的復雜度,比另一種線性表順序表快得多,但是查找一個節(jié)點或者訪問特定編號的節(jié)點則需要 o(n)的時間,而順序表響應的時間復雜度分別是 o(logn)和 o(1)。

          總結一下鏈表優(yōu)點:

          • 無需預先分配內(nèi)存

          • 插入/刪除節(jié)點不影響其他節(jié)點,效率高(典型的例子:git commit)

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

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

          單鏈特點:節(jié)點的鏈接方向是單向的;相對于數(shù)組來說,單鏈表的的隨機訪問速度較慢,但是單鏈表刪除/添加數(shù)據(jù)的效率很高。

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

          3.2 Iterator

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

          • 創(chuàng)建一個指針對象,指向當前數(shù)據(jù)結構的起始位置:

          • 第一次調(diào)用指針對象的 next 方法,將指針指向數(shù)據(jù)結構的第一個成員

          • 第二次調(diào)用指針對象的 next 方法,將指針指向數(shù)據(jù)結構的第二個成員

          • 不斷的調(diào)用指針對象的 next 方法,直到它指向數(shù)據(jù)結構的結束位置

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

          當一個對象需要被迭代的時候(比如開始用于一個 for..of 循環(huán)中),它的 @@iterator 方法被調(diào)用并且無參數(shù),然后返回一個用于在迭代中獲得值的迭代器

          3.3 Generator

          Generator:生成器對象是生成器函數(shù)(GeneratorFunction)返回的,它符合可迭代協(xié)議和迭代器協(xié)議,既是迭代器也是可迭代對象,可以調(diào)用 next 方法,但它不是函數(shù),更不是構造函數(shù).

          調(diào)用一個生成器函數(shù)并不會馬上執(zhí)行它里面的語句,而是返回一個這個生成器的迭代器對象,當這個迭代器的 next() 方法被首次(后續(xù))調(diào)用時,其內(nèi)的語句會執(zhí)行到第一個(后續(xù))出現(xiàn) yield 的位置為止(讓執(zhí)行處于暫停狀),yield 后緊跟迭代器要返回的值。或者如果用的是 yield*(多了個星號),則表示將執(zhí)行權移交給另一個生成器函數(shù)(當前生成器暫停執(zhí)行),調(diào)用 next() (再啟動)方法時,如果傳入了參數(shù),那么這個參數(shù)會作為上一條執(zhí)行的 yield 語句的返回值,

          我們來總結一下 Generator 的本質(zhì),暫停,它會讓程序執(zhí)行到指定位置先暫停(yield),然后再啟動(next),再暫停(yield),再啟動(next),而這個暫停就很容易讓它和異步操作產(chǎn)生聯(lián)系,因為我們在處理異步時:開始異步處理(網(wǎng)絡求情、IO 操作),然后暫停一下,等處理完了,再該干嘛干嘛。不過值得注意的是,js 是單線程的(又重復了三遍),異步還是異步,callback 還是 callback,不會因為 Generator 而有任何改變。

          3.4 Async/Await

          async/await 是 Generator 的語法糖,就是一個自執(zhí)行的generate函數(shù)。利用generate函數(shù)的特性把異步的代碼寫成“同步”的形式。

          覺得這樣是不是可以清晰點了。

          Reference

          • https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Iteration_protocols#%E5%8F%AF%E8%BF%AD%E4%BB%A3%E5%8D%8F%E8%AE%AE

          • http://es6.ruanyifeng.com/#docs/iterator

          • http://es6.ruanyifeng.com/#docs/async


          如果覺得這篇文章還不錯
          點擊下面卡片關注我
          來個【分享、點贊、在看】三連支持一下吧

             “分享、點贊在看” 支持一波 

          瀏覽 83
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中文字幕在线免费看 | 天天搞天天搞 | 日韩乱码一区二区 | 免费操逼视频无删减 | 大香蕉在线看 |