偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

面試題:實(shí)現(xiàn)小程序平臺(tái)的并發(fā)雙工 Rpc 通信

開(kāi)發(fā) 架構(gòu) 移動(dòng)應(yīng)用
rpc 是遠(yuǎn)程過(guò)程調(diào)用,是跨進(jìn)程、跨線程等場(chǎng)景下通信的常見(jiàn)封裝形式。面試題是小程序平臺(tái)的雙線程的場(chǎng)景,在一個(gè)公共文件里實(shí)現(xiàn)雙工的并發(fā)的 rpc 通信。

[[435138]]

前幾天面試的時(shí)候遇到一道面試題,還是挺考驗(yàn)?zāi)芰Φ摹?/p>

題目是這樣的:

rpc 是 remote procedure call,遠(yuǎn)程過(guò)程調(diào)用,比如一個(gè)進(jìn)程調(diào)用另一個(gè)進(jìn)程的某個(gè)方法。很多平臺(tái)提供的進(jìn)程間通信機(jī)制都封裝成了 rpc 的形式,比如 electron 的 remote 模塊。

小程序是雙線程機(jī)制,兩個(gè)線程之間要通信,提供了 postMessage 和 addListener 的 api?,F(xiàn)在要在兩個(gè)線程都會(huì)引入的 common.js 文件里實(shí)現(xiàn) rpc 方法,支持并發(fā)的 rpc 通信。

達(dá)到這樣的使用效果:

  1. const res = await rpc('method', params); 

這道題是有真實(shí)應(yīng)用場(chǎng)景的題目,比一些邏輯題和算法題更有意思一些。

實(shí)現(xiàn)思路

兩個(gè)線程之間是用 postMessage 的 api 來(lái)傳遞消息的:

  • 在 rpc 方法里用 postMessage 來(lái)傳遞要調(diào)用的方法名和參數(shù)
  • 在 addListener 里收到調(diào)用的時(shí)候,調(diào)用 api,然后通過(guò) postMessage 返回結(jié)果或者錯(cuò)誤

