UNPKG

preload-it

Version:

A tiny 1kb JavaScript library for preloading assets on the browser via XHR2. It provides the ability to load assets of different file types and composite progress events.

127 lines (110 loc) 2.79 kB
function preloadOne(url, done) { const xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.responseType = 'blob'; const item = this.getItemByUrl(url); item.xhr = xhr; xhr.onprogress = event => { if (!event.lengthComputable) return false item.completion = parseInt((event.loaded / event.total) * 100); item.downloaded = event.loaded; item.total = event.total; this.updateProgressBar(item); }; xhr.onload = event => { const type = event.target.response.type; const responseURL = event.target.responseURL; item.fileName = responseURL.substring(responseURL.lastIndexOf('/') + 1); item.type = type; item.status = xhr.status; if (xhr.status == 404) { item.blobUrl = item.size = null; item.error = true; this.onerror(item); } else { const blob = new Blob([event.target.response], { type: type }); item.blobUrl = URL.createObjectURL(blob); item.size = blob.size; item.error = false; } done(item); }; xhr.send(); } function updateProgressBar(item) { let sumCompletion = 0; let maxCompletion = this.stepped ? (this.state.length * 100) : 0; let initialisedCount = 0; for (const itemState of this.state) { if (itemState.completion) initialisedCount++; if (this.stepped) { if (itemState.completion) { sumCompletion += itemState.completion; } } else { if (this._readyForComputation) { sumCompletion += itemState.downloaded; maxCompletion += itemState.total; } else { sumCompletion = maxCompletion = 0; } } } this._readyForComputation = (initialisedCount == this.state.length); const totalCompletion = parseInt((sumCompletion / maxCompletion) * 100); if (!isNaN(totalCompletion)) { this.onprogress({ progress: totalCompletion, item: item }); } } function getItemByUrl(rawUrl) { for (var item of this.state) { if (item.url == rawUrl) return item } } function fetch(list) { return new Promise((resolve, reject) => { this.loaded = list.length; for (let item of list) { this.state.push({ url: item }); this.preloadOne(item, item => { this.onfetched(item); this.loaded--; if (this.loaded == 0) { this.oncomplete(this.state); resolve(this.state); } }); } }) } function cancel() { for (var item of this.state) { if (item.completion < 100) { item.xhr.abort(); item.status = 0; } } this.oncancel(this.state); return this.state } function Preload(options) { return { state: [], loaded: false, stepped: (options && options.stepped) || true, onprogress: () => {}, oncomplete: () => {}, onfetched: () => {}, onerror: () => {}, oncancel: () => {}, fetch, updateProgressBar, preloadOne, getItemByUrl, cancel } } export default Preload;