"use strict";
|
|
/**
|
* Queue for all the resources to be download except async scripts.
|
* Async scripts have their own queue AsyncResourceQueue.
|
*/
|
module.exports = class ResourceQueue {
|
constructor({ paused, asyncQueue } = {}) {
|
this.paused = Boolean(paused);
|
this._asyncQueue = asyncQueue;
|
}
|
|
getLastScript() {
|
let head = this.tail;
|
|
while (head) {
|
if (head.isScript) {
|
return head;
|
}
|
head = head.prev;
|
}
|
|
return null;
|
}
|
|
_moreScripts() {
|
let found = false;
|
|
let head = this.tail;
|
while (head && !found) {
|
found = head.isScript;
|
head = head.prev;
|
}
|
|
return found;
|
}
|
|
_notify() {
|
if (this._listener) {
|
this._listener();
|
}
|
}
|
|
setListener(listener) {
|
this._listener = listener;
|
}
|
|
push(request, onLoad, onError, keepLast, element) {
|
const isScript = element ? element.localName === "script" : false;
|
|
if (!request) {
|
if (isScript && !this._moreScripts()) {
|
return onLoad();
|
}
|
|
request = Promise.resolve();
|
}
|
const q = this;
|
const item = {
|
isScript,
|
err: null,
|
element,
|
fired: false,
|
data: null,
|
keepLast,
|
prev: q.tail,
|
check() {
|
if (!q.paused && !this.prev && this.fired) {
|
let promise;
|
|
if (this.err && onError) {
|
promise = onError(this.err);
|
}
|
|
if (!this.err && onLoad) {
|
promise = onLoad(this.data);
|
}
|
|
Promise.resolve(promise)
|
.then(() => {
|
if (this.next) {
|
this.next.prev = null;
|
this.next.check();
|
} else { // q.tail===this
|
q.tail = null;
|
q._notify();
|
}
|
|
this.finished = true;
|
|
if (q._asyncQueue) {
|
q._asyncQueue.notifyItem(this);
|
}
|
});
|
}
|
}
|
};
|
if (q.tail) {
|
if (q.tail.keepLast) {
|
// if the tail is the load event in document and we receive a new element to load
|
// we should add this new request before the load event.
|
if (q.tail.prev) {
|
q.tail.prev.next = item;
|
}
|
item.prev = q.tail.prev;
|
q.tail.prev = item;
|
item.next = q.tail;
|
} else {
|
q.tail.next = item;
|
q.tail = item;
|
}
|
} else {
|
q.tail = item;
|
}
|
return request
|
.then(data => {
|
item.fired = 1;
|
item.data = data;
|
item.check();
|
})
|
.catch(err => {
|
item.fired = true;
|
item.err = err;
|
item.check();
|
});
|
}
|
|
resume() {
|
if (!this.paused) {
|
return;
|
}
|
this.paused = false;
|
|
let head = this.tail;
|
while (head && head.prev) {
|
head = head.prev;
|
}
|
if (head) {
|
head.check();
|
}
|
}
|
};
|