Last active
September 18, 2018 12:04
-
-
Save danshearmur/ad8cbf2c1ef5c7596b27 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function () { | |
if (window.navigator.sendBeacon || !window.localStorage) return; | |
var TO_S = Object.prototype.toString; | |
var TYPE_RE = /\[object ([a-zA-Z0-9]*)\]/; | |
var LS_PFX = 'beaconfill-'; | |
var LIMIT = 64 * 1024; | |
var WAIT = 1500; | |
var MAX_RETRIES = 3; | |
// helpers | |
function type(thing) { | |
return TYPE_RE.exec(TO_S.call(thing))[1].toLowerCase(); | |
} | |
function escStr(str) { | |
return str.replace(/"/g, "\\\""); | |
} | |
function unescStr(str) { | |
return str.replace(/\\"/g, "\""); | |
} | |
// grab the next item in localStorage that has a key beginning with 'beaconfill-' | |
function nextItem() { | |
for (var i = 0, l = localStorage.length; i < l; i++) { | |
var key = localStorage.key(i); | |
if (key.indexOf(LS_PFX) === 0) { | |
return {key: key, payload: JSON.parse(localStorage.getItem(key))}; | |
} | |
} | |
} | |
// posts relevant data to the server, if req successful removes data from localStorage | |
// always starts next `process()` | |
function send(item) { | |
item.payload.retried++; | |
localStorage.setItem(item.key, JSON.stringify(item.payload)); | |
var client = new XMLHttpRequest(); | |
if (!('withCredential' in client)) { | |
if (typeof XDomainRequest === 'undefined') return; | |
client = new XDomainRequest(); | |
} | |
client.open('POST', item.payload.url, false); | |
client.onreadystatechange = function () { | |
if (client.readyState === 4) { | |
if (client.status > 199 && client.status < 299) { | |
localStorage.removeItem(item.key); | |
} | |
process(); | |
} | |
}; | |
client.setRequestHeader('Content-Type', 'text/plain;charset=UTF-8'); | |
client.send(item.payload.data); | |
} | |
// checks for the next item in localStorage | |
// deletes it if over max retries | |
// sends next item | |
function process() { | |
var item = nextItem(); | |
if (!item) return; | |
if (item.payload.retried >= MAX_RETRIES) { | |
localStorage.removeItem(item.key); | |
return process(); | |
} | |
send(item); | |
} | |
window.navigator.sendBeacon = function sendBeacon(url, data) { | |
if (type(data) !== 'string') { | |
throw TypeError('Data must be a string'); | |
} | |
// TODO: allow Blob, FormData or ArrayBufferView | |
if (data.length > LIMIT) { | |
return false; | |
} | |
localStorage.setItem(LS_PFX + Date.now(), JSON.stringify({ | |
data: escStr(data), | |
retried: 0, | |
url: url | |
})); | |
return true; | |
}; | |
window.addEventListener('load', function () { | |
setTimeout(process, WAIT); | |
}, false); | |
}()); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<script src="beaconfill.js"></script> | |
<script> | |
window.onunload = function () { | |
var data = { thing: true, time: Date.now(), x: 1000, rand: Math.random() }; | |
navigator.sendBeacon('/endpoint', JSON.stringify(data)) | |
}; | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment