欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

總結(jié)5種JavaScript異步解決方案

 更新時(shí)間:2023年04月10日 10:29:34   作者:技術(shù)小張zz  
這篇文章主要講解了JavaScript異步解決處理方案,文章中有詳細(xì)的解決方案和代碼示例,需要的朋友參考一下

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 instance
const 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ì)阻塞代碼。

到此這篇關(guān)于總結(jié)5種JavaScript異步解決方案的文章就介紹到這了,更多相關(guān)解決JavaScript異步內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論