淺探 Web Worker 與 JavaScript 沙箱
作者:ES2049 / 靳志凱
一些「炒冷飯」的背景介紹
本文并不會(huì)從頭開始介紹 Web Worker 的基礎(chǔ)知識(shí)和基本 API 的使用等(只是部分有涉及),若還未了解過(guò) Web Worker,可參考查閱 W3C 標(biāo)準(zhǔn) Workers 文檔中的相關(guān)介紹。
JavaScript 沙箱
執(zhí)行從不受信的源獲取到的第三方 JavaScript 代碼時(shí)(比如引入插件、處理 jsonp 請(qǐng)求回來(lái)的數(shù)據(jù)等)。 在線代碼編輯器場(chǎng)景(比如著名的 codesandbox)。 使用服務(wù)端渲染方案。 模板字符串中的表達(dá)式的計(jì)算。 ... ...
掛在 window 上的全局方法/變量(如 setTimeout、滾動(dòng)等全局事件監(jiān)聽等)在子應(yīng)用切換時(shí)的清理和還原。 Cookie、LocalStorage 等的讀寫安全策略限制。 各子應(yīng)用獨(dú)立路由的實(shí)現(xiàn)。 多個(gè)微應(yīng)用共存時(shí)相互獨(dú)立的實(shí)現(xiàn)。
借鑒 with的實(shí)現(xiàn)效果,在 webpack 編譯打包階段為每個(gè)子應(yīng)用代碼包裹一層代碼(見其插件包 breezr-plugin-os 下相關(guān)文件),創(chuàng)建一個(gè)閉包,傳入自己模擬的 window、document、location、history 等全局對(duì)象。在模擬的 Context 中,new 一個(gè) iframe 對(duì)象,提供一個(gè)和宿主應(yīng)用空的(about:blank) 同域 URL 來(lái)作為這個(gè) iframe 初始加載的 URL(空的 URL 不會(huì)發(fā)生資源加載,但是會(huì)產(chǎn)生和這個(gè) iframe 中關(guān)聯(lián)的 history 不能被操作的問(wèn)題,這時(shí)路由的變換只支持 hash 模式),然后將其下的原生瀏覽器對(duì)象通過(guò) contentWindow取出來(lái)(因?yàn)?iframe 對(duì)象天然隔離,這里省去了自己 Mock 實(shí)現(xiàn)所有 API 的成本)。取出對(duì)應(yīng)的 iframe 中原生的對(duì)象之后,繼續(xù)對(duì)特定需要隔離的對(duì)象生成對(duì)應(yīng)的 Proxy,然后對(duì)一些屬性獲取和屬性設(shè)置,做一些特定的實(shí)現(xiàn)(比如 window.document 需要返回特定的沙箱 document 而不是當(dāng)前瀏覽器的document 等)。 為了文檔內(nèi)容能夠被加載在同一個(gè) DOM 樹上,對(duì)于 document,大部分的 DOM 操作的屬性和方法仍舊直接使用宿主瀏覽器中的 document 的屬性和方法處理等。
Web Worker 與 DOM 渲染
__WRAP_WORKER__(`/* 打包代碼 */ }`);
function __WRAP_WORKER__(appCode) {
var blob = new Blob([appCode]);
var appWorker = new Worker(window.URL.createObjectURL(blob));
}
出于線程安全設(shè)計(jì)考慮,Web Worker 不支持 DOM 操作,必須通過(guò) postMessage 通知 UI 主線程來(lái)實(shí)現(xiàn)。 Web Worker 無(wú)法訪問(wèn) window、document 之類的瀏覽器全局對(duì)象。
React Worker DOM
AMP WorkerDOM
const code = `
'use strict';
(function(){
${workerDOMScript}
self['window'] = self;
var workerDOM = WorkerThread.workerDOM;
WorkerThread.hydrate(
workerDOM.document,
${JSON.stringify(strings)},
${JSON.stringify(skeleton)},
${JSON.stringify(cssKeys)},
${JSON.stringify(globalEventHandlerKeys)},
[${window.innerWidth}, ${window.innerHeight}],
${JSON.stringify(localStorageInit)},
${JSON.stringify(sessionStorageInit)}
);
workerDOM.document[${TransferrableKeys.observe}](this);
Object.keys(workerDOM).forEach(function(k){self[k]=workerDOM[k]});
}).call(self);
${authorScript}
//# sourceURL=${encodeURI(config.authorURL)}`;
this[TransferrableKeys.worker] = new Worker(URL.createObjectURL(new Blob([code])));
小結(jié)與一些個(gè)人前瞻

評(píng)論
圖片
表情
