Service Worker skipWaiting 无法激活当前等待的 SW
Service Worker skipWaiting unable to activate currently waiting SW
描述:
我们使用 sw precache 预先缓存脚本,因此要更新我们提供重新加载选项的脚本,
为此,我们正在收听 worker 消息以跳过等待新安装的 service worker,原因不明,我们没有得到正确的
importScript
// GETTING OLD SW reference (self) and NOT getting newly installed SW reference
self.addEventListener('message', function(event) {
*// not working*
self.skipWaiting();
});
// But if we put skipWaiting() in 'install' listener
// it is getting correct new SW reference and working correctly
self.addEventListener('install', function(event) {
// self.skipWaiting();
});
软件注册
if('serviceWorker' in window.navigator) {
window.addEventListener('load', function() {
window.navigator.serviceWorker.register("/serviceWorker.js").then(function(registration) {
console.log("ServiceWorker registration successful with scope: ", registration);
registration.onupdatefound = function() {
console.log('NEW WILD WORKER HAS SPAWNED.!', registration);
var installedWorker = registration.installing;
installedWorker.onstatechange = function() {
if (installedWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
console.log('Updated content is available RELOAD!', navigator.serviceWorker.controller);
var el = document.getElementById('feature');
el.style['display'] = 'block';
}
}
}
}
}).catch(function(error) {
console.error("ServiceWorker registration failed: ", error);
});
});
window.navigator.serviceWorker.addEventListener('controllerchange', function() {
console.log('SERVICE WORKER UPDATED');
});
}
webpack 配置
new SWPrecacheWebpackPlugin({
cacheId: 'pwa',
filename: 'serviceWorker.js',
staticFileGlobsIgnorePatterns: [/\.map$/, /\.json$/, /_nch\.[0-9a-z]+\.[js, css]+/g, /webpackManifest\.[0-9a-z]+\.js/g, /.DS_Store\.[0-9a-z]+/g],
importScripts: ['offline/offline.1a2b3c4df1.js'],
dontCacheBustUrlsMatching: /./,
minify: false,
skipWaiting: false,
runtimeCaching: [ {
urlPattern: /_nch\.[0-9a-z]+\.[js, css]+/g,
handler: 'fastest',
options: {
cache: {
name: 'jd-internal-script',
maxEntries: 10,
},
},
}, {
urlPattern: /webpackManifest\.[0-9a-z]+\.js/g,
handler: 'networkFirst',
options: {
cache: {
name: 'jd-root-doc',
},
},
}],
}),
所以这就是我的想法...
您的新服务人员仍在等待..因此事件侦听器仍在您的旧服务人员上..您发送的任何消息仍将被旧的 sw 捕获(因为新的正在等待)。
如果您唯一的情况是让新软件生效,您可以简单地刷新页面而不是发送消息
skipWaiting()
的最佳文档可以在 https://developers.google.com/web/fundamentals/instant-and-offline/service-worker/lifecycle#skip_the_waiting_phase
找到
您可以在 install
处理程序中无条件地调用它,或者按照您似乎正在做的模型,即监听 message
事件并调用 skipWaiting()
有条件地。
如果你走条件路线,那么你应该修改你的客户端页面的代码以正确检测你注册的服务工作者何时进入 waiting
状态,并为用户提供与以导致相应 postMessage()
的方式告诉服务工作者 skipWaiting()
的页面。根据您所说的,您已经尝试过了,但看起来您将消息发送到了错误的服务工作者实例。
页面代码应如下所示:
// On your page:
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('service-worker.js').then(function(reg) {
reg.onupdatefound = function() {
var newSW = reg.installing;
newSW.onstatechange = function() {
if (newSW.state === 'waiting') {
// This assumes there's a button with id='skip-waiting-button' that
// users should click to get the new SW to activate immediately.
var button = document.querySelector('#skip-waiting-button');
button.addEventListener('click', function() {
newSW.postMessage('skipWaiting');
});
// Assume that 'display' is 'none' initially.
button.style.display = 'inline';
}
// Handle whatever other SW states you care about, like 'active'.
};
};
})
});
}
// In your service worker:
self.addEventListener('message', event => {
if (event.data === 'skipWaiting') {
self.skipWaiting();
}
});
描述:
我们使用 sw precache 预先缓存脚本,因此要更新我们提供重新加载选项的脚本, 为此,我们正在收听 worker 消息以跳过等待新安装的 service worker,原因不明,我们没有得到正确的
importScript
// GETTING OLD SW reference (self) and NOT getting newly installed SW reference
self.addEventListener('message', function(event) {
*// not working*
self.skipWaiting();
});
// But if we put skipWaiting() in 'install' listener
// it is getting correct new SW reference and working correctly
self.addEventListener('install', function(event) {
// self.skipWaiting();
});
软件注册
if('serviceWorker' in window.navigator) {
window.addEventListener('load', function() {
window.navigator.serviceWorker.register("/serviceWorker.js").then(function(registration) {
console.log("ServiceWorker registration successful with scope: ", registration);
registration.onupdatefound = function() {
console.log('NEW WILD WORKER HAS SPAWNED.!', registration);
var installedWorker = registration.installing;
installedWorker.onstatechange = function() {
if (installedWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
console.log('Updated content is available RELOAD!', navigator.serviceWorker.controller);
var el = document.getElementById('feature');
el.style['display'] = 'block';
}
}
}
}
}).catch(function(error) {
console.error("ServiceWorker registration failed: ", error);
});
});
window.navigator.serviceWorker.addEventListener('controllerchange', function() {
console.log('SERVICE WORKER UPDATED');
});
}
webpack 配置
new SWPrecacheWebpackPlugin({
cacheId: 'pwa',
filename: 'serviceWorker.js',
staticFileGlobsIgnorePatterns: [/\.map$/, /\.json$/, /_nch\.[0-9a-z]+\.[js, css]+/g, /webpackManifest\.[0-9a-z]+\.js/g, /.DS_Store\.[0-9a-z]+/g],
importScripts: ['offline/offline.1a2b3c4df1.js'],
dontCacheBustUrlsMatching: /./,
minify: false,
skipWaiting: false,
runtimeCaching: [ {
urlPattern: /_nch\.[0-9a-z]+\.[js, css]+/g,
handler: 'fastest',
options: {
cache: {
name: 'jd-internal-script',
maxEntries: 10,
},
},
}, {
urlPattern: /webpackManifest\.[0-9a-z]+\.js/g,
handler: 'networkFirst',
options: {
cache: {
name: 'jd-root-doc',
},
},
}],
}),
所以这就是我的想法... 您的新服务人员仍在等待..因此事件侦听器仍在您的旧服务人员上..您发送的任何消息仍将被旧的 sw 捕获(因为新的正在等待)。
如果您唯一的情况是让新软件生效,您可以简单地刷新页面而不是发送消息
skipWaiting()
的最佳文档可以在 https://developers.google.com/web/fundamentals/instant-and-offline/service-worker/lifecycle#skip_the_waiting_phase
您可以在 install
处理程序中无条件地调用它,或者按照您似乎正在做的模型,即监听 message
事件并调用 skipWaiting()
有条件地。
如果你走条件路线,那么你应该修改你的客户端页面的代码以正确检测你注册的服务工作者何时进入 waiting
状态,并为用户提供与以导致相应 postMessage()
的方式告诉服务工作者 skipWaiting()
的页面。根据您所说的,您已经尝试过了,但看起来您将消息发送到了错误的服务工作者实例。
页面代码应如下所示:
// On your page:
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('service-worker.js').then(function(reg) {
reg.onupdatefound = function() {
var newSW = reg.installing;
newSW.onstatechange = function() {
if (newSW.state === 'waiting') {
// This assumes there's a button with id='skip-waiting-button' that
// users should click to get the new SW to activate immediately.
var button = document.querySelector('#skip-waiting-button');
button.addEventListener('click', function() {
newSW.postMessage('skipWaiting');
});
// Assume that 'display' is 'none' initially.
button.style.display = 'inline';
}
// Handle whatever other SW states you care about, like 'active'.
};
};
})
});
}
// In your service worker:
self.addEventListener('message', event => {
if (event.data === 'skipWaiting') {
self.skipWaiting();
}
});