首頁 > 軟體

在web worker中使用fetch範例詳解

2022-11-17 14:00:58

1.Web Worker意義

由於 JS 是單執行緒的,費時的 JS 操作將會導致整個頁面的阻塞。Web Worker 提供了建立多執行緒的方法,將一些耗時且 UI 無關的工作交給 worker,可提高頁面的使用體驗。

限制:

同源策略:worker 執行緒執行的指令碼要和當前頁面同源

API 限制:

  • 不能操作 DOM
  • 不能使用 window 的全域性變數,但可以使用 navigator 和 location 物件
  • 不能使用 alert、confirm 方法
  • 無法讀取本地檔案

和主執行緒不在一個上下文環境,通訊要通過 postMessage 完成

2. 主執行緒的使用

建立

建立一個子執行緒,要傳入一個指令碼的 URL。如果該指令碼載入失敗,則 Worker 會靜默失敗

const worker = new Worker('url');

如果要在本檔案中描述執行的內容,可以用 Blob 和 window.URL.createObjectURL 生成一個 URL

function createWorker(f) {
  const blob = new Blob(['(' + f.toString() +')()']);
  const url = window.URL.createObjectURL(blob);
  const worker = new Worker(url);
  return worker;
}

通訊

  • 主執行緒 => 子執行緒
worker.postMessage(param);

引數可以是任意型別,包括二進位制資料。但傳遞是拷貝形式而不是參照形式。因此對於巨量資料會存在效能問題。

  • 子執行緒 => 主執行緒
worker.onmessage = function (event) {
  console.log('Received message ' + event.data);
}

錯誤處理

worker.onerror(function (e) {
  console.log([
    'ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message
  ].join(''));
});

關閉

worker.terminate();

3. 子執行緒的使用

子執行緒中無法使用 window,self 代表全域性物件

和主執行緒的通訊

  • 主執行緒 => 子執行緒
self.addEventListener('message', function (e) {
  self.postMessage('Received: ' + e.data);
}, false);
  • 子執行緒 => 主執行緒
self.postMessage('something');

載入其他指令碼

在子執行緒中載入其他指令碼:

importScripts('script1.js', 'script2.js');

關閉

self.close();

4. 在WebWorker中使用fetch

網路請求是和DOM無關且可能耗時較長的操作,worker執行緒支援使用Fetch,是適合放在worker中進行的操作。

而要在worker中使用fetch,如果每次都要自己處理執行緒間的通訊的話,會十分麻煩,因此我對通訊進行了封裝,寫成了一個可以直接使用的庫

安裝依賴:

npm i web-worker-fetch

使用時先範例化一個WF物件,然後就可以像使用fetch一樣在worker中使用fetch:

import WebWorkerFetch from "web-worker-fetch";
const wf = new WebWorkerFetch();
wf.fetch("url", {
  method: "POST", // *GET, POST, PUT, DELETE, etc.
  mode: "cors", // no-cors, *cors, same-origin
  cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
  credentials: "same-origin", // include, *same-origin, omit
  headers: {
    "Content-Type": "application/json"
    // 'Content-Type': 'application/x-www-form-urlencoded',
  },
  redirect: "follow", // manual, *follow, error
  referrerPolicy: "no-referrer", // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
  body: JSON.stringify(data) // body data type must match "Content-Type" header
}).then((res) => console.log(res));

除此之外,借鑑 axios 的思路,設定中可以提供 requestInterceptorresponseInterceptor,對請求引數和返回資料做統一處理

5. 實現思路

這個庫的封裝主要是解決了兩個問題:

  • 傳送請求時如何把引數傳遞給worker執行緒
  • 請求結束後如何從worker執行緒獲取結果

對於第一個問題,主執行緒使用 ostMessage 向worker執行緒傳遞引數。

對於第二個問題,worker執行緒通過 self.postMessage 向主執行緒傳遞訊息,主執行緒通過 worker.onmessage 監聽訊息。

此時就引出了問題所在:如果多次使用 wf.fetch 傳送請求,那麼在一個請求完成後,worker執行緒觸發的訊息將讓所有請求處都認為請求已完成。

因此,在每次請求時,使用一個fetchId確定該請求做唯一性。將該id傳給worker執行緒,後續worker執行緒向主執行緒通訊時也會帶上這個id。

在主執行緒中監聽onmessage事件時,判斷id是否和自己的請求id一致,只有在相同時才做處理。

具體的實現大家可以移步倉庫原始碼,實際上也非常簡單。

以上就是在web worker中使用fetch範例詳解的詳細內容,更多關於web worker使用fetch的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com