问题描述
我有一个 PWA 项目,我将数据发送到服务器。在此过程中,如果用户离线,则数据存储在 indexedDb 中并注册同步标签。因此,当用户上线时,数据可以发送到服务器。 但是在我的例子中,当我们注册一个同步事件标签时,同步事件会立即执行,这意味着尝试在离线时将数据发送到服务器,这是行不通的。
我认为同步事件应该只在在线时触发,这里可能有什么问题?
当我尝试启用和禁用 chrome devtools 的离线选项时,Service Worker 的同步事件会相应地工作,并且在我的 android 手机中也能正常工作。
function onFailure() {
var form = document.querySelector("form");
//Register the sync on post form error
if ('serviceWorker' in navigator && 'SyncManager' in window) {
navigator.serviceWorker.ready
.then(function (sw) {
var post = {
datetime1: form.datetime1.value,datetime: form.datetime.value,name: form.name.value,image: form.url.value,message: form.comment.value
};
writeData('sync-comments',post)
.then(function () {
return sw.sync.register('sync-new-comment');
})
.then(function () {
console.log("[Sync tag registered]");
})
.catch(function (err) {
console.log(err);
});
});
}
}
这就是同步事件的调用方式
self.addEventListener('sync',function (event) {
console.log("[Service worker] Sync new comment",event);
if (event.tag === 'sync-new-comment') {
event.waitUntil(
readAllData('sync-comments')
.then(function (data) {
setTimeout(() => {
data.forEach(async (dt) => {
const url = "/api/post_data/post_new_comment";
const parameters = {
method: 'POST',headers: {
'Content-Type': "application/json",'Accept': 'application/json'
},body: JSON.stringify({
datetime: dt.datetime,name: dt.name,url: dt.image,comment: dt.message,datetime1: dt.datetime1,})
};
fetch(url,parameters)
.then((res) => {
return res.json();
})
.then(response => {
if (response && response.datetimeid) deleteItemFromData('sync-comments',response.datetimeid);
}).catch((error) => {
console.log('[error post message]',error.message);
})
})
},5000);
})
);
}
});
解决方法
你提到
当我尝试启用和禁用 chrome devtools 的离线选项时,Service Worker 的同步事件会相应地工作,并且在我的 android 手机中也能正常工作。
所以我不确定哪个案例失败了。
你说得对,当浏览器认为用户在线时会触发同步,如果浏览器在同步注册时检测到用户在线,则会触发sync:
在真正的可扩展 Web 风格中,这是一个低级功能,可让您自由地做您需要的事情。您要求在用户连接时触发一个事件,如果用户已经连接,则立即触发。然后,您监听该事件并执行您需要执行的任何操作。
此外,来自工作箱 documentation
支持 BackgroundSync API 的浏览器将在浏览器管理的时间间隔内代表您自动重播失败的请求,可能会在重播尝试之间使用指数退避。