狠狠色丁香婷婷综合尤物/久久精品综合一区二区三区/中国有色金属学报/国产日韩欧美在线观看 - 国产一区二区三区四区五区tv

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

一杯咖啡☕️的時間,聊聊 js 異步解決方案

freeflydom
2023年7月29日 9:42 本文熱度 606

回調函數(callback)

回調函數 簡單理解就是一個函數被作為參數傳遞給另一個函數?;卣{是早期最常用的一種異步解決方案。

回調并不一定就是異步,并沒有直接關系。

舉個簡單的例子:

function f1(cb) {

  setTimeout(() => {

    cb && cb();

  }, 2000);

}


f1(() => {

  console.log("1");

});

如上,我們使用 setTimeout 在函數 f1 中模擬了一個耗時 2s 的任務,耗時任務結束后會拋出一個回調,那么我們在調用時就可以做到在函數 f1 的耗時任務結束后執行回調函數了。

采用這種方式,我們把同步操作變成了異步操作,f1 不會堵塞程序運行,相當于先執行程序的主要邏輯,將耗時的操作推遲執行。

回調優缺點

優點:簡單、容易理解

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

事件監聽(發布訂閱模式)

發布訂閱模式 定義了對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴于它的對象都將會得到通知。

其實我們都用過發布訂閱模式,比如我們在 DOM 節點上綁定一個事件函數:

document.body.addEventListener('click', function () {

  console.log('點擊');

})

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

發布訂閱模式有很多種實現方式,下面我們用 class 來簡單實現下:

class Emitter {

  constructor() {

    // _listener數組,key為自定義事件名,value為執行回調數組-因為可能有多個

    this._listener = []

  }


  // 訂閱 監聽事件

  on(type, fn) {

    // 判斷_listener數組中是否存在該事件命

    // 存在將回調push到事件名對應的value數組中,不存在直接新增

    this._listener[type] 

      ? this._listener[type].push(fn) 

    : (this._listener[type] = [fn])

  }


  // 發布 觸發事件

  trigger(type, ...rest) {

    // 判斷該觸發事件是否存在

    if (!this._listener[type]) return

    // 遍歷執行該事件回調數組并傳遞參數

    this._listener[type].forEach(callback => callback(...rest))

  }

}

如上所示,我們創建了一個 Emitter 類,并且添加了兩個原型方法 ontrigger,使用如下:

// 創建一個emitter實例

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('我是主程序')

  setTimeout(() => {

    emitter.trigger("done", "異步參數一", "異步參數二")

  }, 1000)

}


fn1()

我們先創建一個 emitter 實例,接著注冊事件,再觸發事件,也解決了異步問題。

事件監聽優缺點

優點:比較符合模塊化思想,我們自寫監聽器時可以做很多優化從而更好地監控程序運行。

缺點:整個程序變成了事件驅動,流程上或多或少都會有點影響,每次使用還得注冊事件監聽再進行觸發挺麻煩的,代碼也不太優雅。

Promise

ES2015(ES6)標準化和引入了 Promise 對象,它是異步編程的一種解決方案。

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

Promise 對象狀態一旦改變,就不會再變,只有兩種變化可能:

  1. Pending 變為 Resolved

  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 來實現:

function fn() {

  let time1 = 0;

  fn1(time1)

    .then((time2) => fn2(time2))

    .then((time3) => fn3(time3))

    .then((res) => {

      console.log(`result is ${res}`);

    });

}


fn();

Promise 優缺點

優點:Promise 用同步的方式寫異步的代碼,避免了層層嵌套的回調函數,可讀性更好。鏈式操作,可以在 then 中繼續寫 Promise 對象并返回,然后繼續調用 then 來進行回調操作。

缺點:Promise 對象一旦新建就會立即執行,無法中途取消。若不設置回調函數,Promise 內部會拋出錯誤,不會流到外部。

Generator

Generator 其實是一個函數,只不過是一個特殊的函數。普通函數,你執行了這個函數,函數內部不會停,直到這個函數結束。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();

上面這個示例就是一個 Generator 函數,它有如下特點:

  • 不同于普通函數,Generator 函數在 function 后面,函數名之前有個 *

  • 函數內部有 yield 字段

  • 調用后其函數返回值使用了 next 方法

Generator 優缺點

優點:優雅的流程控制方式,可以讓函數可中斷執行

缺點:Generator 函數的執行必須靠執行器,只針對異步處理來說,還是不太方便

async/await

ES2017 標準引入了 async 函數,使得異步操作變得更加方便。async 是異步的意思,而 await 是 async wait 的簡寫,即異步等待,async/await 的出現,被很多人認為是 js 異步操作的最終且最優雅的解決方案。

async 在做什么

async 函數返回的是一個 Promise 對象,如果在 async 函數中直接 return 一個直接量,async 會把這個直接量通過 Promise.resolve() 封裝成 Promise 對象返回。

await 在等待什么

await 等待的是一個表達式,這個表達式的計算結果是 Promise 對象或者其它值(換句話說,就是沒有特殊限定,啥都行)。

  • 如果 await 后面不是 Promise 對象,直接執行

  • 如果 await 后面是 Promise 對象會阻塞后面的代碼,Promise 對象 resolve,然后得到 resolve 的值,作為 await 表達式的運算結果

  • await 只能在 async 函數中使用

上述用 setTimeout 模擬異步操作,我們用 async/await 來實現:

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 實現是一樣的,但這個 async/await 代碼結構看起來清晰得多,幾乎跟同步寫法一樣,十分優雅。

async/await 優缺點

優點:內置執行器,更好的語義,更廣的適用性

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


原文鏈接



該文章在 2023/7/29 9:42:29 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved