自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

你不知道的 JS 沙箱隔離

開發(fā) 前端
本文接下來的內(nèi)容,將介紹我在探索基于 Web Worker 實(shí)現(xiàn) JavaScript 沙箱隔離方案過程中的一些資料收集、理解以及我的踩坑和思考的過程。

[[442801]]

 自從 2014 年 HTML5 正式推薦標(biāo)準(zhǔn)發(fā)布以來,HTML5 增加了越來越多強(qiáng)大的特性和功能,而在這其中,工作線程(Web Worker)概念的推出讓人眼前一亮,但未曾隨之激起多大的浪花,并被在其隨后工程側(cè)的 Angular、Vue、React 等框架的「革命」浪潮所淹沒。

當(dāng)然,我們總會(huì)偶然看過一些文章介紹,或出于學(xué)習(xí)的目的做過一些應(yīng)用場景下的練習(xí),甚或在實(shí)際項(xiàng)目中的涉及大量數(shù)據(jù)計(jì)算場景中真的使用過。但相信也有很多人和我一樣茫然,找不到這種高大上的技術(shù)在實(shí)際項(xiàng)目場景中能有哪些能起到廣泛作用的應(yīng)用。

究其原因,Web Worker 獨(dú)立于 UI 主線程運(yùn)行的特性使其被大量考慮進(jìn)行性能優(yōu)化方面的嘗試(比如一些圖像分析、3D 計(jì)算繪制等場景),以保證在進(jìn)行大量計(jì)算的同時(shí),頁面對(duì)用戶能有及時(shí)的響應(yīng)。

而這些性能優(yōu)化的需求在前端側(cè)一方面涉及頻率低,另一方面也能通過微任務(wù)或服務(wù)端側(cè)處理來解決,它并不能像 Web Socket 這種技術(shù)為前端頁面下的輪詢場景的優(yōu)化能帶來質(zhì)的改變。

直至 2019 年爆火的微前端架構(gòu)的出現(xiàn),基于微應(yīng)用間 JavaScript 沙箱隔離的需求,Web Worker 才得以重新從邊緣化的位置躍入到我的中心視野。

根據(jù)我已經(jīng)了解到的 Web Worker 的相關(guān)知識(shí),我知道了 Web Worker 是工作在一個(gè)獨(dú)立子線程下(雖然這個(gè)子線程比起 Java 等編譯型語言的子線程實(shí)現(xiàn)得還有點(diǎn)弱,如無法加鎖等),線程之間自帶隔離的特性,那基于這種「物理」性的隔離,能不能實(shí)現(xiàn) JavaScript 運(yùn)行時(shí)的隔離呢?

本文接下來的內(nèi)容,將介紹我在探索基于 Web Worker 實(shí)現(xiàn) JavaScript 沙箱隔離方案過程中的一些資料收集、理解以及我的踩坑和思考的過程。雖然可能整篇文章內(nèi)容都在「炒冷飯」,但還是希望我的探索方案的過程能對(duì)正在看這篇文章的你有所幫助。

JavaScript 沙箱

在探索基于 Web Worker 的解決方案之前,我們先要對(duì)當(dāng)前要解決的問題——JavaScript 沙箱有所了解。

提到沙箱,我會(huì)先想到出于興趣玩過的沙盒游戲,但我們要探索的 JavaScript 沙箱不同于沙盒游戲,沙盒游戲注重對(duì)世界基本元素的抽象、組合以及物理力系統(tǒng)的實(shí)現(xiàn)等,而 JavaScript 沙箱則更注重在使用共享數(shù)據(jù)時(shí)對(duì)操作狀態(tài)的隔離。

在現(xiàn)實(shí)與 JavaScript 相關(guān)的場景中,我們知道平時(shí)使用的瀏覽器就是一個(gè)沙箱,運(yùn)行在瀏覽器中的 JavaScript 代碼無法直接訪問文件系統(tǒng)、顯示器或其他任何硬件。

Chrome 瀏覽器中每個(gè)標(biāo)簽頁也是一個(gè)沙箱,各個(gè)標(biāo)簽頁內(nèi)的數(shù)據(jù)無法直接相互影響,接口都在獨(dú)立的上下文中運(yùn)行。而在同一個(gè)瀏覽器標(biāo)簽頁下運(yùn)行 HTML 頁面,有哪些更細(xì)節(jié)的、對(duì)沙箱現(xiàn)象有需求的場景呢?