我們先實(shí)現(xiàn) rpc 方法,通過(guò) postMessage 傳遞消息,返回一個(gè) promise:

  1. function rpc(method, params) { 
  2.     postMessage(JSON.stringify({ 
  3.         method, 
  4.         params  
  5.     })); 
  6.  
  7.     return new Promise((resolve, reject) => { 
  8.          
  9.     }); 

這個(gè) promise 什么時(shí)候 resolve 或者 reject 呢?是在 addListener 收到消息后。那就要先把它存起來(lái),等收到消息再調(diào)用 resolve 或 reject。

為了支持并發(fā)和區(qū)分多個(gè)調(diào)用通道,我們加一個(gè) id。

  1. let id = 0; 
  2. function genId() { 
  3.     return ++id; 
  4.  
  5. const channelMap = new Map(); 
  6.  
  7. function rpc(method, params) { 
  8.     const curId = genId(); 
  9.  
  10.     postMessage(JSON.stringify({ 
  11.         id: curId, 
  12.         method, 
  13.         params  
  14.     })); 
  15.  
  16.     return new Promise((resolve, reject) => { 
  17.         channelMap.set(curId, { 
  18.             resolve, 
  19.             reject 
  20.         }); 
  21.     }); 

這樣,就通過(guò) id 來(lái)標(biāo)識(shí)了每一個(gè)遠(yuǎn)程調(diào)用請(qǐng)求和與它關(guān)聯(lián)的 resolve、reject。

然后要處理 addListener,因?yàn)槭请p工的通信,也就是通信的兩者都會(huì)用到這段代碼,所以要區(qū)分一下是請(qǐng)求還是響應(yīng)。

  1. addListener((message) => { 
  2.     const { curId, method, params, res}= JSON.parse(message); 
  3.     if (res) { 
  4.         // 處理響應(yīng) 
  5.     } else { 
  6.         // 處理請(qǐng)求 
  7.     } 
  8. }); 

處理請(qǐng)求就是調(diào)用方法,然后返回結(jié)果或者錯(cuò)誤:

  1. try { 
  2.     const data = global[method](...params); 
  3.     postMessage({ 
  4.         id 
  5.         res: { 
  6.             data 
  7.         } 
  8.     }); 
  9. } catch(e) { 
  10.     postMessage({ 
  11.         id, 
  12.         res: { 
  13.             error: e.message 
  14.         } 
  15.     }); 

處理響應(yīng)就是拿到并調(diào)用和 id 關(guān)聯(lián)的 resolve 和 reject:

  1. const { resolve, reject  } = channelMap.get(id); 
  2. if(res.data) { 
  3.     resolve(res.data); 
  4. else { 
  5.     reject(res.error); 

全部代碼是這樣的:

  1. let id = 0; 
  2. function genId() { 
  3.     return ++id; 
  4.  
  5. const channelMap = new Map(); 
  6.  
  7. function rpc(method, params) { 
  8.     const curId = genId(); 
  9.  
  10.     postMessage(JSON.stringify({ 
  11.         id: curId, 
  12.         method, 
  13.         params  
  14.     })); 
  15.  
  16.     return new Promise((resolve, reject) => { 
  17.         channelMap.set(curId, { 
  18.             resolve, 
  19.             reject 
  20.         }); 
  21.     }); 
  22.  
  23. addListener((message) => { 
  24.     const { id, method, params, res}= JSON.parse(message); 
  25.     if (res) { 
  26.         const { resolve, reject  } = channelMap.get(id); 
  27.         if(res.data) { 
  28.             resolve(res.data); 
  29.         } else { 
  30.             reject(res.error); 
  31.         } 
  32.     } else { 
  33.         try { 
  34.             const data = global[method](...params); 
  35.             postMessage({ 
  36.                 id 
  37.                 res: { 
  38.                     data 
  39.                 } 
  40.             }); 
  41.         } catch(e) { 
  42.             postMessage({ 
  43.                 id, 
  44.                 res: { 
  45.                     error: e.message 
  46.                 } 
  47.             }); 
  48.         } 
  49.     } 
  50. }); 

我們實(shí)現(xiàn)了最開(kāi)始的需求:

  • 實(shí)現(xiàn)了 rpc 方法,返回一個(gè) promise
  • 支持并發(fā)的調(diào)用
  • 兩個(gè)線程都引入這個(gè)文件,支持雙工的通信

其實(shí)主要注意的有兩個(gè)點(diǎn):

  • 要添加一個(gè) id 來(lái)關(guān)聯(lián)請(qǐng)求和響應(yīng),這在 socket 通信的時(shí)候也經(jīng)常用
  • resolve 和 reject 可以保存下來(lái),后續(xù)再調(diào)用。這在請(qǐng)求取消,比如 axios 的 cancelToken 的實(shí)現(xiàn)上也有應(yīng)用

這兩個(gè)點(diǎn)的應(yīng)用場(chǎng)景還是比較多的。

總結(jié)

rpc 是遠(yuǎn)程過(guò)程調(diào)用,是跨進(jìn)程、跨線程等場(chǎng)景下通信的常見(jiàn)封裝形式。面試題是小程序平臺(tái)的雙線程的場(chǎng)景,在一個(gè)公共文件里實(shí)現(xiàn)雙工的并發(fā)的 rpc 通信。

思路文中已經(jīng)講清楚了,主要要注意的是 promise 的 resolve 和 reject 可以保存下來(lái)后續(xù)調(diào)用,通過(guò)添加 id 來(lái)標(biāo)識(shí)和關(guān)聯(lián)一組請(qǐng)求響應(yīng)。

 

責(zé)任編輯:姜華 來(lái)源: 神光的編程秘籍
相關(guān)推薦

2009-08-11 15:09:44

一道面試題C#算法

2023-08-07 14:29:26

模擬電話全雙工通信

2021-07-04 08:01:30

Synchronize線程安全并發(fā)編程

2019-06-05 07:47:32

Nginx高并發(fā)多線程

2014-09-19 11:17:48

面試題

2020-04-07 14:40:19

Java并發(fā)編程多線程

2015-09-10 08:46:15

Java面試題

2020-06-04 14:40:40

面試題Vue前端

2023-11-13 07:37:36

JS面試題線程

2020-04-12 22:29:50

程序員MySQL數(shù)據(jù)

2011-03-24 13:27:37

SQL

2022-07-27 08:27:34

Call前端

2012-05-25 10:15:06

Java程序員面試題

2009-06-06 18:34:05

java面試題

2009-06-06 18:36:02

java面試題

2015-09-02 09:32:56

java線程面試

2010-11-26 10:53:29

戴爾

2014-07-15 11:10:01

面試題面試

2020-09-21 11:10:06

Docker運(yùn)維面試

2023-02-17 14:35:15

HashMapNode類型
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)