1. 背景
目前公司系統(tǒng)首頁存在一個定時的輪詢請求/Admin/Dashboard/GetAppRelaseNotice
,包含一些需要實時反映在前端的操作(如:頁面版本,站內(nèi)信,頁面配置更新等)
問題很明顯,單個頁面的情況下,每分鐘會發(fā)送一次請求;
但如果同時打開多個tab,每個tab每分鐘都會發(fā)送一次請求
2. 思路
針對這個情況,可以使用 SharedWorker + BroadcastChannel 來實現(xiàn)多個tab共用一個后臺任務(wù)的情況,減少后端服務(wù)器壓力的同時也可以提升部分前端的性能;
SharedWorker:接口代表一種特定類型的 worker,可以從幾個瀏覽上下文中訪問。
BroadcastChannel:接口代理了一個命名頻道。它允許同源的不同瀏覽器窗口下的不同文檔之間相互通信。
- 使用
SharedWorker
將請求任務(wù)移至后臺輪詢,多頁面共享 - 通過
BroadcastChannel
通知所有頁面請求結(jié)果 - 兼容不支持
SharedWorker
的瀏覽器
3. 編碼
3.1 使用SharedWorker將請求任務(wù)移至后臺輪詢,多頁面共
建立一個后臺任務(wù)js文件 GetAppRelaseNotice.js
onconnect = function (e) {
checkAppReleaseCallBack();
setInterval(checkAppReleaseCallBack, 1000 * 1); //先設(shè)置1秒鐘,用于測試
}
function checkAppReleaseCallBack() {
// 這里請求 GetAppRelaseNotice 接口獲取返回值
}
頁面啟動后臺任務(wù)
function startCheckAppRelease() {
// 給后臺任務(wù)一個名字 GetAppRelaseNotice 后面用于調(diào)試
const worker = new SharedWorker('/Scripts/Workers/GetAppRelaseNotice.js', "GetAppRelaseNotice");
worker.port.start();
}
3.2 通過BroadcastChannel通知所有頁面請求結(jié)果
// 后臺任務(wù)js
const broadcast = new BroadcastChannel('LinkMore:GetAppRelaseNotice');
broadcast.postMessage(data); //發(fā)送廣播數(shù)據(jù)
// 頁面js,訂閱廣播
const broadcast = new BroadcastChannel('LinkMore:GetAppRelaseNotice');
broadcast.onmessage = (msg) => {
const data = msg.data; // 獲取廣播數(shù)據(jù)
};
3.3 兼容不支持 SharedWorker 的瀏覽器
// 檢測應(yīng)用發(fā)版通知
function startCheckAppRelease() {
if (typeof window.SharedWorker === "undefined") { // 如果不存在則沿用老的邏輯
checkAppReleaseCallBack();
setInterval(checkAppReleaseCallBack, 1000 * 60);
} else {
// 這里處理 SharedWorker
}
}
4. 完整代碼
GetAppRelaseNotice.js
let timer;
onconnect = function (e) {
checkAppReleaseCallBack();
clearInterval(timer);
timer = setInterval(checkAppReleaseCallBack, 1000 * 60);
}
// 創(chuàng)建廣播對象
const broadcast = new BroadcastChannel('LinkMore:GetAppRelaseNotice');
function checkAppReleaseCallBack() {
fetch("/Admin/Dashboard/GetAppRelaseNotice", { method: "POST" })
.then(r => r.text())
.then(JSON.parse)
.then(r => broadcast.postMessage(r));
}
頁面代碼
function startCheckAppRelease() {
if (typeof window.SharedWorker === "undefined") {
checkAppReleaseCallBack();
setInterval(checkAppReleaseCallBack, 1000 * 60);
} else {
const worker = new SharedWorker('/Scripts/Workers/GetAppRelaseNotice.js', "GetAppRelaseNotice");
worker.port.start();
// 訂閱廣播消息
const broadcast = new BroadcastChannel('LinkMore:GetAppRelaseNotice');
broadcast.onmessage = msg => {
const rst = msg.data; // 獲取廣播數(shù)據(jù)
doAppReleaseCallBack(rst);
};
}
}
function checkAppReleaseCallBack() {
$.post("/Admin/Dashboard/GetAppRelaseNotice", function (rst) {
checkAppReleaseCallBack(rst);
})
}
function doAppReleaseCallBack(rst) {
// 業(yè)務(wù)邏輯不變
if (rst.result == 0 && rst.data != "" && rst.data != null) {
document.querySelector("#ReleaseNotice").stop();
$("#ReleaseNotice").show();
$("#ReleaseNotice").html(rst.data);
document.querySelector("#ReleaseNotice").start();
} else {
$("#ReleaseNotice").hide();
}
}
5. 調(diào)試
瀏覽器輸入:chrome://inspect
多個頁面都可以收到消息,但后臺任務(wù)只發(fā)一次請求
所有頁面關(guān)閉后任務(wù)會自動停止