<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>

          【基礎(chǔ)復(fù)盤】總結(jié)5種JavaScript異步解決方案

          共 4459字,需瀏覽 9分鐘

           ·

          2023-03-11 10:49

          大廠技術(shù)  高級(jí)前端  Node進(jìn)階

          點(diǎn)擊上方 程序員成長(zhǎng)指北,關(guān)注公眾號(hào)

          回復(fù)1,加入高級(jí)Node交流群

          英文 | https://javascript.plainenglish.io/summarizing-several-javascript-async-solutions-dd4a0fe2a99c


          1.回調(diào)

          回調(diào)簡(jiǎn)單地理解為一個(gè)函數(shù)作為參數(shù)傳遞給另一個(gè)函數(shù),回調(diào)是早期最常用的異步解決方案之一。

          回調(diào)不一定是異步的,也不直接相關(guān)。

          舉個(gè)簡(jiǎn)單的例子:

          function f1(cb) {  setTimeout(() => {    cb && cb();  }, 2000);}
          f1(() => { console.log("1");});

          如上,我們?cè)诤瘮?shù)f1中使用setTimeout模擬一個(gè)耗時(shí)2s的任務(wù),在耗時(shí)任務(wù)結(jié)束時(shí)拋出回調(diào),這樣我們就可以調(diào)用它,讓回調(diào)函數(shù)在耗時(shí)結(jié)束時(shí)執(zhí)行函數(shù) f1 中的任務(wù)。

          這樣,我們就把同步操作變成了異步操作。f1不會(huì)阻塞程序,相當(dāng)于先執(zhí)行程序的主要邏輯,推遲執(zhí)行耗時(shí)操作。

          回調(diào)的優(yōu)點(diǎn)和缺點(diǎn)

          優(yōu)點(diǎn):簡(jiǎn)單,容易理解。

          缺點(diǎn):代碼不優(yōu)雅,可讀性差,不易維護(hù),耦合度高,層層嵌套造成回調(diào)地獄。

          2.事件監(jiān)聽(發(fā)布訂閱模式)

          發(fā)布-訂閱模式定義了對(duì)象之間一對(duì)多的依賴關(guān)系,這樣當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生變化時(shí),所有依賴它的對(duì)象都會(huì)得到通知。

          我們都使用過發(fā)布-訂閱模式,例如,如果我們將事件函數(shù)綁定到 DOM 節(jié)點(diǎn)。

          document.body.addEventListener('click', function () {  console.log('click');})

          但這只是發(fā)布-訂閱模式最簡(jiǎn)單的使用,在很多場(chǎng)景下我們往往會(huì)使用一些自定義事件來滿足我們的需求。

          有很多方法可以實(shí)現(xiàn)發(fā)布-訂閱模式,所以這里有一個(gè)使用類的簡(jiǎn)單實(shí)現(xiàn)。

          class Emitter {  constructor() {    // _listener array, key is the custom event name, value is the execution callback array - as there may be more than one    this._listener = []  }
          // 訂閱 監(jiān)聽事件 on(type, fn) { // Determine if the event exists in the _listener array. // Exists to push the callback to the value array corresponding to the event name, does not exist to add directly this._listener[type] ? this._listener[type].push(fn) : (this._listener[type] = [fn]) }
          // Publish Trigger Event trigger(type, ...rest) { // Determine if the trigger event exists if (!this._listener[type]) return // Iterate through the array of callbacks executing the event and pass the parameters this._listener[type].forEach(callback => callback(...rest)) }}

          如上所示,我們創(chuàng)建了一個(gè) Emitter 類,并在和觸發(fā)器上添加了兩個(gè)原型方法,使用如下。

          // Create an emitter instanceconst emitter = new Emitter()
          emitter.on("done", function(arg1, arg2) { console.log(arg1, arg2)})
          emitter.on("done", function(arg1, arg2) { console.log(arg2, arg1)})
          function fn1() { console.log('I am the main program') setTimeout(() => { emitter.trigger("done", "Asynchronous parameter I", "Asynchronous parameter II") }, 1000)}
          fn1()

          我們先創(chuàng)建一個(gè)emitter實(shí)例,然后注冊(cè)事件,然后觸發(fā)事件,這樣也解決了異步問題。

          事件監(jiān)聽的優(yōu)點(diǎn)和缺點(diǎn)

          優(yōu)點(diǎn):更符合模塊化思想,我們?cè)诰帉懽约旱谋O(jiān)聽器的時(shí)候可以做很多優(yōu)化,從而更好的監(jiān)聽程序的運(yùn)行。

          缺點(diǎn):整個(gè)程序變成了事件驅(qū)動(dòng),或多或少影響了流程,而且每次使用都要注冊(cè)事件監(jiān)聽器然后觸發(fā),比較麻煩,代碼也不是很優(yōu)雅。

          3.Promise

          ES6 標(biāo)準(zhǔn)化并引入了 Promise 對(duì)象,這是一種異步編程的解決方案。

          簡(jiǎn)單的說,就是用同步的方式寫異步代碼,可以用來解決回調(diào)地獄問題。

          Promise對(duì)象的狀態(tài)一旦改變,就不會(huì)再改變,只有兩種可能的改變。

          1. 由待定改為已解決。

          2. 由Pending改為Rejected。

          我們使用 setTimeout 來模擬異步操作。

          function analogAsync(n) {  return new Promise((resolve) => {    setTimeout(() => resolve(n + 500), n);  });}
          function fn1(n) { console.log(`step1 with ${n}`); return analogAsync(n);}
          function fn2(n) { console.log(`step2 with ${n}`); return analogAsync(n);}
          function fn3(n) { console.log(`step3 with ${n}`); return analogAsync(n);}

          使用 Promise 來實(shí)現(xiàn)。

          function fn() {  let time1 = 0;  fn1(time1)    .then((time2) => fn2(time2))    .then((time3) => fn3(time3))    .then((res) => {      console.log(`result is ${res}`);    });}
          fn();

          Promise 優(yōu)點(diǎn)和缺點(diǎn)

          優(yōu)點(diǎn):Promise以同步的方式編寫異步代碼,避免了回調(diào)函數(shù)層層嵌套,可讀性更強(qiáng)。鏈?zhǔn)讲僮?,可以在then中繼續(xù)寫Promise對(duì)象并return,然后繼續(xù)調(diào)用then進(jìn)行回調(diào)操作。

          缺點(diǎn):Promise對(duì)象一旦創(chuàng)建就會(huì)立即執(zhí)行,不能中途取消。如果沒有設(shè)置回調(diào)函數(shù),Promise 會(huì)在內(nèi)部拋出錯(cuò)誤,不會(huì)向外流。

          4.Generator

          Generator其實(shí)就是一個(gè)函數(shù),只不過是一個(gè)特殊的函數(shù)。Generator 的特別之處在于它可以中途停止。

          function *generatorFn() {  console.log("a");  yield '1';  console.log("b");  yield '2';   console.log("c");  return '3';}
          let it = generatorFn();it.next();it.next();it.next();it.next();

          上面的示例是一個(gè)具有以下特征的生成器函數(shù)。與普通函數(shù)不同,Generator 函數(shù)在函數(shù)之后和函數(shù)名稱之前有一個(gè) *,該函數(shù)有一個(gè)內(nèi)部 yield 字段,函數(shù)調(diào)用后的返回值使用next方法。

          Generator的優(yōu)點(diǎn)和缺點(diǎn)

          優(yōu)點(diǎn):優(yōu)雅的流程控制方法,允許函數(shù)被中斷地執(zhí)行。

          缺點(diǎn):Generator函數(shù)的執(zhí)行必須依賴executor,對(duì)于只做異步處理還是不太方便。

          5.async/await 

          ES2017標(biāo)準(zhǔn)引入了async函數(shù),使得異步操作更加方便。async是異步的意思,await是async wait的簡(jiǎn)寫,也就是異步等待。async/await 被許多人認(rèn)為是 js 中異步操作的終極和最優(yōu)雅的解決方案。

          異步在做什么?

          async 函數(shù)返回一個(gè) Promise 對(duì)象。如果直接在 async 函數(shù)中返回一個(gè)直接量,async 會(huì)通過 Promise.resolve() 將直接量包裝在一個(gè) Promise 對(duì)象中。

          await 是什么?

          await 是一個(gè)表達(dá)式,其計(jì)算結(jié)果為 Promise 對(duì)象或其他值(換句話說,沒有特殊限定,無論如何)。

          如果 await 后面沒有跟 Promise 對(duì)象,則直接執(zhí)行。

          如果 await 后面跟著一個(gè) Promise 對(duì)象,它會(huì)阻塞后面的代碼,Promise 對(duì)象解析,然后獲取 resolve 的值作為 await 表達(dá)式的結(jié)果。

          await 只能在異步函數(shù)中使用

          上面使用setTimeout來模擬異步操作,我們使用async/await來實(shí)現(xiàn)。

          async function fn() {  let time1 = 0;  let time2 = await fn1(time1);  let time3 = await fn2(time2);  let res = await fn3(time3);  console.log(`result is ${res}`);}
          fn();

          輸出結(jié)果和上面的 Promise 實(shí)現(xiàn)是一樣的,但是 async/await 的代碼結(jié)構(gòu)看起來更清晰,幾乎和同步寫法一樣優(yōu)雅。

          async/await的優(yōu)點(diǎn)和缺點(diǎn)

          優(yōu)點(diǎn):內(nèi)置執(zhí)行器,語義更好,適用性更廣。

          缺點(diǎn):誤用 await 可能會(huì)導(dǎo)致性能問題,因?yàn)?await 會(huì)阻塞代碼。

          總結(jié)

          在今天這篇文章,我跟大家分享了5種JavaScript異步解決方案,希望這些內(nèi)容對(duì)你有所幫助。

          最后,感謝你的閱讀。

          Node 社群


          我組建了一個(gè)氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對(duì)Node.js學(xué)習(xí)感興趣的話(后續(xù)有計(jì)劃也可以),我們可以一起進(jìn)行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。

             “分享、點(diǎn)贊在看” 支持一波??

          瀏覽 31
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  2024国产中文一区二区在线播放 | 大香蕉伊人在线手机版 | 狠狠撸天天撸日日撸无码 | 国产精品人人妻人人爽人人牛 | 免费看黄色电影 |