當(dāng)我們作為前端開發(fā)人員較長一段時(shí)間后,我們很輕易地就能想到在同一個(gè)頁面下,使用沙箱需求的諸多應(yīng)用場景,譬如:

  1.  執(zhí)行從不受信的源獲取到的第三方 JavaScript 代碼時(shí)(比如引入插件、處理 jsonp 請(qǐng)求回來的數(shù)據(jù)等)。
  2.  在線代碼編輯器場景(比如著名的 codesandbox)。
  3.  使用服務(wù)端渲染方案。
  4.  模板字符串中的表達(dá)式的計(jì)算。
  5.  ... ...

這里我們先回到開頭,先將前提假設(shè)在我正在面對(duì)的微前端架構(gòu)設(shè)計(jì)下。在微前端架構(gòu)中,其最關(guān)鍵的一個(gè)設(shè)計(jì)便是各個(gè)子應(yīng)用間的調(diào)度實(shí)現(xiàn)以及其運(yùn)行態(tài)的維護(hù),而運(yùn)行時(shí)各子應(yīng)用使用全局事件監(jiān)聽、使全局 CSS 樣式生效等常見的需求在多個(gè)子應(yīng)用切換時(shí)便會(huì)成為一種污染性的副作用,為了解決這些副作用,后來出現(xiàn)的很多微前端架構(gòu)(如 乾坤)有著各種各樣的實(shí)現(xiàn)。

譬如 CSS 隔離中常見的命名空間前綴、Shadow DOM、 乾坤 sandbox css 的運(yùn)行時(shí)動(dòng)態(tài)增刪等,都有著確實(shí)行之有效的具體實(shí)踐,而這里最麻煩棘手的,還是微應(yīng)用間的 JavaScript 的沙箱隔離。

在微前端架構(gòu)中,JavaScript 沙箱隔離需要解決如下幾個(gè)問題:

  1.  掛在 window 上的全局方法/變量(如 setTimeout、滾動(dòng)等全局事件監(jiān)聽等)在子應(yīng)用切換時(shí)的清理和還原。
  2.  Cookie、LocalStorage 等的讀寫安全策略限制。
  3.  各子應(yīng)用獨(dú)立路由的實(shí)現(xiàn)。
  4.  多個(gè)微應(yīng)用共存時(shí)相互獨(dú)立的實(shí)現(xiàn)。

在 乾坤 架構(gòu)設(shè)計(jì)中,關(guān)于沙箱有兩個(gè)入口文件需要關(guān)注,一個(gè)是 proxySandbox.ts,另一個(gè)是 snapshotSandbox.ts,他們分別基于 Proxy 實(shí)現(xiàn)代理了 window 上常用的常量和方法以及不支持 Proxy 時(shí)降級(jí)通過快照實(shí)現(xiàn)備份還原。

結(jié)合其相關(guān)開源文章分享,簡單總結(jié)下其實(shí)現(xiàn)思路:起初版本使用了快照沙箱的概念,模擬 ES6 的 Proxy API,通過代理劫持 window ,當(dāng)子應(yīng)用修改或使用 window 上的屬性或方法時(shí),把對(duì)應(yīng)的操作記錄下來,每次子應(yīng)用掛載/卸載時(shí)生成快照,當(dāng)再次從外部切換到當(dāng)前子應(yīng)用時(shí),再從記錄的快照中恢復(fù),而后來為了兼容多個(gè)子應(yīng)用共存的情況,又基于 Proxy 實(shí)現(xiàn)了代理所有全局性的常量和方法接口,為每個(gè)子應(yīng)用構(gòu)造了獨(dú)立的運(yùn)行環(huán)境。

另外一種值得借鑒的思路是阿里云開發(fā)平臺(tái)的 Browser VM,其核心入口邏輯在 Context.js 文件中。它的具體實(shí)現(xiàn)思路是這樣的:

    1. 借鑒 with 的實(shí)現(xiàn)效果,在 webpack 編譯打包階段為每個(gè)子應(yīng)用代碼包裹一層代碼(見其插件包 breezr-plugin-os 下相關(guān)文件),創(chuàng)建一個(gè)閉包,傳入自己模擬的 window、document、location、history 等全局對(duì)象(見 根目錄下 相關(guān)文件)。

    2. 在模擬的 Context 中,new 一個(gè) iframe 對(duì)象,提供一個(gè)和宿主應(yīng)用空的(about:blank) 同域 URL 來作為這個(gè) iframe 初始加載的 URL(空的 URL 不會(huì)發(fā)生資源加載,但是會(huì)產(chǎn)生和這個(gè) iframe 中關(guān)聯(lián)的 history 不能被操作的問題,這時(shí)路由的變換只支持 hash 模式),然后將其下的原生瀏覽器對(duì)象通過 contentWindow 取出來(因?yàn)?iframe 對(duì)象天然隔離,這里省去了自己 Mock 實(shí)現(xiàn)所有 API 的成本)。

    3. 取出對(duì)應(yīng)的 iframe 中原生的對(duì)象之后,繼續(xù)對(duì)特定需要隔離的對(duì)象生成對(duì)應(yīng)的 Proxy,然后對(duì)一些屬性獲取和屬性設(shè)置,做一些特定的實(shí)現(xiàn)(比如 window.document 需要返回特定的沙箱 document 而不是當(dāng)前瀏覽器的document 等)。

    4. 為了文檔內(nèi)容能夠被加載在同一個(gè) DOM 樹上,對(duì)于 document,大部分的 DOM 操作的屬性和方法仍舊直接使用宿主瀏覽器中的 document 的屬性和方法處理等。

總的來說,在 Browser VM 的實(shí)現(xiàn)中, 可以看出其實(shí)現(xiàn)部分還是借鑒了 乾坤 或者說其他微前端架構(gòu)的思路,比如常見全局對(duì)象的代理和攔截。并且借助 Proxy 特性,針對(duì) Cookie、LocalStorage 的讀寫同樣能做一些安全策略的實(shí)現(xiàn)等。

但其最大的亮點(diǎn)還是借助 iframe 做了一些取巧的實(shí)現(xiàn),當(dāng)這個(gè)為每個(gè)子應(yīng)用創(chuàng)建的 iframe 被移除時(shí),寫在其下 window 上的變量和 setTimeout、全局事件監(jiān)聽等也會(huì)一并被移除;另外基于 Proxy,DOM 事件在沙箱中做記錄,然后在宿主中生命周期中實(shí)現(xiàn)移除,能夠以較小的開發(fā)成本實(shí)現(xiàn)整個(gè) JavaScript 沙箱隔離的機(jī)制。

除了以上現(xiàn)在比較火的方案,最近我也了解到了 UI 設(shè)計(jì)領(lǐng)域的 Figma 產(chǎn)品也基于其插件系統(tǒng)產(chǎn)出了一種隔離方案。起初 Figma 同樣是將插件代碼放入 iframe 中執(zhí)行并通過 postMessage 與主線程通信,但由于易用性以及 postMessage 序列化帶來的性能等問題,F(xiàn)igma 選擇還是將插件放入主線程去執(zhí)行。

Figma 采用的方案是基于目前還在草案階段 Realm API,并將 JavaScript 解釋器的一種 C++ 實(shí)現(xiàn) Duktape 編譯到了 WebAssembly,然后將其嵌入到 Realm 上下文中,實(shí)現(xiàn)了其產(chǎn)品下的三方插件的獨(dú)立運(yùn)行。這種方案和探索的基于 Web Worker 的實(shí)現(xiàn)可能能夠結(jié)合得更好,持續(xù)關(guān)注中。

Web Worker 與 DOM 渲染

在了解了 JavaScript 沙箱的「前世今生」之后,我們將目光投回本文的主角——Web Worker 身上。

正如本文開頭所說,Web Worker 子線程的形式也是一種天然的沙箱隔離,理想的方式,是借鑒 Browser VM 的前段思路,在編譯階段通過 Webpack 插件為每個(gè)子應(yīng)用包裹一層創(chuàng)建 Worker 對(duì)象的代碼,讓子應(yīng)用運(yùn)行在其對(duì)應(yīng)的單個(gè) Worker 實(shí)例中,比如: 

  1. __WRAP_WORKER__(`/* 打包代碼 */ }`);  
  2. function __WRAP_WORKER__(appCode) {  
  3.  var blob = new Blob([appCode]);  
  4.  var appWorker = new Worker(window.URL.createObjectURL(blob));  
  5. }  

但在了解過微前端下 JavaScript 沙箱的實(shí)現(xiàn)過程后,我們不難發(fā)現(xiàn)幾個(gè)在 Web Worker 下去實(shí)現(xiàn)微前端場景的 JavaScript 沙箱必然會(huì)遇到的幾個(gè)難題:

  1.   出于線程安全設(shè)計(jì)考慮,Web Worker 不支持 DOM 操作,必須通過 postMessage 通知 UI 主線程來實(shí)現(xiàn)。
  2.   Web Worker 無法訪問 window、document 之類的瀏覽器全局對(duì)象。

其他諸如 Web Worker 無法訪問頁面全局變量和函數(shù)、無法調(diào)用 alert、confirm 等 BOM API 等問題,相對(duì)于無法訪問 window、document 全局對(duì)象已經(jīng)是小問題了。不過可喜的是,Web Worker 中可以正常使用 setTimeout、setInterval 等定時(shí)器函數(shù),也仍能發(fā)送 ajax 請(qǐng)求。

所以,當(dāng)先要解決問題,便是在單個(gè) Web Worker 實(shí)例中執(zhí)行 DOM 操作的問題了。首先我們有一個(gè)大前提:Web Worker 中無法渲染 DOM,所以,我們需要基于實(shí)際的應(yīng)用場景,將 DOM 操作進(jìn)行拆分。

React Worker DOM

因?yàn)槲覀兾⑶岸思軜?gòu)中的子應(yīng)用局限在 React 技術(shù)棧下,我先將目光放在了基于 React 框架的解決方案上。

在 React 中,我們知道其將渲染階段分為對(duì) DOM 樹的改變進(jìn)行 Diff 和實(shí)際渲染改變頁面 DOM 兩個(gè)階段這一基本事實(shí),那能不能將 Diff 過程置于 Web Worker 中,再將渲染階段通過 postMessage 與主線程進(jìn)行通信后放在主線程進(jìn)行呢?簡單一搜,頗為汗顏,已經(jīng)有大佬在 5、6 年前就有嘗試了。這里我們可以參考下 react-worker-dom 的開源代碼。

react-worker-dom 中的實(shí)現(xiàn)思路很清晰。其在 common/channel.js 中統(tǒng)一封裝了子線程和主線程互相通信的接口和序列化通信數(shù)據(jù)的接口,然后我們可以看到其在 Worker 下實(shí)現(xiàn) DOM 邏輯處理的總?cè)肟谖募?worker 目錄下,

從該入口文件順藤摸瓜,可以看到其實(shí)現(xiàn)了計(jì)算 DOM 后通過 postMessage 通知主線程進(jìn)行渲染的入口文件 WorkerBridge.js 以及其他基于 React 庫實(shí)現(xiàn)的 DOM 構(gòu)造、Diff 操作、生命周期 Mock 接口等相關(guān)代碼,而接受渲染事件通信的入口文件在 page 目錄下,該入口文件接受 node 操作事件后再結(jié)合 WorkerDomNodeImpl.js 中的接口代碼實(shí)現(xiàn)了 DOM 在主線程的實(shí)際渲染更新。

簡單做下總結(jié)?;?React 技術(shù)棧,通過在 Web Worker 下實(shí)現(xiàn) Diff 與渲染階段的進(jìn)行分離,可以做到一定程度的 DOM 沙箱,但這不是我們想要的微前端架構(gòu)下的 JavaScript 沙箱。

先不談拆分 Diff 階段與渲染階段的成本與收益比,首先,基于技術(shù)??蚣艿奶厥庑运龅倪@諸多努力,會(huì)隨著這個(gè)框架本身版本的升級(jí)存在著維護(hù)升級(jí)難以掌控的問題;其次,假如各個(gè)子應(yīng)用使用的技術(shù)棧框架不同,要為這些不同的框架分別封裝適配的接口,擴(kuò)展性和普適性弱;最后,最為重要的一點(diǎn),這種方法暫時(shí)還是沒有解決 window 下資源共享的問題,或者說,只是啟動(dòng)了解決這個(gè)問題的第一步。

接下來,我們先繼續(xù)探討 Worker 下實(shí)現(xiàn) DOM 操作的另外一種方案。

AMP WorkerDOM

在我開始糾結(jié)于如 react-worker-dom 這種思路實(shí)際落地開發(fā)的諸多「天塹」問題的同時(shí),瀏覽過其他 DOM 框架因?yàn)橥瑯泳邆洳寮C(jī)制偶然迸進(jìn)了我的腦海,它是 Google 的 AMP。

AMP 開源項(xiàng)目 中除了如 amphtml 這種通用的 Web 組件框架,還有很多其他工程采用了 Shadow DOM、Web Component 等新技術(shù),在項(xiàng)目下簡單刷了一眼后,我欣喜地看到了工程 worker-dom。

粗略翻看下 worker-dom 源碼,我們?cè)?src 根目錄下可以看到 main-thread 和 worker-thread 兩個(gè)目錄,分別打開看了下后,可以發(fā)現(xiàn)其實(shí)現(xiàn)拆分 DOM 相關(guān)邏輯和 DOM 渲染的思路和上面的 react-worker-dom 基本類似,但 worker-dom 因?yàn)楹蜕蠈涌蚣軣o關(guān),其下的實(shí)現(xiàn)更為貼近 DOM 底層。

先看 worker-thread DOM 邏輯層的相關(guān)代碼,可以看到其下的 dom 目錄 下實(shí)現(xiàn)了基于 DOM 標(biāo)準(zhǔn)的所有相關(guān)的節(jié)點(diǎn)元素、屬性接口、document 對(duì)象等代碼,上一層目錄中也實(shí)現(xiàn)了 Canvas、CSS、事件、Storage 等全局屬性和方法。

接著看 main-thread,其關(guān)鍵功能一方面是提供加載 worker 文件從主線程渲染頁面的接口,另一方面可以從 worker.ts 和 nodes.ts 兩個(gè)文件的代碼來理解。

在 worker.ts 中像我最初所設(shè)想的那樣包裹了一層代碼,用于自動(dòng)生成 Worker 對(duì)象,并將代碼中的所有 DOM 操作都代理到模擬的 WorkerDOM 對(duì)象上: 

  1. const code = `  
  2.       'use strict';  
  3.       (function(){  
  4.         ${workerDOMScript}  
  5.         self['window'] = self;  
  6.         var workerDOM = WorkerThread.workerDOM;  
  7.         WorkerThread.hydrate(  
  8.           workerDOM.document,  
  9.           ${JSON.stringify(strings)},  
  10.           ${JSON.stringify(skeleton)}, 
  11.           ${JSON.stringify(cssKeys)},  
  12.           ${JSON.stringify(globalEventHandlerKeys)},  
  13.           [${window.innerWidth}, ${window.innerHeight}],  
  14.           ${JSON.stringify(localStorageInit)},  
  15.           ${JSON.stringify(sessionStorageInit)}  
  16.         );  
  17.         workerDOM.document[${TransferrableKeys.observe}](this);  
  18.         Object.keys(workerDOM).forEach(function(k){self[k]=workerDOM[k]});  
  19. }).call(self);  
  20. ${authorScript}  
  21. //# sourceURL=${encodeURI(config.authorURL)}`;  
  22. this[TransferrableKeys.worker] = new Worker(URL.createObjectURL(new Blob([code]))); 

在 nodes.ts 中,實(shí)現(xiàn)了真實(shí)元素節(jié)點(diǎn)的構(gòu)造和存儲(chǔ)(基于存儲(chǔ)數(shù)據(jù)結(jié)構(gòu)是否以及如何在渲染階段有優(yōu)化還需進(jìn)一步研究源碼)。

同時(shí),在 transfer 目錄下的源碼,定義了邏輯層和 UI 渲染層的消息通信的規(guī)范。

總的來看,AMP WorkerDOM 的方案拋棄了上層框架的約束,通過從底層構(gòu)造了 DOM 所有相關(guān) API 的方式,真正做到了與框架技術(shù)棧無關(guān)。

它一方面完全可以作為上層框架的底層實(shí)現(xiàn),來支持各種上層框架的二次封裝遷移(如工程 amp-react-prototype),另一方面結(jié)合了當(dāng)前主流 JavaScript 沙箱方案,通過模擬 window、document 全局方法的并代理到主線程的方式實(shí)現(xiàn)了部分的 JavaScript 沙箱隔離(暫時(shí)沒看到路由隔離的相關(guān)代碼實(shí)現(xiàn))。

當(dāng)然,從我個(gè)人角度來看,AMP WorkerDOM 也有其當(dāng)前在落地上一定的局限性。一個(gè)是對(duì)當(dāng)前主流上層框架如 Vue、React 等的遷移成本及生態(tài)的適配成本,另一個(gè)是其在單頁應(yīng)用下的尚未看到有相關(guān)實(shí)現(xiàn)方案,在大型 PC 微前端應(yīng)用的支持上還無法找到更優(yōu)方案。

其實(shí),在了解完 AMP WorkerDOM 的實(shí)現(xiàn)方案之后,基于 react-worker-dom 思路的后續(xù)方案也可以有個(gè)大概方向了:渲染通信的后續(xù)過程,可考慮結(jié)合 Browser VM 的相關(guān)實(shí)現(xiàn),在生成 Worker 對(duì)象的同時(shí),也生成一個(gè) iframe 對(duì)象,然后將 DOM 下的操作都通過 postMessage 發(fā)送到主線程后,以與其綁定的 iframe 兌現(xiàn)來執(zhí)行,同時(shí),通過代理將具體的渲染實(shí)現(xiàn)再轉(zhuǎn)發(fā)給原 WorkerDomNodeImpl.js 邏輯來實(shí)現(xiàn) DOM 的實(shí)際更新。

小結(jié)與一些個(gè)人前瞻

首先聊一聊個(gè)人的一些總結(jié)。Web Worker 下實(shí)現(xiàn)微前端架構(gòu)下的 JavaScript 沙箱最初是出于一點(diǎn)個(gè)人靈光的閃現(xiàn),在深入調(diào)研后,雖然最終還是因?yàn)檫@樣那樣的問題導(dǎo)致在方案落地上無法找到最優(yōu)解從而放棄采用通用方案,但仍不妨礙我個(gè)人對(duì) Web Worker 技術(shù)在實(shí)現(xiàn)插件類沙箱應(yīng)用上的持續(xù)看好。

插件機(jī)制在前端領(lǐng)域一直是津津樂道的一種設(shè)計(jì),從 Webpack 編譯工具到 IDE 開發(fā)工具,從 Web 應(yīng)用級(jí)的實(shí)體插件到應(yīng)用架構(gòu)設(shè)計(jì)中插件擴(kuò)展設(shè)計(jì),結(jié)合 WebAssembly 技術(shù),Web Worker 無疑將在插件設(shè)計(jì)上占據(jù)舉足輕重的地位。

其次是一些個(gè)人的一些前瞻思考。其實(shí)從 Web Worker 實(shí)現(xiàn) DOM 渲染的調(diào)研過程中可以看到,基于邏輯與 UI 分離的思路,前端后續(xù)的架構(gòu)設(shè)計(jì)有很大機(jī)會(huì)能夠產(chǎn)生一定的變革。

目前不管是盛行的 Vue 還是 React 框架,其框架設(shè)計(jì)不論是 MVVM 還是結(jié)合 Redux 之后的 Flux,其本質(zhì)上仍舊還是由 View 層驅(qū)動(dòng)的框架設(shè)計(jì)(個(gè)人淺見),其具備靈活性的同時(shí)也產(chǎn)生著性能優(yōu)化、大規(guī)模項(xiàng)目層級(jí)升上后的協(xié)作開發(fā)困難等問題,而基于 Web Worker 的邏輯與 UI 分離,將促使數(shù)據(jù)獲取、處理、消費(fèi)整個(gè)流程的進(jìn)一步的業(yè)務(wù)分層,從而固化出一整套的 MVX 設(shè)計(jì)思路。 

 

責(zé)任編輯:龐桂玉 來源: 前端大全
相關(guān)推薦

2021-11-16 08:51:29

Node JavaScript變量類型

2024-02-05 11:55:41

Next.js開發(fā)URL

2020-06-12 09:20:33

前端Blob字符串

2020-07-28 08:26:34

WebSocket瀏覽器

2011-09-15 17:10:41

2022-10-13 11:48:37

Web共享機(jī)制操作系統(tǒng)

2009-12-10 09:37:43

2021-02-01 23:23:39

FiddlerCharlesWeb

2020-12-14 07:51:16

JS 技巧虛值

2010-08-23 09:56:09

Java性能監(jiān)控

2020-09-15 08:35:57

TypeScript JavaScript類型

2022-11-04 08:19:18

gRPC框架項(xiàng)目

2021-12-22 09:08:39

JSON.stringJavaScript字符串

2012-11-23 10:57:44

Shell

2015-06-19 13:54:49

2020-08-11 11:20:49

Linux命令使用技巧

2021-10-17 13:10:56

函數(shù)TypeScript泛型

2012-06-26 15:49:05

2014-03-12 09:23:06

DevOps團(tuán)隊(duì)合作

2017-03-02 14:05:42

AndroidAndroid Stu調(diào)試技巧
點(diǎn)贊
收藏

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