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

postMessage消息通信Promise化的方法實現(xiàn)

 更新時間:2024年03月13日 08:25:20   作者:ZTStory  
postMessage Api 想必大家都不陌生,WebWorker 通信會用到,iframe 窗口之間通信也會用到,那么我們能不能將 postMessage 進行一次轉(zhuǎn)化,把他變成類似 Promise 的使用方式,所以本文給大家介紹了postMessage消息通信Promise化的方法實現(xiàn),需要的朋友可以參考下

前言

postMessage Api 想必大家都不陌生,WebWorker 通信會用到,iframe 窗口之間通信也會用到,尤其像一些通過 iframe 嵌入其他項目產(chǎn)品的應(yīng)用,想要實現(xiàn)實時通信,就少不了它。

但是,監(jiān)聽消息基本都是全局注冊事件來接收對應(yīng)消息,然后在做分發(fā)處理的。

假如業(yè)務(wù)比較復(fù)雜,流程比較長,消息通信的頻率高,而且通信場景繁瑣,那么通過全局事件處理就顯得不太合適了。

那么問題來了,我們能不能將 postMessage 進行一次轉(zhuǎn)化,把他變成類似 Promise 的使用方式,這樣業(yè)務(wù)里使用 postMessage 進行通信的時候,就不需要考慮全局回調(diào)事件了。而且 Promise 和他的語法糖 await 都可以很好的消除回調(diào)地獄的情況。

思考

Promise 化,需要解決那些問題?

  • 業(yè)務(wù)中發(fā)起的事件,如何注冊并消費?
  • 相同的事件多次發(fā)起,應(yīng)該如何處理響應(yīng)結(jié)果?

我們先來看業(yè)務(wù)中發(fā)起的事件,如何注冊并消費?

舉個實際的例子:我們假定有子系統(tǒng)向父級 iframe 獲取 loginToken 的行為。

正常情況我們會這樣寫:

const messageEventHandler = (event: MessageEvent) => {
  const data = event.data;
  // 分發(fā)事件
  emit(data?.api, data);
}
// 接收
window.addEventListener("message", messageEventHandler);
// 發(fā)送
window.parent.postMessage({ api: "getLoginToken" }, "*");

這樣寫邏輯有問題嗎?沒有問題!邏輯可以正確的執(zhí)行,事件也成功的被分發(fā)了

通過消息訂閱來接收通知,單發(fā)的時候看起來沒什么問題,假如 getLoginToken 被多次觸發(fā),或者說,同一個事件被多次注冊,那么還需要考慮業(yè)務(wù)側(cè)事件執(zhí)行后銷毀,避免重復(fù)觸發(fā)

有沒有辦法可以減輕業(yè)務(wù)側(cè)的心智負(fù)擔(dān)呢?

辦法總比困難多嘛~

我們可以使用一個全局變量 PostMessageCallBackMap 來存放注冊的事件及回調(diào),Promise 中的 resolve 正好有閱后即焚的特性,那么我們是不是可以考慮把創(chuàng)建出來的 resolve 作為 callback 放到 Map 中呢?

想到就立即行動!

實現(xiàn)

改造后的代碼如下:

export const PostMessageCallBackMap = new Map();
const messageEventHandler = (event: MessageEvent) => {
  // 事件分發(fā)
  const data = event.data;
  let eventKey = data?.api;

  if (PostMessageCallBackMap.has(eventKey)) {
    PostMessageCallBackMap.get(eventKey)(data);
  }
};

// 接收
window.addEventListener("message", messageEventHandler);

接收我們寫好了,發(fā)送這塊怎么實現(xiàn)呢?

// 發(fā)送
function sendMessage<T>(param: JSBridgeReq): Promise<JSBridgeRes<T>> {
  return new Promise((resolve, reject) => {
    if (window.parent) {
      window.parent.postMessage(param, "*");
      // 將當(dāng)前的 resolve 添加到 Map 中,等待返回事件觸發(fā)
      let eventKey = param.api;
      PostMessageCallBackMap.set(eventKey, resolve);
    }
  });
}
// 這樣封裝一下,業(yè)務(wù)中使用就十分方便了
const { token } = await sendMessage({ api: "getLoginToken" })
console.log(token);

這樣看起來舒服了很多,業(yè)務(wù)中應(yīng)用起來也順手了很多,完結(jié)撒花~

等等!

還有個問題吶。

相同的事件多次發(fā)起,應(yīng)該如何處理響應(yīng)結(jié)果?

陷入沉思

emm,按上面的寫法,多次發(fā)送 getLoginToken 事件,Map 中的 Key 是唯一的,之前的事件會被覆蓋掉,再加上異步事件返回時間不確定的話,完蛋了??!

擺爛!

注釋加上,不要調(diào)多次!

結(jié)束!

測試:哦?是嗎?(狂點、狂點、狂點)

好啦好啦,雖然我們可以通過防抖來避免測試瘋狂轟炸,但是某些場景下真的會有連續(xù)觸發(fā) api 的情況,那我們怎么解決呢?

