ServiceWorkerのClients.claim APIの周りに私の頭を包み込むのに問題があります。私が理解しているところでは(hereとhere)、サービスワーカーでclaim()
と呼ぶことができます。イベントをアクティブにして、ページを更新してServiceWorkerを初期化しないようにします。私はそれを動作させることはできませんし、常にリフレッシュする必要が終了します。サービスワーカーインサイドページをリロードしないようにServiceWorkerを初期化するときに、どのようにクライアントを要求できますか?
:ここに私のコードです
self.addEventListener('install', function (event) {
self.skipWaiting();
event.waitUntil(caches.open(CURRENT_CACHE_DICT.prefetch)
.then(function(cache) {
var cachePromises = PREFETCH_URL_LIST.map(function(prefetch_url) {
var url = new URL(prefetch_url, location.href),
request = new Request(url, {mode: 'no-cors'});
return fetch(request).then(function(response) {
if (response.status >= 400) {
throw new Error('request for ' + prefetch_url +
' failed with status ' + response.statusText);
}
return cache.put(prefetch_url, response);
}).catch(function(error) {
console.error('Not caching ' + prefetch_url + ' due to ' + error);
});
});
return Promise.all(cachePromises).then(function() {
console.log('Pre-fetching complete.');
});
}).catch(function(error) {
console.error('Pre-fetching failed:', error);
})
);
});
self.addEventListener('activate', function (event) {
// claim the scope immediately
// XXX does not work?
//self.clients.claim();
event.waitUntil(self.clients.claim()
.then(caches.keys)
.then(function(cache_name_list) {
return Promise.all(
cache_name_list.map(function() {...}
);
})
);
});
以上実行されますが、私はリフレッシュする必要が終わるとChrome ServiceWorkerの内部でIllegal invocation
エラーを検出しましたよ。 waitUntil
ハンドラからclients.claim
を削除し、以前のコメントを外してもエラーは発生しませんが、まだ更新する必要があります。デバッガは示しています
Console: {"lineNumber":128,"message":"Pre-fetching complete.","message_level":1,"sourceIdentifier":3,"sourceURL":""}
Console: {"lineNumber":0,"message":"Uncaught (in promise) TypeError: Illegal invocation","message_level":3,"sourceIdentifier":1,"sourceURL":""}
リフレッシュは、次のようにトリガーされます。
function waitForInstallation(registration) {
return new RSVP.Promise(function(resolve, reject) {
if (registration.installing) {
registration.installing.addEventListener('statechange', function(e) {
if (e.target.state == 'installed') {
resolve();
} else if (e.target.state == 'redundant') {
reject(e);
}
});
} else {
resolve();
}
});
}
// refreshing should not be necessary if scope is claimed on activate
function claimScope(installation) {
return new RSVP.Promise(function (resolve, reject) {
if (navigator.serviceWorker.controller) {
resolve();
} else {
reject(new Error("Please refresh to initialize serviceworker."));
}
});
}
rJS(window)
.declareMethod('render', function (my_option_dict) {
var gadget = this;
if ('serviceWorker' in navigator) {
return new RSVP.Queue()
.push(function() {
return navigator.serviceWorker.register(
my_option_dict.serviceworker_url,
{scope: my_option_dict.scope}
);
})
.push(function (registration) {
return waitForInstallation(registration);
})
.push(function (installation) {
return claimScope(installation);
})
.push(null, function (my_error) {
console.log(my_error);
throw my_error;
});
} else {
throw new Error("Browser does not support serviceworker.");
}
});
質問:
どのように正しくclaim
を使用してServiceWorkerをアクティブにするためにリフレッシュされることからページを防ぐのですか?私が指摘したリンクのうち、controller
を明示的にチェックする必要はありませんでしたが、ServiceWorkerがアクティブな場合、コントローラにアクセス可能であると想定しています。
いくつかの情報を流してくれてありがとう。
編集:
以下のヘルプから理解してください。
var SW = navigator.serviceWorker;
function installServiceWorker(my_option_dict) {
return new RSVP.Queue()
.push(function() {
return SW.getRegistration();
})
.push(function (is_registered_worker) {
// XXX What if this isn't mine?
if (!is_registered_worker) {
return SW.register(
my_option_dict.serviceworker_url, {
"scope": my_option_dict.scope
}
);
}
return is_registered_worker;
});
}
function waitForInstallation(registration) {
return new RSVP.Promise(function(resolve, reject) {
if (registration.installing) {
// If the current registration represents the "installing" service
// worker, then wait until the installation step completes (during
// which any defined resources are pre-fetched) to continue.
registration.installing.addEventListener('statechange', function(e) {
if (e.target.state == 'installed') {
resolve(registration);
} else if (e.target.state == 'redundant') {
reject(e);
}
});
} else {
// Otherwise, if this isn't the "installing" service worker, then
// installation must have beencompleted during a previous visit to this
// page, and the any resources will already have benn pre-fetched So
// we can proceed right away.
resolve(registration);
}
});
}
// refreshing should not be necessary if scope is claimed on activate
function claimScope(registration) {
return new RSVP.Promise(function (resolve, reject) {
if (registration.active.state === 'activated') {
resolve();
} else {
reject(new Error("Please refresh to initialize serviceworker."));
}
});
}
rJS(window)
.ready(function (my_gadget) {
my_gadget.property_dict = {};
})
.declareMethod('render', function (my_option_dict) {
var gadget = this;
if (!SW) {
throw new Error("Browser does not support serviceworker.");
}
return new RSVP.Queue()
.push(function() {
return installServiceWorker(my_option_dict),
})
.push(function (my_promise) {
return waitForInstallation(my_promise);
})
.push(function (my_installation) {
return claimScope(my_installation);
})
.push(function() {
return gadget;
})
.push(null, function (my_error) {
console.log(my_error);
throw my_error;
});
});
孤独な括弧を付けてくれてありがとう:)ページロード#1は制御を提供し、ページロード#2は#2ロードで新しい静的コンテンツをロードします。したがって、私がpostMessage経由で通信する必要があり、要求をキャッシュしない場合は、負荷#1で十分でしょうか?私が主張しているのになぜ 'navigator.serviceWorker.controller'がまだロード#1上で未定義であるのか知っていますか?ありがとう – frequent
ハハ、あなたは歓迎です=)サービスワーカーのアクティブ化を聞くことができるので、サービスワーカーがアクティブになっている/利用可能なときにコードを実行できます。私はその事件をカバーするために私の最近の答えの一つを更新しました。 [あなたは答えに行くことができます](http://stackoverflow.com/a/41916335/4306828)、最後のセクションで 'if(sw.state == 'activated')'ステートメントをチェックしてください。 –
はいいですね。助けてくれてありがとう!括弧は – frequent