Use Promise polyfill instead of Q #735 (#736)

This commit is contained in:
Jaifroid 2021-07-22 18:56:08 +01:00 committed by GitHub
parent 5a2ea27df1
commit 8fb07bb5a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 999 additions and 2157 deletions

View File

@ -30,14 +30,19 @@ require.config({
baseUrl: (window.__karma__ ? 'base/' : '') + 'www/js/lib/', baseUrl: (window.__karma__ ? 'base/' : '') + 'www/js/lib/',
paths: { paths: {
'jquery': 'jquery-3.2.1.slim', 'jquery': 'jquery-3.2.1.slim',
'webpHeroBundle': 'webpHeroBundle_0.0.0-dev.27', 'webpHeroBundle': 'webpHeroBundle_0.0.0-dev.27'
'webpHeroPolyfills': 'webpHeroPolyfills_0.0.0-dev.27'
}, },
shim: { shim: {
'webpHeroBundle': { 'webpHeroBundle': ''
deps: ['webpHeroPolyfills']
}
} }
}); });
requirejs(['../../../tests/tests']); var req = []; // Baseline Require array
// Add polyfills to the Require array only if needed
if (!('Promise' in self)) req.push('promisePolyfill');
if (!('from' in Array)) req.push('arrayFromPolyfill');
requirejs(req, function () {
requirejs(['../../../tests/tests']);
});

View File

