溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript異步解決方案有哪些

發(fā)布時間:2023-05-06 09:46:37 來源:億速云 閱讀:130 作者:iii 欄目:開發(fā)技術

這篇文章主要介紹“JavaScript異步解決方案有哪些”,在日常操作中,相信很多人在JavaScript異步解決方案有哪些問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”JavaScript異步解決方案有哪些”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

1.回調

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

回調不一定是異步的,也不直接相關。

舉個簡單的例子:

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

如上,我們在函數(shù)f1中使用setTimeout模擬一個耗時2s的任務,在耗時任務結束時拋出回調,這樣我們就可以調用它,讓回調函數(shù)在耗時結束時執(zhí)行函數(shù) f1 中的任務。

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

回調的優(yōu)點和缺點

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

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

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

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

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

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

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

有很多方法可以實現(xiàn)發(fā)布-訂閱模式,所以這里有一個使用類的簡單實現(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)建了一個 Emitter 類,并在和觸發(fā)器上添加了兩個原型方法,使用如下。

// 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)建一個emitter實例,然后注冊事件,然后觸發(fā)事件,這樣也解決了異步問題。

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

優(yōu)點:更符合模塊化思想,我們在編寫自己的監(jiān)聽器的時候可以做很多優(yōu)化,從而更好的監(jiān)聽程序的運行。

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

3.Promise

ES6 標準化并引入了 Promise 對象,這是一種異步編程的解決方案。

簡單的說,就是用同步的方式寫異步代碼,可以用來解決回調地獄問題。

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

  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 來實現(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)點和缺點

優(yōu)點:Promise以同步的方式編寫異步代碼,避免了回調函數(shù)層層嵌套,可讀性更強。鏈式操作,可以在then中繼續(xù)寫Promise對象并return,然后繼續(xù)調用then進行回調操作。

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

4.Generator

Generator其實就是一個函數(shù),只不過是一個特殊的函數(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();

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

Generator的優(yōu)點和缺點

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

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

5.async/await

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

異步在做什么?

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

await 是什么?

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

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

如果 await 后面跟著一個 Promise 對象,它會阻塞后面的代碼,Promise 對象解析,然后獲取 resolve 的值作為 await 表達式的結果。

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

上面使用setTimeout來模擬異步操作,我們使用async/await來實現(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();

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

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

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

缺點:誤用 await 可能會導致性能問題,因為 await 會阻塞代碼。

到此,關于“JavaScript異步解決方案有哪些”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關知識,請繼續(xù)關注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。

AI