Web Worker 为 Web å
容å¨åå°çº¿ç¨ä¸è¿è¡èæ¬æä¾äºä¸ç§ç®åçæ¹æ³ã线ç¨å¯ä»¥æ§è¡ä»»å¡èä¸å¹²æ°ç¨æ·çé¢ãæ¤å¤ï¼å®ä»¬å¯ä»¥ä½¿ç¨ XMLHttpRequest
ï¼å°½ç®¡ responseXML
å channel
屿§æ»æ¯ä¸ºç©ºï¼æ fetch
ï¼æ²¡æè¿äºéå¶ï¼æ§è¡ I/Oã䏿¦å建ï¼ä¸ä¸ª worker å¯ä»¥å°æ¶æ¯åéå°å建å®ç JavaScript 代ç ï¼éè¿å°æ¶æ¯åå¸å°è¯¥ä»£ç æå®çäºä»¶å¤çå¨ï¼åä¹äº¦ç¶ï¼ã
æ¬æè¯¦ç»ä»ç»äºå¦ä½ä½¿ç¨ web workerã
Web Worker APIä¸ä¸ª worker æ¯ä½¿ç¨ä¸ä¸ªæé 彿°å建çä¸ä¸ªå¯¹è±¡ï¼ä¾å¦ Worker()
ï¼è¿è¡ä¸ä¸ªå½åç JavaScript æä»¶ââè¿ä¸ªæä»¶å
å«å°å¨ worker 线ç¨ä¸è¿è¡ç代ç ; worker è¿è¡å¨å¦ä¸ä¸ªå
¨å±ä¸ä¸æä¸ï¼ä¸åäºå½åçwindow
ãå æ¤ï¼å¨ Worker
å
éè¿ window
è·åå
¨å±ä½ç¨åï¼è䏿¯self
ï¼å°è¿åé误ã
å¨ä¸ç¨ worker çæ
åµä¸ï¼DedicatedWorkerGlobalScope
å¯¹è±¡ä»£è¡¨äº worker çä¸ä¸æï¼ä¸ç¨ worker æ¯ææ å worker ä»
å¨åä¸èæ¬ä¸è¢«ä½¿ç¨ï¼å
±äº« worker çä¸ä¸ææ¯ SharedWorkerGlobalScope
对象ï¼ãä¸ä¸ªä¸ç¨ worker ä»
è½è¢«é¦æ¬¡çæå®çèæ¬ä½¿ç¨ï¼èå
±äº« worker å¯ä»¥åæ¶è¢«å¤ä¸ªèæ¬ä½¿ç¨ã
夿³¨ï¼ åè§ Web Worker API è½å°é¡µä»¥è·å worker çåèææ¡£åæ´å¤æå¼ã
å¨ worker 线ç¨ä¸ä½ å¯ä»¥è¿è¡ä»»ä½ä½ 忬¢ç代ç ï¼ä¸è¿æä¸äºä¾å¤æ
åµãæ¯å¦ï¼å¨ worker å
ï¼ä¸è½ç´æ¥æä½ DOM èç¹ï¼ä¹ä¸è½ä½¿ç¨ window
对象çé»è®¤æ¹æ³å屿§ã使¯ä½ å¯ä»¥ä½¿ç¨å¤§é window
对象ä¹ä¸çä¸è¥¿ï¼å
æ¬ WebSocketsï¼ä»¥å IndexedDB çæ°æ®å卿ºå¶ãæ¥ç Web Worker å¯ä»¥ä½¿ç¨ç彿°åç±»è·å详æ
ã
workers å主线ç¨é´çæ°æ®ä¼ ééè¿è¿æ ·çæ¶æ¯æºå¶è¿è¡ââåæ¹é½ä½¿ç¨ postMessage()
æ¹æ³åéåèªçæ¶æ¯ï¼ä½¿ç¨ onmessage
äºä»¶å¤ç彿°æ¥ååºæ¶æ¯ï¼æ¶æ¯è¢«å
å«å¨ message
äºä»¶ç data 屿§ä¸ï¼ãè¿ä¸ªè¿ç¨ä¸æ°æ®å¹¶ä¸æ¯è¢«å
±äº«èæ¯è¢«å¤å¶ã
åªè¦è¿è¡å¨åæºçç¶é¡µé¢ä¸ï¼worker å¯ä»¥ä¾æ¬¡çææ°ç workerï¼å¹¶ä¸å¯ä»¥ä½¿ç¨ XMLHttpRequest
è¿è¡ç½ç» I/Oï¼ä½æ¯ XMLHttpRequest
ç responseXML
å channel
屿§æ»ä¼è¿å null
ã
å¦åææè¿°ï¼ä¸ä¸ªä¸ç¨ worker ä» è½è¢«çæå®çèæ¬æä½¿ç¨ãè¿ä¸é¨åå°æ¢è®¨ä¸ç¨ worker åºç¡ç¤ºä¾ï¼è¿è¡ä¸ç¨ workerï¼ä¸ç JavaScript 代ç ï¼å°ä½ è¾å ¥ç 2 个æ°åä½ä¹æ³ãè¾å ¥çæ°åä¼åéç»ä¸ä¸ªä¸ç¨ workerï¼ç±ä¸ç¨ worker ä½ä¹æ³åï¼åè¿åç»é¡µé¢è¿è¡å±ç¤ºã
è¿ä¸ªä¾åå¾å°ï¼ä½æ¯æä»¬å³å®å¨ä¿æç®åçåæ¶åä½ ä»ç»åºç¡ç worker æ¦å¿µãæ´å¤çç»èä¼å¨ä¹åçæç« ä¸è¿è¡è®²è§£ã
worker ç¹æ§æ£æµä¸ºäºæ´å¥½çé误å¤çæ§å¶ä»¥ååä¸å ¼å®¹ï¼å°ä½ ç worker è¿è¡ä»£ç å 裹å¨ä»¥ä¸ä»£ç 䏿¯ä¸ä¸ªå¾å¥½çæ³æ³ï¼main.jsï¼ï¼
if (window.Worker) {
// â¦
}
çæä¸ä¸ªä¸ç¨ worker
å建ä¸ä¸ªæ°ç worker å¾ç®åãä½ éè¦åçæ¯è°ç¨ Worker()
æé å¨ï¼æå®ä¸ä¸ªèæ¬ç URI æ¥æ§è¡ worker 线ç¨ï¼main.jsï¼ï¼
const myWorker = new Worker("worker.js");
ä¸ç¨ worker 䏿¶æ¯çæ¥æ¶ååé
ä½ å¯ä»¥éè¿ postMessage()
æ¹æ³å onmessage
äºä»¶å¤ç彿°è§¦å worker çæ¹æ³ãå½ä½ æ³è¦åä¸ä¸ª worker åéæ¶æ¯æ¶ï¼ä½ åªéè¦è¿æ ·åï¼main.jsï¼ï¼
first.onchange = () => {
myWorker.postMessage([first.value, second.value]);
console.log("Message posted to worker");
};
second.onchange = () => {
myWorker.postMessage([first.value, second.value]);
console.log("Message posted to worker");
};
è¿æ®µä»£ç ä¸åé first
å second
代表 2 个 <input>
å
ç´ ï¼å®ä»¬å½ä¸ä»»æä¸ä¸ªçå¼åçæ¹åæ¶ï¼myWorker.postMessage([first.value,second.value])
ä¼å°è¿ 2 个å¼ç»ææ°ç»åéç» workerãä½ å¯ä»¥å¨æ¶æ¯ä¸åé许å¤ä½ æ³åéçä¸è¥¿ã
å¨ worker 䏿¥æ¶å°æ¶æ¯åï¼æä»¬å¯ä»¥åè¿æ ·ä¸ä¸ªäºä»¶å¤ç彿°ä»£ç ä½ä¸ºååºï¼worker.jsï¼ï¼
onmessage = (e) => {
console.log("Message received from main script");
const workerResult = `Result: ${e.data[0] * e.data[1]}`;
console.log("Posting message back to main script");
postMessage(workerResult);
};
onmessage
å¤ç彿°å
许æä»¬å¨æ¶å°æ¶æ¯æ¶è¿è¡ä¸äºä»£ç ï¼æ¶æ¯æ¬èº«å¨ message
äºä»¶ data
屿§è¿è¡ä½¿ç¨ãè¿éæä»¬ç®åçå¯¹è¿ 2 个æ°åä½ä¹æ³å¤ç并忬¡ä½¿ç¨ postMessage()
æ¹æ³ï¼å°ç»æåä¼ ç»ä¸»çº¿ç¨ã
åå°ä¸»çº¿ç¨ï¼æä»¬åæ¬¡ä½¿ç¨ onmessage
以ååº worker åä¼ çæ¶æ¯ï¼
myWorker.onmessage = (e) => {
result.textContent = e.data;
console.log("Message received from worker");
};
å¨è¿éæä»¬è·åæ¶æ¯äºä»¶çæ°æ®ï¼å¹¶ä¸å°å®è®¾ç½®ä¸ºæ¾ç¤ºç»ææ®µè½ç textContent
ï¼æä»¥ç¨æ·å¯ä»¥ç´æ¥çå°è¿ç®çç»æã
夿³¨ï¼ å¨ä¸»çº¿ç¨ä¸ä½¿ç¨æ¶ï¼onmessage
å postMessage()
å¿
é¡»æå¨ worker
对象ä¸ï¼èå¨ worker ä¸ä½¿ç¨æ¶ä¸ç¨è¿æ ·åãåå æ¯ï¼å¨ worker å
é¨ï¼worker æ¯ææçå
¨å±ä½ç¨åã
夿³¨ï¼ å½ä¸ä¸ªæ¶æ¯å¨ä¸»çº¿ç¨å worker ä¹é´ä¼ éæ¶ï¼å®è¢«å¤å¶æè 转移äºï¼è䏿¯å ±äº«ã请åé worker 䏿°æ®çæ¥æ¶ä¸åéï¼è¯¦ç»ä»ç» è·åæ´è¯¦å°½çè§£éã
ç»æ¢ workerå¦æä½ éè¦ä»ä¸»çº¿ç¨ä¸ç«å»ç»æ¢ä¸ä¸ªè¿è¡ä¸ç workerï¼å¯ä»¥è°ç¨ worker ç terminate
æ¹æ³ï¼
worker 线ç¨ä¼è¢«ç«å³ç»æ¢ã
å¤çéè¯¯å½ worker åºç°è¿è¡ä¸é误æ¶ï¼å®ç onerror
äºä»¶å¤ç彿°ä¼è¢«è°ç¨ãå®ä¼æ¶å°ä¸ä¸ªæ©å±äº ErrorEvent
æ¥å£çå为 error
çäºä»¶ã
该äºä»¶ä¸ä¼å泡并ä¸å¯ä»¥è¢«åæ¶ï¼ä¸ºäºé²æ¢è§¦åé»è®¤å¨ä½ï¼worker å¯ä»¥è°ç¨é误äºä»¶ç preventDefault()
æ¹æ³ã
é误äºä»¶æä»¥ä¸ä¸ä¸ªç¨æ·å ³å¿çåæ®µï¼
message
å¯è¯»æ§è¯å¥½çéè¯¯æ¶æ¯ã
filename
åçé误çèæ¬æä»¶åã
lineno
åçéè¯¯æ¶æå¨èæ¬æä»¶çè¡å·ã
妿éè¦çè¯ï¼worker è½å¤çææ´å¤ç workerï¼è¿å°±æ¯æè°ç subworkerï¼å®ä»¬å¿ é¡»æç®¡å¨åæºçç¶é¡µé¢å ãèä¸ï¼subworker è§£æ URI æ¶ä¼ç¸å¯¹äºç¶ worker çå°åè䏿¯èªèº«é¡µé¢çå°åãè¿ä½¿å¾ worker æ´å®¹æè®°å½å®ä»¬ä¹é´çä¾èµå ³ç³»ã
å¼å ¥èæ¬ä¸åºWorker 线ç¨è½å¤è®¿é®ä¸ä¸ªå
¨å±å½æ° importScripts()
æ¥å¼å
¥èæ¬ï¼è¯¥å½æ°æ¥å 0 个æè
å¤ä¸ª URI ä½ä¸ºåæ°æ¥å¼å
¥èµæºï¼ä»¥ä¸ä¾å齿¯åæ³çï¼
importScripts(); /* ä»ä¹é½ä¸å¼å
¥ */
importScripts("foo.js"); /* åªå¼å
¥ "foo.js" */
importScripts("foo.js", "bar.js"); /* å¼å
¥ä¸¤ä¸ªèæ¬ */
importScripts("//example.com/hello.js"); /* ä½ å¯ä»¥ä»å
¶ä»æ¥æºå¯¼å
¥èæ¬ */
æµè§å¨å 载并è¿è¡æ¯ä¸ä¸ªååºçèæ¬ãæ¯ä¸ªèæ¬ä¸çå
¨å±å¯¹è±¡é½è½å¤è¢« worker 使ç¨ãå¦æèæ¬æ æ³å è½½ï¼å°æåº NETWORK_ERROR
å¼å¸¸ï¼æ¥ä¸æ¥ç代ç 乿 æ³æ§è¡ãèä¹åæ§è¡ç代ç ï¼å
æ¬ä½¿ç¨ setTimeout()
弿¥æ§è¡ç代ç ï¼ä¾ç¶è½å¤è¿è¡ãimportScripts()
ä¹åç彿°å£°æä¾ç¶ä¼è¢«ä¿çï¼å 为å®ä»¬å§ç»ä¼å¨å
¶ä»ä»£ç ä¹åè¿è¡ã
夿³¨ï¼ èæ¬çä¸è½½é¡ºåºä¸åºå®ï¼ä½æ§è¡æ¶ä¼æç
§ä¼ å
¥ importScripts()
ä¸çæä»¶å顺åºè¿è¡ãè¿ä¸ªè¿ç¨æ¯åæ¥å®æçï¼ç´å°ææèæ¬é½ä¸è½½å¹¶è¿è¡å®æ¯ï¼importScripts()
æä¼è¿åã
ä¸ä¸ªå ±äº« worker å¯ä»¥è¢«å¤ä¸ªèæ¬ä½¿ç¨ââå³ä½¿è¿äºèæ¬æ£å¨è¢«ä¸åç windowãiframe æè worker 访é®ãè¿ä¸é¨åï¼æä»¬ä¼è®¨è®ºå ±äº« worker åºç¡ç¤ºä¾ï¼è¿è¡å ±äº« workerï¼ä¸ç JavaScript 代ç ï¼è¯¥ç¤ºä¾ä¸ä¸ç¨ worker åºç¡ç¤ºä¾é常ç¸åï¼åªæ¯æ 2 个å¯ç¨å½æ°è¢«åæ¾å¨ä¸åèæ¬æä»¶ä¸ï¼ä¸¤æ°ç¸ä¹å½æ°ï¼ä»¥åæ±å¹³æ¹å½æ°ãè¿ä¸¤ä¸ªèæ¬ä½¿ç¨åä¸ä¸ª worker æ¥å®æå®é éè¦çè¿ç®ã
è¿éï¼æä»¬å ³æ³¨ä¸ä¸ä¸ç¨ worker åå ±äº« worker ä¹é´çåºå«ãå¨è¿ä¸ªç¤ºä¾ä¸æ 2 个 HTML 页é¢ï¼æ¯ä¸ªé¡µé¢æå å«ç JavaScript 代ç 使ç¨çæ¯åä¸ä¸ª workerã
夿³¨ï¼ å¦æå ±äº« worker å¯ä»¥è¢«å¤ä¸ªæµè§ä¸ä¸æè°ç¨ï¼ææè¿äºæµè§ä¸ä¸æå¿ é¡»å±äºåæºï¼ç¸åçåè®®ï¼ä¸»æºå端å£å·ï¼ã
夿³¨ï¼ å¨ Firefox ä¸ï¼å ±äº« worker ä¸è½è¢«ç§æåéç§æ window 对象ç document æå ±äº«ï¼Firefox bug 1177621ï¼ã
çæä¸ä¸ªå ±äº« workerçæä¸ä¸ªæ°çå ±äº« worker ä¸çæä¸ä¸ªä¸ç¨ worker é常ç¸ä¼¼ï¼åªæ¯æé å¨çååä¸åï¼æ¥ç index.html å index2.htmlï¼ââçæå ±äº« worker ç代ç å¦ä¸ï¼
const myWorker = new SharedWorker("worker.js");
ä¸ä¸ªé常大çåºå«å¨äºï¼ä¸ä¸ä¸ªå
±äº« worker éä¿¡å¿
é¡»éè¿ port
对象ââä¸ä¸ªç¡®åçæå¼ç端å£ä¾èæ¬ä¸ worker éä¿¡ï¼å¨ä¸ç¨ worker ä¸è¿ä¸é¨åæ¯éå¼è¿è¡çï¼ã
å¨ä¼ éæ¶æ¯ä¹åï¼ç«¯å£è¿æ¥å¿
须被æ¾å¼çæå¼ï¼æå¼æ¹å¼æ¯ä½¿ç¨ onmessage
äºä»¶å¤ç彿°æè
start()
æ¹æ³ãåªæä¸ç§æ
åµä¸éè¦è°ç¨ start()
æ¹æ³ï¼é£å°±æ¯ message
äºä»¶è¢« addEventListener()
æ¹æ³ä½¿ç¨ã
夿³¨ï¼ å¨ä½¿ç¨ start()
æ¹æ³æå¼ç«¯å£è¿æ¥æ¶ï¼å¦æç¶çº§çº¿ç¨å worker 线ç¨éè¦ååéä¿¡ï¼é£ä¹å®ä»¬é½éè¦è°ç¨è¯¥æ¹æ³ã
ç°å¨ï¼æ¶æ¯å¯ä»¥åä¹å飿 ·åéå° worker äºï¼ä½æ¯ postMessage()
æ¹æ³å¿
须被端å£å¯¹è±¡è°ç¨ï¼ä½ ä¼å䏿¬¡çå° multiply.js å square.js ä¸ç¸ä¼¼çç»æï¼ï¼
squareNumber.onchange = () => {
myWorker.port.postMessage([squareNumber.value, squareNumber.value]);
console.log("Message posted to worker");
};
åå° worker ä¸ï¼è¿é乿äºå¤æï¼worker.jsï¼:
onconnect = (e) => {
const port = e.ports[0];
port.onmessage = (e) => {
const workerResult = `Result: ${e.data[0] * e.data[1]}`;
port.postMessage(workerResult);
};
};
é¦å
ï¼å½ä¸ä¸ªç«¯å£è¿æ¥è¢«å建æ¶ï¼ä¾å¦ï¼å¨ç¶çº§çº¿ç¨ä¸ï¼è®¾ç½® onmessage
äºä»¶å¤ç彿°ï¼æè
æ¾å¼è°ç¨ start()
æ¹æ³æ¶ï¼ï¼ä½¿ç¨ onconnect
äºä»¶å¤ç彿°æ¥æ§è¡ä»£ç ã
使ç¨äºä»¶ç ports
屿§æ¥è·å端å£å¹¶åå¨å¨åéä¸ã
ç¶åï¼ä¸ºç«¯å£æ·»å ä¸ä¸ª onmessage
å¤ç彿°ç¨æ¥åè¿ç®å¹¶åä¼ ç»æç»ä¸»çº¿ç¨ãå¨ worker 线ç¨ä¸è®¾ç½®æ¤ onmessage
å¤ç彿°ä¹ä¼éå¼çæå¼ä¸ä¸»çº¿ç¨ç端å£è¿æ¥ï¼å æ¤è¿éè·åæä¸æ ·ï¼å¯¹ port.start()
çè°ç¨ä¹æ¯ä¸å¿
è¦çã
æåï¼åå°ä¸»èæ¬ï¼æä»¬å¤çæ¶æ¯ï¼ä½ ä¼å䏿¬¡çå° multiply.js å square.jsä¸ç¸ä¼¼çç»æï¼ï¼
myWorker.port.onmessage = (e) => {
result2.textContent = e.data;
console.log("Message received from worker");
};
å½ä¸æ¡æ¶æ¯éè¿ç«¯å£åå° workerï¼æä»¬å°è¿ç®ç»ææ¾å ¥ç»ææ®µè½ä¸åéçå°æ¹ã
å ³äºçº¿ç¨å®å ¨Worker
æ¥å£ä¼çæçæ£çæä½ç³»ç»çº§å«ç线ç¨ï¼å¦æä½ ä¸å¤ªå°å¿ï¼é£ä¹å¹¶åä¼å¯¹ä½ ç代ç 产çæè¶£çå½±åã
ç¶èï¼å¯¹äº web worker æ¥è¯´ï¼ä¸å ¶ä»çº¿ç¨çéä¿¡ç¹ä¼è¢«å¾å°å¿çæ§å¶ï¼è¿æå³çä½ å¾é¾å¼èµ·å¹¶åé®é¢ãä½ æ²¡æåæ³å»è®¿é®é线ç¨å®å ¨çç»ä»¶æè æ¯ DOMï¼æ¤å¤ä½ è¿éè¦éè¿åºåå对象æ¥ä¸çº¿ç¨äº¤äºç¹å®çæ°æ®ãæä»¥ä½ è¦æ¯ä¸è´¹ç¹å²å¿ï¼è¿çæä¸åºé误æ¥ã
å 容å®å ¨çç¥æå«äºå建å®ç document 对象ï¼worker æå®èªå·±çæ§è¡ä¸ä¸æãå æ¤æ®éæ¥è¯´ï¼worker å¹¶ä¸åéäºå建å®ç documentï¼æè ç¶çº§ workerï¼çå 容å®å ¨çç¥ãæä»¬æ¥ä¸¾ä¸ªä¾åï¼å设ä¸ä¸ª document æå¦ä¸å¤´é¨å£°æï¼
Content-Security-Policy: script-src 'self'
è¿ä¸ªå£°ææä¸é¨åä½ç¨å¨äºï¼ç¦æ¢å®å
é¨å
å«çèæ¬ä»£ç ä½¿ç¨ eval()
æ¹æ³ãç¶èï¼å¦æèæ¬ä»£ç å建äºä¸ä¸ª workerï¼å¨ worker ä¸ä¸æä¸æ§è¡ç代ç å´æ¯å¯ä»¥ä½¿ç¨ eval()
çã
为äºç» worker æå®å 容å®å ¨çç¥ï¼å¿ 须为åé worker 代ç çè¯·æ±æ¬èº«è®¾ç½® Content-Security-Policy ååºæ 头ã
æä¸ä¸ªä¾å¤æ åµï¼å³ worker èæ¬çæºå¦ææ¯ä¸ä¸ªå ¨å±æ§çå¯ä¸çæ è¯ç¬¦ï¼ä¾å¦ï¼å®ç URL å议为 data æ blobï¼ï¼worker åä¼ç»§æ¿å建å®ç document æè worker ç CSPã
worker 䏿°æ®çæ¥æ¶ä¸åéï¼è¯¦ç»ä»ç»å¨ä¸»é¡µé¢ä¸ worker ä¹é´ä¼ éçæ°æ®æ¯éè¿æ·è´ï¼è䏿¯å
±äº«æ¥å®æçãä¼ éç» worker
ç对象éè¦ç»è¿åºååï¼æ¥ä¸æ¥å¨å¦ä¸ç«¯è¿éè¦ååºååã页é¢ä¸ worker
ä¸ä¼å
±äº«åä¸ä¸ªå®ä¾ï¼æç»çç»æå°±æ¯å¨æ¯æ¬¡éä¿¡ç»ææ¶çæäºæ°æ®çä¸ä¸ªå¯æ¬ã大é¨åæµè§å¨ä½¿ç¨ç»æåå
鿥å®ç°è¯¥ç¹æ§ã
å¨å¾ä¸è¿è¡ä¹åï¼åºäºæå¦çç®çï¼è®©æä»¬å建ä¸ä¸ªå为 emulateMessage()
ç彿°ï¼å®å°æ¨¡æå¨ä» worker
å°ä¸»é¡µé¢ï¼åä¹äº¦ç¶ï¼çéä¿¡è¿ç¨ä¸ï¼åéçâæ·è´èéå
±äº«âè¡ä¸ºï¼
function emulateMessage(vVal) {
return eval(`(${JSON.stringify(vVal)})`);
}
// Tests
// test #1
const example1 = new Number(3);
console.log(typeof example1); // object
console.log(typeof emulateMessage(example1)); // number
// test #2
const example2 = true;
console.log(typeof example2); // boolean
console.log(typeof emulateMessage(example2)); // boolean
// test #3
const example3 = new String("Hello World");
console.log(typeof example3); // object
console.log(typeof emulateMessage(example3)); // string
// test #4
const example4 = {
name: "Carina Anand",
age: 43,
};
console.log(typeof example4); // object
console.log(typeof emulateMessage(example4)); // object
// test #5
function Animal(type, age) {
this.type = type;
this.age = age;
}
const example5 = new Animal("Cat", 3);
console.log(example5.constructor); // Animal
console.log(emulateMessage(example5).constructor); // Object
æ·è´èå¹¶éå
±äº«çé£ä¸ªå¼ç§°ä¸ºæ¶æ¯ï¼messageï¼ã忥è°è° worker
ï¼ä½ å¯ä»¥ä½¿ç¨ postMessage()
å°æ¶æ¯ä¼ éç»ä¸»çº¿ç¨æä»ä¸»çº¿ç¨ä¼ é忥ãmessage
äºä»¶ç data
屿§å°±å
å«äºä» worker ä¼ åæ¥çæ°æ®ã
example.htmlï¼ä¸»é¡µé¢ï¼ï¼
const myWorker = new Worker("my_task.js");
myWorker.onmessage = (event) => {
console.log(`Worker said : ${event.data}`);
};
myWorker.postMessage("ali");
my_task.jsï¼worker æä»¶ï¼ï¼
postMessage("I'm working before postMessage('ali').");
onmessage = (event) => {
postMessage(`Hi, ${event.data}`);
};
ç»æåå éç®æ³å¯ä»¥æ¥æ¶ JSON æ°æ®ä»¥åä¸äº JSON ä¸è½è¡¨ç¤ºçæ°æ®ââæ¯å¦å¾ªç¯å¼ç¨ã
ä¼ éæ°æ®çä¾å ä¾å 1ï¼ä¼ è¾ JSON çé«çº§æ¹å¼åå建ä¸ä¸ªäº¤æ¢ç³»ç»å¦æä½ éè¦ä¼ è¾éå¸¸å¤æçæ°æ®ï¼è¿è¦åæ¶å¨ä¸»é¡µä¸ Worker å è°ç¨å¤ä¸ªæ¹æ³ï¼é£ä¹å¯ä»¥èèå建ä¸ä¸ªç±»ä¼¼ä¸é¢çç³»ç»ã
é¦å
ï¼æä»¬å建ä¸ä¸ª QueryableWorker
çç±»ï¼å®æ¥æ¶ worker ç URLãä¸ä¸ªé»è®¤ä¾¦å¬å½æ°åä¸ä¸ªé误å¤ç彿°ä½ä¸ºåæ°ï¼è¿ä¸ªç±»å°ä¼è®°å½ææç侦å¬çå表并ä¸å¸®å©æä»¬ä¸ worker è¿è¡éä¿¡ã
function QueryableWorker(url, defaultListener, onError) {
const instance = this;
const worker = new Worker(url);
const listeners = {};
this.defaultListener = defaultListener ?? (() => {});
if (onError) {
worker.onerror = onError;
}
this.postMessage = (message) => {
worker.postMessage(message);
};
this.terminate = () => {
worker.terminate();
};
}
ç´§æ¥çï¼æä»¬ååºæ°å¢åå é¤ä¾¦å¬çæ¹æ³ã
this.addListeners = (name, listener) => {
listeners[name] = listener;
};
this.removeListeners = (name) => {
delete listeners[name];
};
è¿éæä»¬è®© worker å¤ç 2 ä¸ªè¿æ ·çç®åæä½ï¼åºå« 2 个æ°åå¹¶å¨ 3 ç§åå¼¹æ¡æç¤ºã为äºå®æè¿ä¸ªæä½ï¼æä»¬é¦å
å®ç°ä¸ä¸ª sendQuery
æ¹æ³ï¼è¯¥æ¹æ³å¯ä»¥æ¥è¯¢ worker æ¯å¦çæ£ææä»¬æéè¦çå¯¹åºæ¹æ³ã
// è¯¥å½æ°è³å°éè¦ä¸ä¸ªåæ°ï¼å³æä»¬æ³è¦æ¥è¯¢çæ¹æ³åç§°ã
// ç¶åæä»¬å¯ä»¥ä¼ å
¥æ¹æ³æéçåæ°ã
this.sendQuery = (queryMethod, ...queryMethodArguments) => {
if (!queryMethod) {
throw new TypeError(
"QueryableWorker.sendQuery takes at least one argument",
);
}
worker.postMessage({
queryMethod,
queryMethodArguments,
});
};
æä»¬ä»¥ onmessage
æ¹æ³ä½ä¸º QueryableWorker çç»å°¾ã妿 worker ææä»¬æéè¦ç对åºçæ¹æ³ï¼å®å°±ä¼è¿åç¸å¯¹åºç侦嬿¹æ³çåå以åæéè¦çåæ°ï¼æä»¬åªéè¦å¨ä¾¦å¬å表 listeners
䏿¾å°å®ï¼
worker.onmessage = (event) => {
if (
event.data instanceof Object &&
Object.hasOwn(event.data, "queryMethodListener") &&
Object.hasOwn(event.data, "queryMethodArguments")
) {
listeners[event.data.queryMethodListener].apply(
instance,
event.data.queryMethodArguments,
);
} else {
this.defaultListener.call(instance, event.data);
}
};
ç°å¨åå° worker ä¸ãé¦å æä»¬éè¦ä¸ä¸ªè½å¤å®æè¿ 2 个æä½çæ¹æ³ï¼
const queryableFunctions = {
getDifference(a, b) {
reply("printStuff", a - b);
},
waitSomeTime() {
setTimeout(() => {
reply("doAlert", 3, "seconds");
}, 3000);
},
};
function reply(queryMethodListener, ...queryMethodArguments) {
if (!queryMethodListener) {
throw new TypeError("reply - takes at least one argument");
}
postMessage({
queryMethodListener,
queryMethodArguments,
});
}
// å½ä¸»é¡µé¢ç´æ¥è°ç¨ QueryWorker ç postMessage æ¹æ³æ¶ï¼è¯¥æ¹æ³è¢«è°ç¨ã
function defaultReply(message) {
// åç¹ä»ä¹
}
onmessage
æ¹æ³ä¹å°±å¾ç®åäºï¼
onmessage = (event) => {
if (
event.data instanceof Object &&
Object.hasOwn(event.data, "queryMethod") &&
Object.hasOwn(event.data, "queryMethodArguments")
) {
queryableFunctions[event.data.queryMethod].apply(
self,
event.data.queryMethodArguments,
);
} else {
defaultReply(event.data);
}
};
æ¥ä¸æ¥ç»åºä¸ä¸ªå®æ´çå®ç°ï¼
example.htmlï¼ä¸»é¡µé¢ï¼ï¼
<!doctype html>
<html lang="en-US">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<title>MDN Example - Queryable worker</title>
<script type="text/javascript">
// QueryableWorker å®ä¾çæ¹æ³ï¼
// * sendQuery(queryable function name, argument to pass 1, argument to pass 2, etc. etc.): è°ç¨ä¸ä¸ª Worker ç坿¥è¯¢å½æ°
// * postMessage(string or JSON Data): è§ Worker.prototype.postMessage()
// * terminate(): ç»æ¢ Worker
// * addListener(name, function): æ·»å ä¸ä¸ªçå¬å¨
// * removeListener(name): ç§»é¤ä¸ä¸ªçå¬å¨
// QueryableWorker å®ä¾ç屿§ï¼
// * defaultListener: é»è®¤çå¬å¨åªå¨ Worker ç´æ¥è°ç¨ postMessage() 彿°æ¶æ§è¡
function QueryableWorker(url, defaultListener, onError) {
const instance = this;
const worker = new Worker(url);
const listeners = {};
this.defaultListener = defaultListener ?? (() => {});
if (onError) {
worker.onerror = onError;
}
this.postMessage = (message) => {
worker.postMessage(message);
};
this.terminate = () => {
worker.terminate();
};
this.addListener = (name, listener) => {
listeners[name] = listener;
};
this.removeListener = (name) => {
delete listeners[name];
};
// è¿ä¸ªå½æ°è³å°éè¦ä¸ä¸ªåæ°ï¼å³æä»¬æ³è¦æ¥è¯¢çæ¹æ³åç§°ã
// ç¶åæä»¬å¯ä»¥ä¼ å
¥æ¹æ³æéçåæ°ã
this.sendQuery = (queryMethod, ...queryMethodArguments) => {
if (!queryMethod) {
throw new TypeError(
"QueryableWorker.sendQuery takes at least one argument",
);
}
worker.postMessage({
queryMethod,
queryMethodArguments,
});
};
worker.onmessage = (event) => {
if (
event.data instanceof Object &&
Object.hasOwn(event.data, "queryMethodListener") &&
Object.hasOwn(event.data, "queryMethodArguments")
) {
listeners[event.data.queryMethodListener].apply(
instance,
event.data.queryMethodArguments,
);
} else {
this.defaultListener.call(instance, event.data);
}
};
}
// ä½ èªå®ä¹ç "queryable" worker
const myTask = new QueryableWorker("my_task.js");
// ä½ èªå®ä¹ç "listeners"
myTask.addListener("printStuff", (result) => {
document
.getElementById("firstLink")
.parentNode.appendChild(
document.createTextNode(`The difference is ${result}!`),
);
});
myTask.addListener("doAlert", (time, unit) => {
alert(`Worker waited for ${time} ${unit} :-)`);
});
</script>
</head>
<body>
<ul>
<li>
<a
id="firstLink"
href="javascript:myTask.sendQuery('getDifference', 5, 3);"
>What is the difference between 5 and 3?</a
>
</li>
<li>
<a href="javascript:myTask.sendQuery('waitSomeTime');"
>Wait 3 seconds</a
>
</li>
<li>
<a href="javascript:myTask.terminate();">terminate() the Worker</a>
</li>
</ul>
</body>
</html>
my_task.jsï¼worker æä»¶ï¼ï¼
const queryableFunctions = {
// ç¤ºä¾ 1ï¼å¾å°ä¸¤ä¸ªæ°åçå·®å¼ï¼
getDifference(minuend, subtrahend) {
reply("printStuff", minuend - subtrahend);
},
// ç¤ºä¾ 2ï¼çå¾
ä¸ç§
waitSomeTime() {
setTimeout(() => {
reply("doAlert", 3, "seconds");
}, 3000);
},
};
// ç³»ç»å½æ°
function defaultReply(message) {
// ä½ çé»è®¤ PUBLIC 彿°åªå¨ä¸»é¡µé¢ç´æ¥è°ç¨ queryableWorker.postMessage() æ¹æ³æ¶æ§è¡ã
// åç¹ä»ä¹
}
function reply(queryMethodListener, ...queryMethodArguments) {
if (!queryMethodListener) {
throw new TypeError("reply - not enough arguments");
}
postMessage({
queryMethodListener,
queryMethodArguments,
});
}
onmessage = (event) => {
if (
event.data instanceof Object &&
Object.hasOwn(event.data, "queryMethod") &&
Object.hasOwn(event.data, "queryMethodArguments")
) {
queryableFunctions[event.data.queryMethod].apply(
self,
event.data.queryMethodArguments,
);
} else {
defaultReply(event.data);
}
};
è¿ä¸ªå®ä¾ä¸ï¼å¯ä»¥å¯¹ä»ä¸»é¡µé¢å° workerã以å worker å°ä¸»é¡µé¢ä¹é´ä¼ éçæ¶æ¯å
容è¿è¡åæ¢ãèä¸å±æ§å "queryMethod"ã"queryMethodListeners" å "queryMethodArguments" å¯ä»¥æ¯ä»»ä½ä¸è¥¿ï¼åªè¦å®ä»¬å¨ QueryableWorker
å worker
ä¸ä¿æä¸è´ã
ç°ä»£æµè§å¨å å«å¦ä¸ç§æ§è½æ´é«çæ¹æ³æ¥å°ç¹å®ç±»åçå¯¹è±¡ä¼ éç»ä¸ä¸ª worker æä» worker ä¼ åãå¯è½¬ç§»å¯¹è±¡ä»ä¸ä¸ªä¸ä¸æè½¬ç§»å°å¦ä¸ä¸ªä¸ä¸æèä¸ä¼ç»è¿ä»»ä½æ·è´æä½ãè¿æå³çå½ä¼ é大忰æ®éæ¶ä¼è·å¾æå¤§çæ§è½æåã
ä¾å¦ï¼å½ä½ å°ä¸ä¸ª ArrayBuffer
对象ä»ä¸»åºç¨è½¬è®©å° Worker ä¸ï¼åå§ç ArrayBuffer
被æ¸
é¤å¹¶ä¸æ æ³ä½¿ç¨ãå®å
å«çå
容ä¼ï¼å®æ´æ å·®çï¼ä¼ éç» Worker ä¸ä¸æã
// å建ä¸ä¸ª 32MB çâæä»¶âï¼ç¨ä» 0 å° 255 çè¿ç»æ°å¼å¡«å
å®ââ32MB = 1024 * 1024 * 32
const uInt8Array = new Uint8Array(1024 * 1024 * 32).map((v, i) => i);
worker.postMessage(uInt8Array.buffer, [uInt8Array.buffer]);
夿³¨ï¼ è·åæ´å¤è¯¥æ¹æ³ç¸å ³çå¯è½¬è®©å¯¹è±¡ãæ§è½åç¹æ§æ£æµçæ¹æ³ï¼è¯·åé HTML5 Rocks ä¸çTransferable Objects: Lightning Fast! ã
åµå ¥å¼ workerç®å没æä¸ç§â宿¹âçæ¹æ³è½å¤å <script>
å
ç´ ä¸æ ·å° worker ç代ç åµå
¥å°ç½é¡µä¸ã使¯å¦æä¸ä¸ª <script>
å
ç´ æ²¡æ src
屿§ï¼å¹¶ä¸å®ç type
屿§æ²¡ææå®æä¸ä¸ªå¯è¿è¡ç MIME typeï¼é£ä¹å®å°±ä¼è¢«è®¤ä¸ºæ¯ä¸ä¸ªæ°æ®åå
ç´ ï¼å¹¶ä¸è½å¤è¢« JavaScript 使ç¨ãâæ°æ®åâæ¯ HTML5 ä¸ä¸ä¸ªåå常è§çç¹æ§ï¼å®å¯ä»¥æºå¸¦å ä¹ä»»ä½ææ¬ç±»åçæ°æ®ãæä»¥ï¼ä½ è½å¤ä»¥å¦ä¸æ¹å¼åµå
¥ä¸ä¸ª workerï¼
<!doctype html>
<html lang="en-US">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<title>MDN Example - Embedded worker</title>
<script type="text/js-worker">
// è¯¥èæ¬ä¸ä¼è¢« JS å¼æè§£æï¼å 为å®ç mime-type æ¯ text/js-workerã
const myVar = 'Hello World!';
// å©ä¸ç worker 代ç åå°è¿éã
</script>
<script>
// è¯¥èæ¬ä¼è¢« JS å¼æè§£æï¼å 为å®ç mime-type æ¯ text/javascriptã
function pageLog(sMsg) {
// ä½¿ç¨ fragmentï¼è¿æ ·æµè§å¨åªä¼è¿è¡ä¸æ¬¡æ¸²æ/éæã
const frag = document.createDocumentFragment();
frag.appendChild(document.createTextNode(sMsg));
frag.appendChild(document.createElement("br"));
document.querySelector("#logDisplay").appendChild(frag);
}
</script>
<script type="text/js-worker">
// è¯¥èæ¬ä¸ä¼è¢« JS å¼æè§£æï¼å 为å®ç mime-type æ¯ text/js-workerã
onmessage = (event) => {
postMessage(myVar);
};
// å©ä¸ç worker 代ç åå°è¿éã
</script>
<script>
// è¯¥èæ¬ä¼è¢« JS å¼æè§£æï¼å 为å®ç mime-type æ¯ text/javascriptã
// è¿å»åå¨ blob builderï¼ä½ç°å¨æä»¬ä½¿ç¨ Blob
const blob = new Blob(
Array.prototype.map.call(
document.querySelectorAll("script[type='text\/js-worker']"),
(script) => script.textContent,
{ type: "text/javascript" },
),
);
// å建ä¸ä¸ªæ°ç document.worker 屿§ï¼å
嫿æ "text/js-worker" èæ¬ã
document.worker = new Worker(window.URL.createObjectURL(blob));
document.worker.onmessage = (event) => {
pageLog(`Received: ${event.data}`);
};
// å¯å¨ workerã
window.onload = () => {
document.worker.postMessage("");
};
</script>
</head>
<body>
<div id="logDisplay"></div>
</body>
</html>
ç°å¨ï¼åµå
¥å¼ worker å·²ç»åµå¥è¿äºä¸ä¸ªèªå®ä¹ç document.worker
屿§ä¸ã
è¿æ ·ä¹ä¸è¶³ä¸ºå¥ï¼ä½ ä»ç¶å¯ä»¥å°ä¸ä¸ªå½æ°è½¬æ¢ä¸º blobï¼ç¶å为è¿ä¸ª blob çæ URL å¯¹è±¡ãæ¯å¦ï¼
function fn2workerURL(fn) {
const blob = new Blob([`(${fn.toString()})()`], { type: "text/javascript" });
return URL.createObjectURL(blob);
}
æ´å¤ç¤ºä¾
æ¬èæä¾äºå 个å¦ä½ä½¿ç¨ web worker çä¾åã
å¨åå°æ§è¡è¿ç®worker çä¸ä¸ªä¼å¿å¨äºè½å¤æ§è¡å¤çå¨å¯éåçè¿ç®èä¸ä¼é»å¡ UI 线ç¨ãå¨ä¸é¢çä¾åä¸ï¼worker ç¨äºè®¡ç®ææ³¢é£å¥æ°ã
JavaScript 代ç ä¸é¢ç JavaScript 代ç ä¿åå¨âfibonacci.jsâæä»¶ä¸ï¼ä¸ä¸ä¸èç HTML æä»¶å ³èã
self.onmessage = (e) => {
const userNum = Number(e.data);
fibonacci(userNum);
};
function fibonacci(num) {
let a = 1;
let b = 0;
while (num >= 0) {
[a, b] = [a + b, a];
num--;
}
self.postMessage(b);
}
worker å°å±æ§ onmessage
设置为ä¸ä¸ªå½æ°ï¼å½ worker 对象è°ç¨ postMessage()
æ¶è¯¥å½æ°ä¼æ¥æ¶å°åéè¿æ¥çä¿¡æ¯ï¼æ³¨æï¼è¿ä¹ä½¿ç¨å¹¶ä¸çåå®ä¹ä¸ä¸ªååç彿°ãvar onmessage
ãlet onmessage
ä¸ function onmessage
å°ä¼å®ä¹ä¸è¯¥ååç¸åçå
¨å±å±æ§ï¼ä½æ¯å®ä»¬ä¸ä¼æ³¨åè½å¤æ¥æ¶ä»å建 worker çç½é¡µåéè¿æ¥çæ¶æ¯ç彿°ï¼ãè¿å°æ§è¡æ°å¦è¿ç®ï¼å¹¶æç»å°ç»æè¿åå°ä¸»çº¿ç¨ã
<!doctype html>
<html lang="en-US">
<head>
<meta charset="UTF-8" />
<title>Fibonacci number generator</title>
<style>
body {
width: 500px;
}
div,
p {
margin-bottom: 20px;
}
</style>
</head>
<body>
<form>
<div>
<label for="number"
>Enter a number that is an index position in the fibonacci sequence to
see what number is in that position (e.g. enter 5 and you'll get a
result of 8 â fibonacci index position 5 is 8).</label
>
<input type="number" id="number" />
</div>
<div>
<input type="submit" />
</div>
</form>
<p id="result"></p>
<script>
const form = document.querySelector("form");
const input = document.querySelector('input[type="number"]');
const result = document.querySelector("p#result");
const worker = new Worker("fibonacci.js");
worker.onmessage = (event) => {
result.textContent = event.data;
console.log(`Got: ${event.data}`);
};
worker.onerror = (error) => {
console.log(`Worker error: ${error.message}`);
throw error;
};
form.onsubmit = (e) => {
e.preventDefault();
worker.postMessage(input.value);
input.value = "";
};
</script>
</body>
</html>
ç½é¡µå建äºä¸ä¸ª ID 为 result
çç¨äºæ¾ç¤ºè¿ç®ç»æç <div>
å
ç´ ï¼ç¶åçæ workerãå¨çæ worker åï¼onmessage
å¤ç彿°é
置为éè¿è®¾ç½® div
å
ç´ çå
å®¹æ¥æ¾ç¤ºè¿ç®ç»æï¼ç¶å onerror
å¤ç彿°è¢«è®¾ç½®ä¸ºå°éè¯¯æ¶æ¯è®°å½å° devtools æ§å¶å°ã
æåï¼å worker åé䏿¡æ¶æ¯æ¥å¯å¨å®ã
ååä»»å¡ç»å¤ä¸ª workerå½å¤æ ¸ç³»ç»æµè¡å¼æ¥ï¼å°å¤æçè¿ç®ä»»å¡åé ç»å¤ä¸ª worker æ¥è¿è¡å·²ç»åå¾ååæç¨ï¼è¿äº worker ä¼å¨å¤å¤çå¨å æ ¸ä¸è¿è¡è¿äºä»»å¡ã
å ¶ä»ç±»åç workeré¤äºä¸ç¨åå ±äº«ç web workerï¼è¿æä¸äºå ¶ä»ç±»åç workerï¼
大夿°æµè§å¨é½å è®¸ä½ å¨ JavaScript è°è¯å¨ä¸è°è¯ Web Workerï¼å ¶æ¹å¼ä¸è°è¯ä¸»çº¿ç¨å®å ¨ç¸åï¼ä¾å¦ï¼Firefox å Chrome é½ååºäºä¸»çº¿ç¨åæ´»å¨ worker 线ç¨ç JavaScript æºæä»¶ï¼ææè¿äºæä»¶é½å¯ä»¥æå¼ä»¥è®¾ç½®æç¹åæ¥å¿ç¹ã
è¦äºè§£å¦ä½è°è¯ Web Workerï¼è¯·åé æ¯ä¸ªæµè§å¨ç JavaScript è°è¯å¨çææ¡£ï¼
worker ä¸å¯ç¨ç彿°åæ¥å£ä½ å¯ä»¥å¨ web worker ä¸ä½¿ç¨å¤§å¤æ°çæ å JavaScript ç¹æ§ï¼å æ¬ï¼
Navigator
fetch()
Array
ãDate
ãMath
å String
setTimeout()
å setInterval()
å¨ä¸ä¸ª worker 䏿䏻è¦çä½ ä¸è½åçäºæ
å°±æ¯ç´æ¥å½±åç¶é¡µé¢ãå
æ¬æä½ç¶é¡µé¢çèç¹ä»¥å使ç¨é¡µé¢ä¸ç对象ãä½ åªè½é´æ¥å°å®ç°ï¼éè¿ DedicatedWorkerGlobalScope.postMessage
åä¼ æ¶æ¯ç»ä¸»èæ¬ï¼ç¶åä»ä¸»èæ¬é£éæ§è¡æä½æååã
夿³¨ï¼ ä½ å¯ä»¥ä½¿ç¨ç½ç«æµè¯ä¸ä¸ªæ¹æ³æ¯å¦å¯¹ worker å¯ç¨ï¼https://worker-playground.glitch.me/ãä¾å¦ï¼å¦æä½ å¨ Firefox 84 çç½ç«ä¸è¾å
¥ EventSource
ï¼ä½ ä¼åç°å¨ service worker 䏿¯æè¿ä¸ªæ¹æ³ï¼ä½å¨ä¸ç¨åå
±äº« worker 䏿¯æã
夿³¨ï¼ è·å worker ä¸å®æ´çæ¹æ³å表ï¼è¯·åé worker å¯ç¨çæ¹æ³åæ¥å£ã
è§è åè§RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4