@ -109,13 +109,13 @@ define(['jquery', 'zimArchive', 'zimDirEntry', 'util', 'uiUtil', 'utf8'],
var testString3 = "le Couvre-chef Est sur le porte-manteaux"; var testString3 = "le Couvre-chef Est sur le porte-manteaux";
var testString4 = "épée"; var testString4 = "épée";
var testString5 = '$¥€“«xριστός» †¡Ἀνέστη!”'; var testString5 = '$¥€“«xριστός» †¡Ἀνέστη!”';
var testString6 = "Καλά Νερά Μαγνησίας žižek"; var testString6 = "Καλά Νερά Μαγνησία žižek";
assert.equal(util.allCaseFirstLetters(testString1).indexOf("Téléphone") >= 0, true, "The first letter should be uppercase"); assert.equal(util.allCaseFirstLetters(testString1).indexOf("Téléphone") >= 0, true, "The first letter should be uppercase");
assert.equal(util.allCaseFirstLetters(testString2).indexOf("paris") >= 0, true, "The first letter should be lowercase"); assert.equal(util.allCaseFirstLetters(testString2).indexOf("paris") >= 0, true, "The first letter should be lowercase");
assert.equal(util.allCaseFirstLetters(testString3).indexOf("Le Couvre-Chef Est Sur Le Porte-Manteaux") >= 0, true, "The first letter of every word should be uppercase"); assert.equal(util.allCaseFirstLetters(testString3).indexOf("Le Couvre-Chef Est Sur Le Porte-Manteaux") >= 0, true, "The first letter of every word should be uppercase");
assert.equal(util.allCaseFirstLetters(testString4).indexOf("Épée") >= 0, true, "The first letter should be uppercase (with accent)"); assert.equal(util.allCaseFirstLetters(testString4).indexOf("Épée") >= 0, true, "The first letter should be uppercase (with accent)");
assert.equal(util.allCaseFirstLetters(testString5).indexOf('$¥€“«Xριστός» †¡ἀνέστη!”') >= 0, true, "First non-punctuation/non-currency Unicode letter should be uppercase, second (with breath mark) lowercase"); assert.equal(util.allCaseFirstLetters(testString5).indexOf('$¥€“«Xριστός» †¡ἀνέστη!”') >= 0, true, "First non-punctuation/non-currency Unicode letter should be uppercase, second (with breath mark) lowercase");
assert.equal(util.allCaseFirstLetters(testString6, "full").indexOf("ΚΑΛΆ ΝΕΡΆ ΜΑΓΝΗΣΊΑΣ ŽIŽEK") >= 0, true, "All Unicode letters should be uppercase"); assert.equal(util.allCaseFirstLetters(testString6, "full").indexOf("ΚΑΛΆ ΝΕΡΆ ΜΑΓΝΗΣΊΑ ŽIŽEK") >= 0, true, "All Unicode letters should be uppercase");
}); });
QUnit.test("check removal of parameters in URL", function(assert) { QUnit.test("check removal of parameters in URL", function(assert) {
var testUrl1 = "A/question.html"; var testUrl1 = "A/question.html";

View File

@ -26,8 +26,8 @@
// This uses require.js to structure javascript: // This uses require.js to structure javascript:
// http://requirejs.org/docs/api.html#define // http://requirejs.org/docs/api.html#define
define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesystemAccess','q'], define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesystemAccess'],
function($, zimArchiveLoader, uiUtil, settingsStore, abstractFilesystemAccess, Q) { function($, zimArchiveLoader, uiUtil, settingsStore, abstractFilesystemAccess) {
/** /**
* The delay (in milliseconds) between two "keepalive" messages sent to the ServiceWorker (so that it is not stopped * The delay (in milliseconds) between two "keepalive" messages sent to the ServiceWorker (so that it is not stopped
@ -475,7 +475,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys
* @returns {Promise<Object>} A Promise for an object with cache attributes 'type', 'description', and 'count' * @returns {Promise<Object>} A Promise for an object with cache attributes 'type', 'description', and 'count'
*/ */
function getCacheAttributes() { function getCacheAttributes() {
return Q.Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
if (contentInjectionMode === 'serviceworker') { if (contentInjectionMode === 'serviceworker') {
// Create a Message Channel // Create a Message Channel
var channel = new MessageChannel(); var channel = new MessageChannel();
@ -963,26 +963,24 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys
* @returns {Promise<Blob>} A promise for the requested file (blob) * @returns {Promise<Blob>} A promise for the requested file (blob)
*/ */
function readRemoteArchive(url) { function readRemoteArchive(url) {
// DEV: This deferred can't be standardized to a Promise/A+ pattern (using Q) because return new Promise(function (resolve, reject) {
// IE11 is unable to scope the callbacks inside the Promise correctly. See [kiwix.js #589] var request = new XMLHttpRequest();
var deferred = Q.defer(); request.open("GET", url);
var request = new XMLHttpRequest(); request.responseType = "blob";
request.open("GET", url); request.onreadystatechange = function () {
request.responseType = "blob"; if (request.readyState === XMLHttpRequest.DONE) {
request.onreadystatechange = function () { if (request.status >= 200 && request.status < 300 || request.status === 0) {
if (request.readyState === XMLHttpRequest.DONE) { // Hack to make this look similar to a file
if (request.status >= 200 && request.status < 300 || request.status === 0) { request.response.name = url;
// Hack to make this look similar to a file resolve(request.response);
request.response.name = url; } else {
deferred.resolve(request.response); reject("HTTP status " + request.status + " when reading " + url);
} else { }
deferred.reject("HTTP status " + request.status + " when reading " + url);
} }
} };
}; request.onabort = request.onerror = reject;
request.onabort = request.onerror = deferred.reject; request.send();
request.send(); });
return deferred.promise;
} }
/** /**
@ -994,7 +992,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys
Array.prototype.slice.call(arguments).forEach(function (arg) { Array.prototype.slice.call(arguments).forEach(function (arg) {
readRequests.push(readRemoteArchive(arg)); readRequests.push(readRemoteArchive(arg));
}); });
return Q.all(readRequests).then(function (arrayOfArchives) { return Promise.all(readRequests).then(function (arrayOfArchives) {
setLocalArchiveFromFileList(arrayOfArchives); setLocalArchiveFromFileList(arrayOfArchives);
}).catch(function (e) { }).catch(function (e) {
console.error('Unable to load remote archive(s)', e); console.error('Unable to load remote archive(s)', e);

View File

@ -36,7 +36,6 @@ require.config({
'jquery': 'jquery-3.2.1.slim', 'jquery': 'jquery-3.2.1.slim',
'bootstrap': 'bootstrap.bundle', 'bootstrap': 'bootstrap.bundle',
'webpHeroBundle': 'webpHeroBundle_0.0.0-dev.27', 'webpHeroBundle': 'webpHeroBundle_0.0.0-dev.27',
'webpHeroPolyfills': 'webpHeroPolyfills_0.0.0-dev.27',
'fontawesome': 'fontawesome/fontawesome', 'fontawesome': 'fontawesome/fontawesome',
'fontawesome-solid': 'fontawesome/solid' 'fontawesome-solid': 'fontawesome/solid'
}, },
@ -47,13 +46,17 @@ require.config({
'bootstrap': { 'bootstrap': {
deps: ['jquery', 'fontawesome', 'fontawesome-solid'] deps: ['jquery', 'fontawesome', 'fontawesome-solid']
}, },
'webpHeroBundle': { 'webpHeroBundle': ''
deps: ['webpHeroPolyfills']
}
} }
}); });
requirejs(['bootstrap'], function (bootstrap) { var req = ['bootstrap']; // Baseline Require array
// Add polyfills to the Require array only if needed
if (!('Promise' in self)) req.push('promisePolyfill');
if (!('from' in Array)) req.push('arrayFromPolyfill');
requirejs(req, function () {
requirejs(['../app']); requirejs(['../app']);
}); });

View File

@ -25,7 +25,7 @@
* along with Kiwix (file LICENSE-GPLv3.txt). If not, see <http://www.gnu.org/licenses/> * along with Kiwix (file LICENSE-GPLv3.txt). If not, see <http://www.gnu.org/licenses/>
*/ */
'use strict'; 'use strict';
define(['q', 'jquery'], function(q, jQuery) { define([], function() {
/** /**
* Storage implemented by Firefox OS * Storage implemented by Firefox OS
@ -50,11 +50,12 @@ define(['q', 'jquery'], function(q, jQuery) {
* rejected with an error message. * rejected with an error message.
*/ */
StorageFirefoxOS.prototype.get = function(path) { StorageFirefoxOS.prototype.get = function(path) {
var deferred = q.defer(); var that = this;
var request = this._storage.get(path); return new Promise(function (resolve, reject){
request.onsuccess = function() { deferred.resolve(this.result); }; var request = that._storage.get(path);
request.onerror = function() { deferred.reject(this.error.name); }; request.onsuccess = function() { resolve(this.result); };
return deferred.promise; request.onerror = function() { reject(this.error.name); };
});
}; };
// We try to match both a standalone ZIM file (.zim) or // We try to match both a standalone ZIM file (.zim) or
@ -67,26 +68,27 @@ define(['q', 'jquery'], function(q, jQuery) {
* paths and rejected with an error message. * paths and rejected with an error message.
*/ */
StorageFirefoxOS.prototype.scanForArchives = function() { StorageFirefoxOS.prototype.scanForArchives = function() {
var deferred = jQuery.Deferred(); var that = this;
var directories = []; return new Promise(function (resolve, reject){
var cursor = this._storage.enumerate(); var directories = [];
cursor.onerror = function() { var cursor = that._storage.enumerate();
deferred.reject(cursor.error); cursor.onerror = function () {
}; reject(cursor.error);
cursor.onsuccess = function() { };
if (!cursor.result) { cursor.onsuccess = function () {
deferred.resolve(directories); if (!cursor.result) {
return; resolve(directories);
} return;
var file = cursor.result; }
var file = cursor.result;
if (regexpZIMFileName.test(file.name)) { if (regexpZIMFileName.test(file.name)) {
directories.push(file.name); directories.push(file.name);
} }
cursor.continue(); cursor.continue();
}; };
return deferred.promise(); });
}; };
/** /**

View File

@ -0,0 +1,33 @@
/**
* Simple Array.from polyfill (with Set support) from https://stackoverflow.com/a/62682524/9727685
*/
(function () {
function arrayFrom(arr, callbackFn, thisArg) {
//if you need you can uncomment the following line
//if(!arr || typeof arr == 'function')throw new Error('This function requires an array-like object - not null, undefined or a function');
var arNew = [],
k = [], // used for convert Set to an Array
i = 0;
//if you do not need a Set object support then
//you can comment or delete the following if statement
if (window.Set && arr instanceof Set) {
//we use forEach from Set object
arr.forEach(function (v) {
k.push(v)
});
arr = k;
}
for (; i < arr.length; i++)
arNew[i] = callbackFn ?
callbackFn.call(thisArg, arr[i], i, arr) :
arr[i];
return arNew;
}
//You could also use it without the following line, but it is not recommended because native function is faster.
Array.from = Array.from || arrayFrom; //We set it as polyfill
}());

View File

@ -23,7 +23,7 @@
*/ */
'use strict'; 'use strict';
define(['q'], function (Q) { define([], function () {
/** /**
* Set maximum number of cache blocks of BLOCK_SIZE bytes each * Set maximum number of cache blocks of BLOCK_SIZE bytes each
* Maximum size of cache in bytes = MAX_CACHE_SIZE * BLOCK_SIZE * Maximum size of cache in bytes = MAX_CACHE_SIZE * BLOCK_SIZE
@ -166,7 +166,7 @@ define(['q'], function (Q) {
// misses = 0; // misses = 0;
// } // }
// Wait for all the blocks to be read either from the cache or from the archive // Wait for all the blocks to be read either from the cache or from the archive
return Q.all(readRequests).then(function () { return Promise.all(readRequests).then(function () {
var result = new Uint8Array(end - begin); var result = new Uint8Array(end - begin);
var pos = 0; var pos = 0;
// Stitch together the data parts in the right order // Stitch together the data parts in the right order

View File

@ -0,0 +1,878 @@
/*
Yaku v0.19.3
(c) 2015 Yad Smood. http://ysmood.org
License MIT
*/
/*
Yaku v0.17.9
(c) 2015 Yad Smood. http://ysmood.org
License MIT
*/
(function () {
'use strict';
var $undefined
, $null = null
, isBrowser = typeof self === 'object'
, root = self
, nativePromise = root.Promise
, process = root.process
, console = root.console
, isLongStackTrace = true
, Arr = Array
, Err = Error
, $rejected = 1
, $resolved = 2
, $pending = 3
, $Symbol = 'Symbol'
, $iterator = 'iterator'
, $species = 'species'
, $speciesKey = $Symbol + '(' + $species + ')'
, $return = 'return'
, $unhandled = '_uh'
, $promiseTrace = '_pt'
, $settlerTrace = '_st'
, $invalidThis = 'Invalid this'
, $invalidArgument = 'Invalid argument'
, $fromPrevious = '\nFrom previous '
, $promiseCircularChain = 'Chaining cycle detected for promise'
, $unhandledRejectionMsg = 'Uncaught (in promise)'
, $rejectionHandled = 'rejectionHandled'
, $unhandledRejection = 'unhandledRejection'
, $tryCatchFn
, $tryCatchThis
, $tryErr = { e: $null }
, $noop = function () {}
, $cleanStackReg = /^.+\/node_modules\/yaku\/.+\n?/mg
;
/**
* This class follows the [Promises/A+](https://promisesaplus.com) and
* [ES6](http://people.mozilla.org/~jorendorff/es6-draft.html#sec-promise-objects) spec
* with some extra helpers.
* @param {Function} executor Function object with two arguments resolve, reject.
* The first argument fulfills the promise, the second argument rejects it.
* We can call these functions, once our operation is completed.
*/
var Yaku = function (executor) {
var self = this,
err;
// "this._s" is the internao state of: pending, resolved or rejected
// "this._v" is the internal value
if (!isObject(self) || self._s !== $undefined)
throw genTypeError($invalidThis);
self._s = $pending;
if (isLongStackTrace) self[$promiseTrace] = genTraceInfo();
if (executor !== $noop) {
if (!isFunction(executor))
throw genTypeError($invalidArgument);
err = genTryCatcher(executor)(
genSettler(self, $resolved),
genSettler(self, $rejected)
);
if (err === $tryErr)
settlePromise(self, $rejected, err.e);
}
};
Yaku['default'] = Yaku;
extend(Yaku.prototype, {
/**
* Appends fulfillment and rejection handlers to the promise,
* and returns a new promise resolving to the return value of the called handler.
* @param {Function} onFulfilled Optional. Called when the Promise is resolved.
* @param {Function} onRejected Optional. Called when the Promise is rejected.
* @return {Yaku} It will return a new Yaku which will resolve or reject after
* @example
* the current Promise.
* ```js
* var Promise = require('yaku');
* var p = Promise.resolve(10);
*
* p.then((v) => {
* console.log(v);
* });
* ```
*/
then: function (onFulfilled, onRejected) {
if (this._s === undefined) throw genTypeError();
return addHandler(
this,
newCapablePromise(Yaku.speciesConstructor(this, Yaku)),
onFulfilled,
onRejected
);
},
/**
* The `catch()` method returns a Promise and deals with rejected cases only.
* It behaves the same as calling `Promise.prototype.then(undefined, onRejected)`.
* @param {Function} onRejected A Function called when the Promise is rejected.
* This function has one argument, the rejection reason.
* @return {Yaku} A Promise that deals with rejected cases only.
* @example
* ```js
* var Promise = require('yaku');
* var p = Promise.reject(new Error("ERR"));
*
* p['catch']((v) => {
* console.log(v);
* });
* ```
*/
'catch': function (onRejected) {
return this.then($undefined, onRejected);
},
/**
* Register a callback to be invoked when a promise is settled (either fulfilled or rejected).
* Similar with the try-catch-finally, it's often used for cleanup.
* @param {Function} onFinally A Function called when the Promise is settled.
* It will not receive any argument.
* @return {Yaku} A Promise that will reject if onFinally throws an error or returns a rejected promise.
* Else it will resolve previous promise's final state (either fulfilled or rejected).
* @example
* ```js
* var Promise = require('yaku');
* var p = Math.random() > 0.5 ? Promise.resolve() : Promise.reject();
* p.finally(() => {
* console.log('finally');
* });
* ```
*/
'finally': function (onFinally) {
return this.then(function (val) {
return Yaku.resolve(onFinally()).then(function () {
return val;
});
}, function (err) {
return Yaku.resolve(onFinally()).then(function () {
throw err;
});
});
},
// The number of current promises that attach to this Yaku instance.
_c: 0,
// The parent Yaku.
_p: $null
});
/**
* The `Promise.resolve(value)` method returns a Promise object that is resolved with the given value.
* If the value is a thenable (i.e. has a then method), the returned promise will "follow" that thenable,
* adopting its eventual state; otherwise the returned promise will be fulfilled with the value.
* @param {Any} value Argument to be resolved by this Promise.
* Can also be a Promise or a thenable to resolve.
* @return {Yaku}
* @example
* ```js
* var Promise = require('yaku');
* var p = Promise.resolve(10);
* ```
*/
Yaku.resolve = function (val) {
return isYaku(val) ? val : settleWithX(newCapablePromise(this), val);
};
/**
* The `Promise.reject(reason)` method returns a Promise object that is rejected with the given reason.
* @param {Any} reason Reason why this Promise rejected.
* @return {Yaku}
* @example
* ```js
* var Promise = require('yaku');
* var p = Promise.reject(new Error("ERR"));
* ```
*/
Yaku.reject = function (reason) {
return settlePromise(newCapablePromise(this), $rejected, reason);
};
/**
* The `Promise.race(iterable)` method returns a promise that resolves or rejects
* as soon as one of the promises in the iterable resolves or rejects,
* with the value or reason from that promise.
* @param {iterable} iterable An iterable object, such as an Array.
* @return {Yaku} The race function returns a Promise that is settled
* the same way as the first passed promise to settle.
* It resolves or rejects, whichever happens first.
* @example
* ```js
* var Promise = require('yaku');
* Promise.race([
* 123,
* Promise.resolve(0)
* ])
* .then((value) => {
* console.log(value); // => 123
* });
* ```
*/
Yaku.race = function (iterable) {
var self = this
, p = newCapablePromise(self)
, resolve = function (val) {
settlePromise(p, $resolved, val);
}
, reject = function (val) {
settlePromise(p, $rejected, val);
}
, ret = genTryCatcher(each)(iterable, function (v) {
self.resolve(v).then(resolve, reject);
});
if (ret === $tryErr) return self.reject(ret.e);
return p;
};
/**
* The `Promise.all(iterable)` method returns a promise that resolves when
* all of the promises in the iterable argument have resolved.
*
* The result is passed as an array of values from all the promises.
* If something passed in the iterable array is not a promise,
* it's converted to one by Promise.resolve. If any of the passed in promises rejects,
* the all Promise immediately rejects with the value of the promise that rejected,
* discarding all the other promises whether or not they have resolved.
* @param {iterable} iterable An iterable object, such as an Array.
* @return {Yaku}
* @example
* ```js
* var Promise = require('yaku');
* Promise.all([
* 123,
* Promise.resolve(0)
* ])
* .then((values) => {
* console.log(values); // => [123, 0]
* });
* ```
* @example
* Use with iterable.
* ```js
* var Promise = require('yaku');
* Promise.all((function * () {
* yield 10;
* yield new Promise(function (r) { setTimeout(r, 1000, "OK") });
* })())
* .then((values) => {
* console.log(values); // => [123, 0]
* });
* ```
*/
Yaku.all = function (iterable) {
var self = this
, p1 = newCapablePromise(self)
, res = []
, ret
;
function reject (reason) {
settlePromise(p1, $rejected, reason);
}
ret = genTryCatcher(each)(iterable, function (item, i) {
self.resolve(item).then(function (value) {
res[i] = value;
if (!--ret) settlePromise(p1, $resolved, res);
}, reject);
});
if (ret === $tryErr) return self.reject(ret.e);
if (!ret) settlePromise(p1, $resolved, []);
return p1;
};
/**
* The ES6 Symbol object that Yaku should use, by default it will use the
* global one.
* @type {Object}
* @example
* ```js
* var core = require("core-js/library");
* var Promise = require("yaku");
* Promise.Symbol = core.Symbol;
* ```
*/
Yaku.Symbol = root[$Symbol] || {};
// To support browsers that don't support `Object.defineProperty`.
genTryCatcher(function () {
Object.defineProperty(Yaku, getSpecies(), {
get: function () { return this; }
});
})();
/**
* Use this api to custom the species behavior.
* https://tc39.github.io/ecma262/#sec-speciesconstructor
* @param {Any} O The current this object.
* @param {Function} defaultConstructor
*/
Yaku.speciesConstructor = function (O, D) {
var C = O.constructor;
return C ? (C[getSpecies()] || D) : D;
};
/**
* Catch all possibly unhandled rejections. If you want to use specific
* format to display the error stack, overwrite it.
* If it is set, auto `console.error` unhandled rejection will be disabled.
* @param {Any} reason The rejection reason.
* @param {Yaku} p The promise that was rejected.
* @example
* ```js
* var Promise = require('yaku');
* Promise.unhandledRejection = (reason) => {
* console.error(reason);
* };
*
* // The console will log an unhandled rejection error message.
* Promise.reject('my reason');
*
* // The below won't log the unhandled rejection error message.
* Promise.reject('v')["catch"](() => {});
* ```
*/
Yaku.unhandledRejection = function (reason, p) {
console && console.error(
$unhandledRejectionMsg,
isLongStackTrace ? p.longStack : genStackInfo(reason, p)
);
};
/**
* Emitted whenever a Promise was rejected and an error handler was
* attached to it (for example with `["catch"]()`) later than after an event loop turn.
* @param {Any} reason The rejection reason.
* @param {Yaku} p The promise that was rejected.
*/
Yaku.rejectionHandled = $noop;
/**
* It is used to enable the long stack trace.
* Once it is enabled, it can't be reverted.
* While it is very helpful in development and testing environments,
* it is not recommended to use it in production. It will slow down
* application and eat up memory.
* It will add an extra property `longStack` to the Error object.
* @example
* ```js
* var Promise = require('yaku');
* Promise.enableLongStackTrace();
* Promise.reject(new Error("err"))["catch"]((err) => {
* console.log(err.longStack);
* });
* ```
*/
Yaku.enableLongStackTrace = function () {
isLongStackTrace = true;
};
/**
* Only Node has `process.nextTick` function. For browser there are
* so many ways to polyfill it. Yaku won't do it for you, instead you
* can choose what you prefer. For example, this project
* [next-tick](https://github.com/medikoo/next-tick).
* By default, Yaku will use `process.nextTick` on Node, `setTimeout` on browser.
* @type {Function}
* @example
* ```js
* var Promise = require('yaku');
* Promise.nextTick = require('next-tick');
* ```
* @example
* You can even use sync resolution if you really know what you are doing.
* ```js
* var Promise = require('yaku');
* Promise.nextTick = fn => fn();
* ```
*/
Yaku.nextTick = isBrowser ?
function (fn) {
nativePromise ?
new nativePromise(function (resolve) { resolve(); }).then(fn) :
setTimeout(fn);
} :
process.nextTick;
// ********************** Private **********************
Yaku._s = 1;
/**
* All static variable name will begin with `$`. Such as `$rejected`.
* @private
*/
// ******************************* Utils ********************************
function getSpecies () {
return Yaku[$Symbol][$species] || $speciesKey;
}
function extend (src, target) {
for (var k in target) {
src[k] = target[k];
}
}
function isObject (obj) {
return obj && typeof obj === 'object';
}
function isFunction (obj) {
return typeof obj === 'function';
}
function isInstanceOf (a, b) {
return a instanceof b;
}
function isError (obj) {
return isInstanceOf(obj, Err);
}
function ensureType (obj, fn, msg) {
if (!fn(obj)) throw genTypeError(msg);
}
/**
* Wrap a function into a try-catch.
* @private
* @return {Any | $tryErr}
*/
function tryCatcher () {
try {
return $tryCatchFn.apply($tryCatchThis, arguments);
} catch (e) {
$tryErr.e = e;
return $tryErr;
}
}
/**
* Generate a try-catch wrapped function.
* @private
* @param {Function} fn
* @return {Function}
*/
function genTryCatcher (fn, self) {
$tryCatchFn = fn;
$tryCatchThis = self;
return tryCatcher;
}
/**
* Generate a scheduler.
* @private
* @param {Integer} initQueueSize
* @param {Function} fn `(Yaku, Value) ->` The schedule handler.
* @return {Function} `(Yaku, Value) ->` The scheduler.
*/
function genScheduler (initQueueSize, fn) {
/**
* All async promise will be scheduled in
* here, so that they can be execute on the next tick.
* @private
*/
var fnQueue = Arr(initQueueSize)
, fnQueueLen = 0;
/**
* Run all queued functions.
* @private
*/
function flush () {
var i = 0;
while (i < fnQueueLen) {
fn(fnQueue[i], fnQueue[i + 1]);
fnQueue[i++] = $undefined;
fnQueue[i++] = $undefined;
}
fnQueueLen = 0;
if (fnQueue.length > initQueueSize) fnQueue.length = initQueueSize;
}
return function (v, arg) {
fnQueue[fnQueueLen++] = v;
fnQueue[fnQueueLen++] = arg;
if (fnQueueLen === 2) Yaku.nextTick(flush);
};
}
/**
* Generate a iterator
* @param {Any} obj
* @private
* @return {Object || TypeError}
*/
function each (iterable, fn) {
var len
, i = 0
, iter
, item
, ret
;
if (!iterable) throw genTypeError($invalidArgument);
var gen = iterable[Yaku[$Symbol][$iterator]];
if (isFunction(gen))
iter = gen.call(iterable);
else if (isFunction(iterable.next)) {
iter = iterable;
}
else if (isInstanceOf(iterable, Arr)) {
len = iterable.length;
while (i < len) {
fn(iterable[i], i++);
}
return i;
} else
throw genTypeError($invalidArgument);
while (!(item = iter.next()).done) {
ret = genTryCatcher(fn)(item.value, i++);
if (ret === $tryErr) {
isFunction(iter[$return]) && iter[$return]();
throw ret.e;
}
}
return i;
}
/**
* Generate type error object.
* @private
* @param {String} msg
* @return {TypeError}
*/
function genTypeError (msg) {
return new TypeError(msg);
}
function genTraceInfo (noTitle) {
return (noTitle ? '' : $fromPrevious) + new Err().stack;
}
// *************************** Promise Helpers ****************************
/**
* Resolve the value returned by onFulfilled or onRejected.
* @private
* @param {Yaku} p1
* @param {Yaku} p2
*/
var scheduleHandler = genScheduler(999, function (p1, p2) {
var x, handler;
// 2.2.2
// 2.2.3
handler = p1._s !== $rejected ? p2._onFulfilled : p2._onRejected;
// 2.2.7.3
// 2.2.7.4
if (handler === $undefined) {
settlePromise(p2, p1._s, p1._v);
return;
}
// 2.2.7.1
x = genTryCatcher(callHanler)(handler, p1._v);
if (x === $tryErr) {
// 2.2.7.2
settlePromise(p2, $rejected, x.e);
return;
}
settleWithX(p2, x);
});
var scheduleUnhandledRejection = genScheduler(9, function (p) {
if (!hashOnRejected(p)) {
p[$unhandled] = 1;
emitEvent($unhandledRejection, p);
}
});
function emitEvent (name, p) {
var browserEventName = 'on' + name.toLowerCase()
, browserHandler = root[browserEventName];
if (process && process.listeners(name).length)
name === $unhandledRejection ?
process.emit(name, p._v, p) : process.emit(name, p);
else if (browserHandler)
browserHandler({ reason: p._v, promise: p });
else
Yaku[name](p._v, p);
}
function isYaku (val) { return val && val._s; }
function newCapablePromise (Constructor) {
if (isYaku(Constructor)) return new Constructor($noop);
var p, r, j;
p = new Constructor(function (resolve, reject) {
if (p) throw genTypeError();
r = resolve;
j = reject;
});
ensureType(r, isFunction);
ensureType(j, isFunction);
return p;
}
/**
* It will produce a settlePromise function to user.
* Such as the resolve and reject in this `new Yaku (resolve, reject) ->`.
* @private
* @param {Yaku} self
* @param {Integer} state The value is one of `$pending`, `$resolved` or `$rejected`.
* @return {Function} `(value) -> undefined` A resolve or reject function.
*/
function genSettler (self, state) {
var isCalled = false;
return function (value) {
if (isCalled) return;
isCalled = true;
if (isLongStackTrace)
self[$settlerTrace] = genTraceInfo(true);
if (state === $resolved)
settleWithX(self, value);
else
settlePromise(self, state, value);
};
}
/**
* Link the promise1 to the promise2.
* @private
* @param {Yaku} p1
* @param {Yaku} p2
* @param {Function} onFulfilled
* @param {Function} onRejected
*/
function addHandler (p1, p2, onFulfilled, onRejected) {
// 2.2.1
if (isFunction(onFulfilled))
p2._onFulfilled = onFulfilled;
if (isFunction(onRejected)) {
if (p1[$unhandled]) emitEvent($rejectionHandled, p1);
p2._onRejected = onRejected;
}
if (isLongStackTrace) p2._p = p1;
p1[p1._c++] = p2;
// 2.2.6
if (p1._s !== $pending)
scheduleHandler(p1, p2);
// 2.2.7
return p2;
}
// iterate tree
function hashOnRejected (node) {
// A node shouldn't be checked twice.
if (node._umark)
return true;
else
node._umark = true;
var i = 0
, len = node._c
, child;
while (i < len) {
child = node[i++];
if (child._onRejected || hashOnRejected(child)) return true;
}
}
function genStackInfo (reason, p) {
var stackInfo = [];
function push (trace) {
return stackInfo.push(trace.replace(/^\s+|\s+$/g, ''));
}
if (isLongStackTrace) {
if (p[$settlerTrace])
push(p[$settlerTrace]);
// Hope you guys could understand how the back trace works.
// We only have to iterate through the tree from the bottom to root.
(function iter (node) {
if (node && $promiseTrace in node) {
iter(node._next);
push(node[$promiseTrace] + '');
iter(node._p);
}
})(p);
}
return (reason && reason.stack ? reason.stack : reason) +
('\n' + stackInfo.join('\n')).replace($cleanStackReg, '');
}
function callHanler (handler, value) {
// 2.2.5
return handler(value);
}
/**
* Resolve or reject a promise.
* @private
* @param {Yaku} p
* @param {Integer} state
* @param {Any} value
*/
function settlePromise (p, state, value) {
var i = 0
, len = p._c;
// 2.1.2
// 2.1.3
if (p._s === $pending) {
// 2.1.1.1
p._s = state;
p._v = value;
if (state === $rejected) {
if (isLongStackTrace && isError(value)) {
value.longStack = genStackInfo(value, p);
}
scheduleUnhandledRejection(p);
}
// 2.2.4
while (i < len) {
scheduleHandler(p, p[i++]);
}
}
return p;
}
/**
* Resolve or reject promise with value x. The x can also be a thenable.
* @private
* @param {Yaku} p
* @param {Any | Thenable} x A normal value or a thenable.
*/
function settleWithX (p, x) {
// 2.3.1
if (x === p && x) {
settlePromise(p, $rejected, genTypeError($promiseCircularChain));
return p;
}
// 2.3.2
// 2.3.3
if (x !== $null && (isFunction(x) || isObject(x))) {
// 2.3.2.1
var xthen = genTryCatcher(getThen)(x);
if (xthen === $tryErr) {
// 2.3.3.2
settlePromise(p, $rejected, xthen.e);
return p;
}
if (isFunction(xthen)) {
if (isLongStackTrace && isYaku(x))
p._next = x;
// Fix https://bugs.chromium.org/p/v8/issues/detail?id=4162
if (isYaku(x))
settleXthen(p, x, xthen);
else
Yaku.nextTick(function () {
settleXthen(p, x, xthen);
});
} else
// 2.3.3.4
settlePromise(p, $resolved, x);
} else
// 2.3.4
settlePromise(p, $resolved, x);
return p;
}
/**
* Try to get a promise's then method.
* @private
* @param {Thenable} x
* @return {Function}
*/
function getThen (x) { return x.then; }
/**
* Resolve then with its promise.
* @private
* @param {Yaku} p
* @param {Thenable} x
* @param {Function} xthen
*/
function settleXthen (p, x, xthen) {
// 2.3.3.3
var err = genTryCatcher(xthen, x)(function (y) {
// 2.3.3.3.3
// 2.3.3.3.1
x && (x = $null, settleWithX(p, y));
}, function (r) {
// 2.3.3.3.3
// 2.3.3.3.2
x && (x = $null, settlePromise(p, $rejected, r));
});
// 2.3.3.3.4.1
if (err === $tryErr && x) {
// 2.3.3.3.4.2
settlePromise(p, $rejected, err.e);
x = $null;
}
}
root.Promise = Yaku;
})();

File diff suppressed because it is too large Load Diff

View File

@ -20,7 +20,7 @@
* along with Kiwix (file LICENSE-GPLv3.txt). If not, see <http://www.gnu.org/licenses/> * along with Kiwix (file LICENSE-GPLv3.txt). If not, see <http://www.gnu.org/licenses/>
*/ */
'use strict'; 'use strict';
define(['q'], function(Q) { define([], function() {
/** /**
* A Regular Expression to match the first letter of a word even if preceded by Unicode punctuation * A Regular Expression to match the first letter of a word even if preceded by Unicode punctuation
@ -211,7 +211,7 @@ define(['q'], function(Q) {
return new Uint8Array(buffer); return new Uint8Array(buffer);
}); });
} else { } else {
return Q.Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
var reader = new FileReader(); var reader = new FileReader();
reader.readAsArrayBuffer(file.slice(begin, end)); reader.readAsArrayBuffer(file.slice(begin, end));
reader.addEventListener('load', function (e) { reader.addEventListener('load', function (e) {

File diff suppressed because one or more lines are too long

View File

@ -20,7 +20,7 @@
* along with Kiwix (file LICENSE-GPLv3.txt). If not, see <http://www.gnu.org/licenses/> * along with Kiwix (file LICENSE-GPLv3.txt). If not, see <http://www.gnu.org/licenses/>
*/ */
'use strict'; 'use strict';
define(['q', 'xzdec'], function(Q) { define(['xzdec'], function() {
// DEV: xzdec.js emits a global Module variable, which cannot be set in requireJS function line above, though it can be loaded in definition // DEV: xzdec.js emits a global Module variable, which cannot be set in requireJS function line above, though it can be loaded in definition
var xzdec = Module; var xzdec = Module;
xzdec._init(); xzdec._init();
@ -86,14 +86,15 @@ define(['q', 'xzdec'], function(Q) {
* @returns {Promise} A Promise for the read data * @returns {Promise} A Promise for the read data
*/ */
Decompressor.prototype.readSliceSingleThread = function (offset, length) { Decompressor.prototype.readSliceSingleThread = function (offset, length) {
if (!busy) { // Tests whether the decompressor is ready (initiated) and not busy
if (xzdec && !busy) {
return this.readSlice(offset, length); return this.readSlice(offset, length);
} else { } else {
// The decompressor is already in progress. // The decompressor is already in progress.
// To avoid using too much memory, we wait until it has finished // To avoid using too much memory, we wait until it has finished
// before using it for another decompression // before using it for another decompression
var that = this; var that = this;
return Q.Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
setTimeout(function () { setTimeout(function () {
that.readSliceSingleThread(offset, length).then(resolve, reject); that.readSliceSingleThread(offset, length).then(resolve, reject);
}, DELAY_WAITING_IDLE_DECOMPRESSOR); }, DELAY_WAITING_IDLE_DECOMPRESSOR);
@ -148,8 +149,7 @@ define(['q', 'xzdec'], function(Q) {
*/ */
Decompressor.prototype._fillInBufferIfNeeded = function() { Decompressor.prototype._fillInBufferIfNeeded = function() {
if (!xzdec._input_empty(this._decHandle)) { if (!xzdec._input_empty(this._decHandle)) {
// DEV: When converting to Promise/A+, use Promise.resolve(0) here return Promise.resolve(0);
return Q.when(0);
} }
var that = this; var that = this;
return this._reader(this._inStreamPos, this._chunkSize).then(function(data) { return this._reader(this._inStreamPos, this._chunkSize).then(function(data) {

View File

@ -21,7 +21,7 @@
*/ */
'use strict'; 'use strict';
define(['xzdec_wrapper', 'zstddec_wrapper', 'util', 'utf8', 'q', 'zimDirEntry', 'filecache'], function(xz, zstd, util, utf8, Q, zimDirEntry, FileCache) { define(['xzdec_wrapper', 'zstddec_wrapper', 'util', 'utf8', 'zimDirEntry', 'filecache'], function(xz, zstd, util, utf8, zimDirEntry, FileCache) {
/** /**
* A variable to keep track of the currently loaded ZIM archive, e.g., for labelling cache entries * A variable to keep track of the currently loaded ZIM archive, e.g., for labelling cache entries
@ -118,12 +118,12 @@ define(['xzdec_wrapper', 'zstddec_wrapper', 'util', 'utf8', 'q', 'zimDirEntry',
} }
} }
if (readRequests.length === 0) { if (readRequests.length === 0) {
return Q(new Uint8Array(0).buffer); return Promise.resolve(new Uint8Array(0).buffer);
} else if (readRequests.length === 1) { } else if (readRequests.length === 1) {
return readRequests[0]; return readRequests[0];
} else { } else {
// Wait until all are resolved and concatenate. // Wait until all are resolved and concatenate.
return Q.all(readRequests).then(function (arrays) { return Promise.all(readRequests).then(function (arrays) {
var concatenated = new Uint8Array(end - begin); var concatenated = new Uint8Array(end - begin);
var offset = 0; var offset = 0;
arrays.forEach(function (item) { arrays.forEach(function (item) {
@ -227,7 +227,7 @@ define(['xzdec_wrapper', 'zstddec_wrapper', 'util', 'utf8', 'q', 'zimDirEntry',
return that._readSlice(offsetStart, size); return that._readSlice(offsetStart, size);
} }
} else { } else {
return Q(new Uint8Array(0).buffer); return Promise.resolve(new Uint8Array(0).buffer);
} }
}; };
// If only metadata were requested and the cluster is compressed, return null (this is probably a ZIM format error) // If only metadata were requested and the cluster is compressed, return null (this is probably a ZIM format error)

View File

@ -35,7 +35,7 @@ function B(){return buffer.byteLength/65536|0}return{"e":Ha,"f":oa,"g":na,"h":ga
B=[];"object"!==typeof WebAssembly&&J("no native wasm support detected");var G,H=new function(c){var e=Array(c.initial);e.set=function(d,m){e[d]=m};e.get=function(d){return e[d]};return e}({initial:1,maximum:1,element:"anyfunc"}),K=!1;function L(c){var e=a["_"+c];e||J("Assertion failed: Cannot call unknown function "+(c+", make sure it is exported"));return e} B=[];"object"!==typeof WebAssembly&&J("no native wasm support detected");var G,H=new function(c){var e=Array(c.initial);e.set=function(d,m){e[d]=m};e.get=function(d){return e[d]};return e}({initial:1,maximum:1,element:"anyfunc"}),K=!1;function L(c){var e=a["_"+c];e||J("Assertion failed: Cannot call unknown function "+(c+", make sure it is exported"));return e}
function ea(c,e,d,m){var l={string:function(b){var f=0;if(null!==b&&void 0!==b&&0!==b){var g=(b.length<<2)+1;f=M(g);var h=f,k=O;if(0<g){g=h+g-1;for(var t=0;t<b.length;++t){var n=b.charCodeAt(t);if(55296<=n&&57343>=n){var I=b.charCodeAt(++t);n=65536+((n&1023)<<10)|I&1023}if(127>=n){if(h>=g)break;k[h++]=n}else{if(2047>=n){if(h+1>=g)break;k[h++]=192|n>>6}else{if(65535>=n){if(h+2>=g)break;k[h++]=224|n>>12}else{if(h+3>=g)break;k[h++]=240|n>>18;k[h++]=128|n>>12&63}k[h++]=128|n>>6&63}k[h++]=128|n&63}}k[h]= function ea(c,e,d,m){var l={string:function(b){var f=0;if(null!==b&&void 0!==b&&0!==b){var g=(b.length<<2)+1;f=M(g);var h=f,k=O;if(0<g){g=h+g-1;for(var t=0;t<b.length;++t){var n=b.charCodeAt(t);if(55296<=n&&57343>=n){var I=b.charCodeAt(++t);n=65536+((n&1023)<<10)|I&1023}if(127>=n){if(h>=g)break;k[h++]=n}else{if(2047>=n){if(h+1>=g)break;k[h++]=192|n>>6}else{if(65535>=n){if(h+2>=g)break;k[h++]=224|n>>12}else{if(h+3>=g)break;k[h++]=240|n>>18;k[h++]=128|n>>12&63}k[h++]=128|n>>6&63}k[h++]=128|n&63}}k[h]=
0}}return f},array:function(b){var f=M(b.length);fa.set(b,f);return f}},p=L(c),r=[];c=0;if(m)for(var q=0;q<m.length;q++){var D=l[d[q]];D?(0===c&&(c=ha()),r[q]=D(m[q])):r[q]=m[q]}d=p.apply(null,r);d=function(b){if("string"===e)if(b){for(var f=O,g=b+NaN,h=b;f[h]&&!(h>=g);)++h;if(16<h-b&&f.subarray&&ia)b=ia.decode(f.subarray(b,h));else{for(g="";b<h;){var k=f[b++];if(k&128){var t=f[b++]&63;if(192==(k&224))g+=String.fromCharCode((k&31)<<6|t);else{var n=f[b++]&63;k=224==(k&240)?(k&15)<<12|t<<6|n:(k&7)<< 0}}return f},array:function(b){var f=M(b.length);fa.set(b,f);return f}},p=L(c),r=[];c=0;if(m)for(var q=0;q<m.length;q++){var D=l[d[q]];D?(0===c&&(c=ha()),r[q]=D(m[q])):r[q]=m[q]}d=p.apply(null,r);d=function(b){if("string"===e)if(b){for(var f=O,g=b+NaN,h=b;f[h]&&!(h>=g);)++h;if(16<h-b&&f.subarray&&ia)b=ia.decode(f.subarray(b,h));else{for(g="";b<h;){var k=f[b++];if(k&128){var t=f[b++]&63;if(192==(k&224))g+=String.fromCharCode((k&31)<<6|t);else{var n=f[b++]&63;k=224==(k&240)?(k&15)<<12|t<<6|n:(k&7)<<
18|t<<12|n<<6|f[b++]&63;65536>k?g+=String.fromCharCode(k):(k-=65536,g+=String.fromCharCode(55296|k>>10,56320|k&1023))}}else g+=String.fromCharCode(k)}b=g}}else b="";else b="boolean"===e?!!b:b;return b}(d);0!==c&&ja(c);return d}var ia="undefined"!==typeof TextDecoder?new TextDecoder("utf8"):void 0,P,fa,O,C=a.INITIAL_MEMORY||140247040;a.wasmMemory?G=a.wasmMemory:G=new aa;G&&(P=G.buffer);C=P.byteLength;var Q=P;P=Q;a.HEAP8=fa=new Int8Array(Q);a.HEAP16=new Int16Array(Q);a.HEAP32=new Int32Array(Q); 18|t<<12|n<<6|f[b++]&63;65536>k?g+=String.fromCharCode(k):(k-=65536,g+=String.fromCharCode(55296|k>>10,56320|k&1023))}}else g+=String.fromCharCode(k)}b=g}}else b="";else b="boolean"===e?!!b:b;return b}(d);0!==c&&ja(c);return d}var ia="undefined"!==typeof TextDecoder?new TextDecoder("utf8"):void 0,P,fa,O,C=a.INITIAL_MEMORY||150994944;a.wasmMemory?G=a.wasmMemory:G=new aa;G&&(P=G.buffer);C=P.byteLength;var Q=P;P=Q;a.HEAP8=fa=new Int8Array(Q);a.HEAP16=new Int16Array(Q);a.HEAP32=new Int32Array(Q);
a.HEAPU8=O=new Uint8Array(Q);a.HEAPU16=new Uint16Array(Q);a.HEAPU32=new Uint32Array(Q);a.HEAPF32=new Float32Array(Q);a.HEAPF64=new Float64Array(Q);var ka=[],la=[],ma=[],na=[];function oa(){var c=a.preRun.shift();ka.unshift(c)}Math.imul&&-5===Math.imul(4294967295,5)||(Math.imul=function(c,e){var d=c&65535,m=e&65535;return d*m+((c>>>16)*m+d*(e>>>16)<<16)|0});if(!Math.fround){var pa=new Float32Array(1);Math.fround=function(c){pa[0]=c;return pa[0]}} a.HEAPU8=O=new Uint8Array(Q);a.HEAPU16=new Uint16Array(Q);a.HEAPU32=new Uint32Array(Q);a.HEAPF32=new Float32Array(Q);a.HEAPF64=new Float64Array(Q);var ka=[],la=[],ma=[],na=[];function oa(){var c=a.preRun.shift();ka.unshift(c)}Math.imul&&-5===Math.imul(4294967295,5)||(Math.imul=function(c,e){var d=c&65535,m=e&65535;return d*m+((c>>>16)*m+d*(e>>>16)<<16)|0});if(!Math.fround){var pa=new Float32Array(1);Math.fround=function(c){pa[0]=c;return pa[0]}}
Math.clz32||(Math.clz32=function(c){var e=32,d=c>>16;d&&(e-=16,c=d);if(d=c>>8)e-=8,c=d;if(d=c>>4)e-=4,c=d;if(d=c>>2)e-=2,c=d;return c>>1?e-2:e-c});Math.trunc||(Math.trunc=function(c){return 0>c?Math.ceil(c):Math.floor(c)});var R=0,T=null,U=null;a.preloadedImages={};a.preloadedAudios={};function J(c){if(a.onAbort)a.onAbort(c);A(c);K=!0;c=new da("abort("+c+"). Build with -s ASSERTIONS=1 for more info.");v(c);throw c;} Math.clz32||(Math.clz32=function(c){var e=32,d=c>>16;d&&(e-=16,c=d);if(d=c>>8)e-=8,c=d;if(d=c>>4)e-=4,c=d;if(d=c>>2)e-=2,c=d;return c>>1?e-2:e-c});Math.trunc||(Math.trunc=function(c){return 0>c?Math.ceil(c):Math.floor(c)});var R=0,T=null,U=null;a.preloadedImages={};a.preloadedAudios={};function J(c){if(a.onAbort)a.onAbort(c);A(c);K=!0;c=new da("abort("+c+"). Build with -s ASSERTIONS=1 for more info.");v(c);throw c;}
function V(c){return String.prototype.startsWith?c.startsWith("data:application/octet-stream;base64,"):0===c.indexOf("data:application/octet-stream;base64,")}var W="zstddec.wasm";if(!V(W)){var qa=W;W=a.locateFile?a.locateFile(qa,y):y+qa} function V(c){return String.prototype.startsWith?c.startsWith("data:application/octet-stream;base64,"):0===c.indexOf("data:application/octet-stream;base64,")}var W="zstddec.wasm";if(!V(W)){var qa=W;W=a.locateFile?a.locateFile(qa,y):y+qa}

View File

@ -20,7 +20,7 @@
* along with Kiwix (file LICENSE-GPLv3.txt). If not, see <http://www.gnu.org/licenses/> * along with Kiwix (file LICENSE-GPLv3.txt). If not, see <http://www.gnu.org/licenses/>
*/ */
'use strict'; 'use strict';
define(['q', 'zstddec'], function (Q) { define(['zstddec'], function () {
// DEV: zstddec.js has been compiled with `-s EXPORT_NAME="ZD" -s MODULARIZE=1` to avoid a clash with xzdec which uses "Module" as its exported object // DEV: zstddec.js has been compiled with `-s EXPORT_NAME="ZD" -s MODULARIZE=1` to avoid a clash with xzdec which uses "Module" as its exported object
// Note that we include zstddec above in requireJS definition, but we cannot change the name in the function list // Note that we include zstddec above in requireJS definition, but we cannot change the name in the function list
// There is no longer any need to load it in index.html // There is no longer any need to load it in index.html
@ -130,7 +130,7 @@ define(['q', 'zstddec'], function (Q) {
this._outDataBufPos = 0; this._outDataBufPos = 0;
var ret = zd._ZSTD_initDStream(zd._decHandle); var ret = zd._ZSTD_initDStream(zd._decHandle);
if (zd._ZSTD_isError(ret)) { if (zd._ZSTD_isError(ret)) {
return Q.reject('Failed to initialize ZSTD decompression'); return Promise.reject('Failed to initialize ZSTD decompression');
} }
return this._readLoop(offset, length).then(function (data) { return this._readLoop(offset, length).then(function (data) {
@ -153,14 +153,15 @@ define(['q', 'zstddec'], function (Q) {
* @returns {Promise} A Promise for the readSlice() function * @returns {Promise} A Promise for the readSlice() function
*/ */
Decompressor.prototype.readSliceSingleThread = function (offset, length) { Decompressor.prototype.readSliceSingleThread = function (offset, length) {
if (!busy) { // Tests whether the decompressor is ready (initiated) and not busy
if (zd && !busy) {
return this.readSlice(offset, length); return this.readSlice(offset, length);
} else { } else {
// The decompressor is already in progress. // The decompressor is already in progress.
// To avoid using too much memory, we wait until it has finished // To avoid using too much memory, we wait until it has finished
// before using it for another decompression // before using it for another decompression
var that = this; var that = this;
return Q.Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
setTimeout(function () { setTimeout(function () {
that.readSliceSingleThread(offset, length).then(resolve, reject); that.readSliceSingleThread(offset, length).then(resolve, reject);
}, DELAY_WAITING_IDLE_DECOMPRESSOR); }, DELAY_WAITING_IDLE_DECOMPRESSOR);
@ -181,7 +182,7 @@ define(['q', 'zstddec'], function (Q) {
var ret = zd._ZSTD_decompressStream(zd._decHandle, zd._outBuffer.ptr, zd._inBuffer.ptr); var ret = zd._ZSTD_decompressStream(zd._decHandle, zd._outBuffer.ptr, zd._inBuffer.ptr);
if (zd._ZSTD_isError(ret)) { if (zd._ZSTD_isError(ret)) {
var errorMessage = "Failed to decompress data stream!\n" + zd.getErrorString(ret); var errorMessage = "Failed to decompress data stream!\n" + zd.getErrorString(ret);
return Q.reject(errorMessage); return Promise.reject(errorMessage);
} }
// Get updated outbuffer values // Get updated outbuffer values
var obxPtr32Bit = zd._outBuffer.ptr >> 2; var obxPtr32Bit = zd._outBuffer.ptr >> 2;