Okですので、非同期XHRと2つのイベントbeforeunloadとunloadで実行できます。
私は1つのイベントでそれをやろうとしましたが、リクエストがループの前に送信されたとしても、ループが終了するまでリクエストは送信されません。
beforeunloadハンドラでは、非同期要求を送信して現在の時間を保存します。アンロードハンドラでは、十分な時間が経過していないか、サーバが応答した(readyStateをチェックしている)場合は、whileループを続行します。 ループが終了すると、ブラウザはウィンドウを自由にアンロードできます。
ここにコードがあります。また、ブラウザがサポートしている場合は、ビーコンを送信することもできました。
var unloadRequest = null,
requestStartTime = null,
isBeaconSupported = (navigator && typeof navigator.sendBeacon === 'function');
window.onbeforeunload = function() {
if (isBeaconSupported) {
unloadRequest = new XMLHttpRequest();
unloadRequest.withCredentials = true;
unloadRequest.open('POST', '/beacon', true);
unloadRequest.setRequestHeader("Content-Type", "text/plain");
requestStartTime = performance.now();
unloadRequest.send(JSON.stringify({ test: true, _sentBy: 'XMLHttpRequest' }));
}
//return true;
};
window.onunload = function() {
if (isBeaconSupported) {
navigator.sendBeacon('/beacon', JSON.stringify({ test: true, _sentBy: 'beacon' }))
} else if (unloadRequest) {
//continue the loop if time is left and the request havent finished
while (requestStartTime + 3000 > performance.now() && unloadRequest.readyState !== XMLHttpRequest.DONE) {
//console.log(unloadRequest.readyState);
}
console.log('request finished or timed out')
console.log('it took: ' + (performance.now() - requestStartTime) + 'ms');
}
};