每一個回調(diào)給他一個唯一id,然后通過事件id來進行匹配,不管事件執(zhí)行的時間長短,通過事件id總可以找到另一半。

唯一id,最簡單的我們就用時間戳吧。

改造!改造!改造!

export const PostMessageCallBackMap = new Map();

// 發(fā)送
function sendMessage<T>(param: JSBridgeReq): Promise<JSBridgeRes<T>> {
  return new Promise((resolve, reject) => {
    if (window.parent) {
      param.timestamp = Date.now();
      window.parent.postMessage(param, "*");
      
      let eventKey = param.api + param.timestamp;
      PostMessageCallBackMap.set(eventKey, resolve);
    }
  });
}

// 接收
const messageEventHandler = (event: MessageEvent) => {
  // 事件分發(fā)
  const data = event.data;
  let eventKey = data?.api;
  // timestamp 來保證對應(yīng)關(guān)系
  eventKey = data?.api + (data?.timestamp || "");

  if (PostMessageCallBackMap.has(eventKey)) {
    PostMessageCallBackMap.get(eventKey)(data);
    // 由于事件id的存在,Map會越來越大,清除字典防止內(nèi)存泄漏
    setTimeout(() => {
      PostMessageCallBackMap.delete(eventKey);
    }, 0);
  }
};
window.addEventListener("message", messageEventHandler);

總結(jié)

通過這樣一番分析改造,終于讓難以控制的全局注冊事件 postMessage 變成了可以鏈?zhǔn)秸{(diào)用的 Promise,又可以愉快的寫業(yè)務(wù)代碼啦~

演示地址:https://ztstory.github.io/vue-composition-demo/#/PostMessagePromise

源碼地址:https://github.com/ZTStory/vue-composition-demo

到此這篇關(guān)于postMessage消息通信Promise化的方法實現(xiàn)的文章就介紹到這了,更多相關(guān)postMessage消息Promise化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • javascript 解決瀏覽器不支持的問題

    javascript 解決瀏覽器不支持的問題

    這篇文章主要介紹了javascript 解決瀏覽器不支持的問題的相關(guān)資料,需要的朋友可以參考下
    2016-09-09
  • 通過javascript的匿名函數(shù)來分析幾段簡單有趣的代碼

    通過javascript的匿名函數(shù)來分析幾段簡單有趣的代碼

    想起自己很久以前學(xué)習(xí)javascript的經(jīng)歷,也曾經(jīng)碰到過幾個由匿名函數(shù)造成的困擾(其中一個就是由閉包引起的),下面就整理幾段簡單代碼討論一下,讓我們大家一起進步。
    2010-06-06
  • 微信小程序?qū)崿F(xiàn)頁面浮動導(dǎo)航

    微信小程序?qū)崿F(xiàn)頁面浮動導(dǎo)航

    這篇文章主要為大家詳細介紹了微信小程序?qū)崿F(xiàn)頁面浮動導(dǎo)航,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • 小程序?qū)崿F(xiàn)簡單分頁組件

    小程序?qū)崿F(xiàn)簡單分頁組件

    這篇文章主要為大家詳細介紹了小程序?qū)崿F(xiàn)簡單分頁組件,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • 基于WebUploader的文件上傳js插件

    基于WebUploader的文件上傳js插件

    這篇文章主要為大家詳細介紹了基于WebUploader的文件上傳js插件,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-08-08
  • 詳解TypeScript中類的定義與用法

    詳解TypeScript中類的定義與用法

    TypeScript是一種開源的編程語言,它是JavaScript的超集,這篇文章主要來和大家介紹一下TypeScript中類的定義與用法,感興趣的小伙伴可以了解一下
    2023-06-06
  • echarts多條折線圖動態(tài)分層的實現(xiàn)方法

    echarts多條折線圖動態(tài)分層的實現(xiàn)方法

    這篇文章主要介紹了echarts多條折線圖動態(tài)分層的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • javascript各種復(fù)制代碼收集

    javascript各種復(fù)制代碼收集

    javascript各種形式的復(fù)制代碼效果,有直接復(fù)制url,復(fù)制文本框中的內(nèi)容、隱藏表單中的內(nèi)容,復(fù)制span中的內(nèi)容
    2008-09-09
  • 原生js實現(xiàn)可拖拽效果

    原生js實現(xiàn)可拖拽效果

    本文主要介紹了原生js實現(xiàn)可拖拽效果的實例,具有很好的參考價值,下面跟著小編一起來看下吧
    2017-02-02
  • 微信小程序?qū)崿F(xiàn)聊天對話(文本、圖片)功能

    微信小程序?qū)崿F(xiàn)聊天對話(文本、圖片)功能

    這篇文章主要為大家詳細介紹了微信小程序?qū)崿F(xiàn)聊天對話功能,可以發(fā)送文本、圖片,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-07-07

最新評論