epubjs
Version:
Parse and Render Epubs
1,574 lines (1,298 loc) • 50.9 kB
JavaScript
/*!
* @overview RSVP - a tiny implementation of Promises/A+.
* @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors
* @license Licensed under MIT license
* See https://raw.githubusercontent.com/tildeio/rsvp.js/master/LICENSE
* @version 3.0.20
*/
(function() {
"use strict";
function lib$rsvp$utils$$objectOrFunction(x) {
return typeof x === 'function' || (typeof x === 'object' && x !== null);
}
function lib$rsvp$utils$$isFunction(x) {
return typeof x === 'function';
}
function lib$rsvp$utils$$isMaybeThenable(x) {
return typeof x === 'object' && x !== null;
}
var lib$rsvp$utils$$_isArray;
if (!Array.isArray) {
lib$rsvp$utils$$_isArray = function (x) {
return Object.prototype.toString.call(x) === '[object Array]';
};
} else {
lib$rsvp$utils$$_isArray = Array.isArray;
}
var lib$rsvp$utils$$isArray = lib$rsvp$utils$$_isArray;
var lib$rsvp$utils$$now = Date.now || function() { return new Date().getTime(); };
function lib$rsvp$utils$$F() { }
var lib$rsvp$utils$$o_create = (Object.create || function (o) {
if (arguments.length > 1) {
throw new Error('Second argument not supported');
}
if (typeof o !== 'object') {
throw new TypeError('Argument must be an object');
}
lib$rsvp$utils$$F.prototype = o;
return new lib$rsvp$utils$$F();
});
function lib$rsvp$events$$indexOf(callbacks, callback) {
for (var i=0, l=callbacks.length; i<l; i++) {
if (callbacks[i] === callback) { return i; }
}
return -1;
}
function lib$rsvp$events$$callbacksFor(object) {
var callbacks = object._promiseCallbacks;
if (!callbacks) {
callbacks = object._promiseCallbacks = {};
}
return callbacks;
}
var lib$rsvp$events$$default = {
/**
`RSVP.EventTarget.mixin` extends an object with EventTarget methods. For
Example:
```javascript
var object = {};
RSVP.EventTarget.mixin(object);
object.on('finished', function(event) {
// handle event
});
object.trigger('finished', { detail: value });
```
`EventTarget.mixin` also works with prototypes:
```javascript
var Person = function() {};
RSVP.EventTarget.mixin(Person.prototype);
var yehuda = new Person();
var tom = new Person();
yehuda.on('poke', function(event) {
console.log('Yehuda says OW');
});
tom.on('poke', function(event) {
console.log('Tom says OW');
});
yehuda.trigger('poke');
tom.trigger('poke');
```
@method mixin
@for RSVP.EventTarget
@private
@param {Object} object object to extend with EventTarget methods
*/
'mixin': function(object) {
object['on'] = this['on'];
object['off'] = this['off'];
object['trigger'] = this['trigger'];
object._promiseCallbacks = undefined;
return object;
},
/**
Registers a callback to be executed when `eventName` is triggered
```javascript
object.on('event', function(eventInfo){
// handle the event
});
object.trigger('event');
```
@method on
@for RSVP.EventTarget
@private
@param {String} eventName name of the event to listen for
@param {Function} callback function to be called when the event is triggered.
*/
'on': function(eventName, callback) {
if (typeof callback !== 'function') {
throw new TypeError('Callback must be a function');
}
var allCallbacks = lib$rsvp$events$$callbacksFor(this), callbacks;
callbacks = allCallbacks[eventName];
if (!callbacks) {
callbacks = allCallbacks[eventName] = [];
}
if (lib$rsvp$events$$indexOf(callbacks, callback) === -1) {
callbacks.push(callback);
}
},
/**
You can use `off` to stop firing a particular callback for an event:
```javascript
function doStuff() { // do stuff! }
object.on('stuff', doStuff);
object.trigger('stuff'); // doStuff will be called
// Unregister ONLY the doStuff callback
object.off('stuff', doStuff);
object.trigger('stuff'); // doStuff will NOT be called
```
If you don't pass a `callback` argument to `off`, ALL callbacks for the
event will not be executed when the event fires. For example:
```javascript
var callback1 = function(){};
var callback2 = function(){};
object.on('stuff', callback1);
object.on('stuff', callback2);
object.trigger('stuff'); // callback1 and callback2 will be executed.
object.off('stuff');
object.trigger('stuff'); // callback1 and callback2 will not be executed!
```
@method off
@for RSVP.EventTarget
@private
@param {String} eventName event to stop listening to
@param {Function} callback optional argument. If given, only the function
given will be removed from the event's callback queue. If no `callback`
argument is given, all callbacks will be removed from the event's callback
queue.
*/
'off': function(eventName, callback) {
var allCallbacks = lib$rsvp$events$$callbacksFor(this), callbacks, index;
if (!callback) {
allCallbacks[eventName] = [];
return;
}
callbacks = allCallbacks[eventName];
index = lib$rsvp$events$$indexOf(callbacks, callback);
if (index !== -1) { callbacks.splice(index, 1); }
},
/**
Use `trigger` to fire custom events. For example:
```javascript
object.on('foo', function(){
console.log('foo event happened!');
});
object.trigger('foo');
// 'foo event happened!' logged to the console
```
You can also pass a value as a second argument to `trigger` that will be
passed as an argument to all event listeners for the event:
```javascript
object.on('foo', function(value){
console.log(value.name);
});
object.trigger('foo', { name: 'bar' });
// 'bar' logged to the console
```
@method trigger
@for RSVP.EventTarget
@private
@param {String} eventName name of the event to be triggered
@param {*} options optional value to be passed to any event handlers for
the given `eventName`
*/
'trigger': function(eventName, options) {
var allCallbacks = lib$rsvp$events$$callbacksFor(this), callbacks, callback;
if (callbacks = allCallbacks[eventName]) {
// Don't cache the callbacks.length since it may grow
for (var i=0; i<callbacks.length; i++) {
callback = callbacks[i];
callback(options);
}
}
}
};
var lib$rsvp$config$$config = {
instrument: false
};
lib$rsvp$events$$default['mixin'](lib$rsvp$config$$config);
function lib$rsvp$config$$configure(name, value) {
if (name === 'onerror') {
// handle for legacy users that expect the actual
// error to be passed to their function added via
// `RSVP.configure('onerror', someFunctionHere);`
lib$rsvp$config$$config['on']('error', value);
return;
}
if (arguments.length === 2) {
lib$rsvp$config$$config[name] = value;
} else {
return lib$rsvp$config$$config[name];
}
}
var lib$rsvp$instrument$$queue = [];
function lib$rsvp$instrument$$scheduleFlush() {
setTimeout(function() {
var entry;
for (var i = 0; i < lib$rsvp$instrument$$queue.length; i++) {
entry = lib$rsvp$instrument$$queue[i];
var payload = entry.payload;
payload.guid = payload.key + payload.id;
payload.childGuid = payload.key + payload.childId;
if (payload.error) {
payload.stack = payload.error.stack;
}
lib$rsvp$config$$config['trigger'](entry.name, entry.payload);
}
lib$rsvp$instrument$$queue.length = 0;
}, 50);
}
function lib$rsvp$instrument$$instrument(eventName, promise, child) {
if (1 === lib$rsvp$instrument$$queue.push({
name: eventName,
payload: {
key: promise._guidKey,
id: promise._id,
eventName: eventName,
detail: promise._result,
childId: child && child._id,
label: promise._label,
timeStamp: lib$rsvp$utils$$now(),
error: lib$rsvp$config$$config["instrument-with-stack"] ? new Error(promise._label) : null
}})) {
lib$rsvp$instrument$$scheduleFlush();
}
}
var lib$rsvp$instrument$$default = lib$rsvp$instrument$$instrument;
function lib$rsvp$$internal$$withOwnPromise() {
return new TypeError('A promises callback cannot return that same promise.');
}
function lib$rsvp$$internal$$noop() {}
var lib$rsvp$$internal$$PENDING = void 0;
var lib$rsvp$$internal$$FULFILLED = 1;
var lib$rsvp$$internal$$REJECTED = 2;
var lib$rsvp$$internal$$GET_THEN_ERROR = new lib$rsvp$$internal$$ErrorObject();
function lib$rsvp$$internal$$getThen(promise) {
try {
return promise.then;
} catch(error) {
lib$rsvp$$internal$$GET_THEN_ERROR.error = error;
return lib$rsvp$$internal$$GET_THEN_ERROR;
}
}
function lib$rsvp$$internal$$tryThen(then, value, fulfillmentHandler, rejectionHandler) {
try {
then.call(value, fulfillmentHandler, rejectionHandler);
} catch(e) {
return e;
}
}
function lib$rsvp$$internal$$handleForeignThenable(promise, thenable, then) {
lib$rsvp$config$$config.async(function(promise) {
var sealed = false;
var error = lib$rsvp$$internal$$tryThen(then, thenable, function(value) {
if (sealed) { return; }
sealed = true;
if (thenable !== value) {
lib$rsvp$$internal$$resolve(promise, value);
} else {
lib$rsvp$$internal$$fulfill(promise, value);
}
}, function(reason) {
if (sealed) { return; }
sealed = true;
lib$rsvp$$internal$$reject(promise, reason);
}, 'Settle: ' + (promise._label || ' unknown promise'));
if (!sealed && error) {
sealed = true;
lib$rsvp$$internal$$reject(promise, error);
}
}, promise);
}
function lib$rsvp$$internal$$handleOwnThenable(promise, thenable) {
if (thenable._state === lib$rsvp$$internal$$FULFILLED) {
lib$rsvp$$internal$$fulfill(promise, thenable._result);
} else if (thenable._state === lib$rsvp$$internal$$REJECTED) {
thenable._onError = null;
lib$rsvp$$internal$$reject(promise, thenable._result);
} else {
lib$rsvp$$internal$$subscribe(thenable, undefined, function(value) {
if (thenable !== value) {
lib$rsvp$$internal$$resolve(promise, value);
} else {
lib$rsvp$$internal$$fulfill(promise, value);
}
}, function(reason) {
lib$rsvp$$internal$$reject(promise, reason);
});
}
}
function lib$rsvp$$internal$$handleMaybeThenable(promise, maybeThenable) {
if (maybeThenable.constructor === promise.constructor) {
lib$rsvp$$internal$$handleOwnThenable(promise, maybeThenable);
} else {
var then = lib$rsvp$$internal$$getThen(maybeThenable);
if (then === lib$rsvp$$internal$$GET_THEN_ERROR) {
lib$rsvp$$internal$$reject(promise, lib$rsvp$$internal$$GET_THEN_ERROR.error);
} else if (then === undefined) {
lib$rsvp$$internal$$fulfill(promise, maybeThenable);
} else if (lib$rsvp$utils$$isFunction(then)) {
lib$rsvp$$internal$$handleForeignThenable(promise, maybeThenable, then);
} else {
lib$rsvp$$internal$$fulfill(promise, maybeThenable);
}
}
}
function lib$rsvp$$internal$$resolve(promise, value) {
if (promise === value) {
lib$rsvp$$internal$$fulfill(promise, value);
} else if (lib$rsvp$utils$$objectOrFunction(value)) {
lib$rsvp$$internal$$handleMaybeThenable(promise, value);
} else {
lib$rsvp$$internal$$fulfill(promise, value);
}
}
function lib$rsvp$$internal$$publishRejection(promise) {
if (promise._onError) {
promise._onError(promise._result);
}
lib$rsvp$$internal$$publish(promise);
}
function lib$rsvp$$internal$$fulfill(promise, value) {
if (promise._state !== lib$rsvp$$internal$$PENDING) { return; }
promise._result = value;
promise._state = lib$rsvp$$internal$$FULFILLED;
if (promise._subscribers.length === 0) {
if (lib$rsvp$config$$config.instrument) {
lib$rsvp$instrument$$default('fulfilled', promise);
}
} else {
lib$rsvp$config$$config.async(lib$rsvp$$internal$$publish, promise);
}
}
function lib$rsvp$$internal$$reject(promise, reason) {
if (promise._state !== lib$rsvp$$internal$$PENDING) { return; }
promise._state = lib$rsvp$$internal$$REJECTED;
promise._result = reason;
lib$rsvp$config$$config.async(lib$rsvp$$internal$$publishRejection, promise);
}
function lib$rsvp$$internal$$subscribe(parent, child, onFulfillment, onRejection) {
var subscribers = parent._subscribers;
var length = subscribers.length;
parent._onError = null;
subscribers[length] = child;
subscribers[length + lib$rsvp$$internal$$FULFILLED] = onFulfillment;
subscribers[length + lib$rsvp$$internal$$REJECTED] = onRejection;
if (length === 0 && parent._state) {
lib$rsvp$config$$config.async(lib$rsvp$$internal$$publish, parent);
}
}
function lib$rsvp$$internal$$publish(promise) {
var subscribers = promise._subscribers;
var settled = promise._state;
if (lib$rsvp$config$$config.instrument) {
lib$rsvp$instrument$$default(settled === lib$rsvp$$internal$$FULFILLED ? 'fulfilled' : 'rejected', promise);
}
if (subscribers.length === 0) { return; }
var child, callback, detail = promise._result;
for (var i = 0; i < subscribers.length; i += 3) {
child = subscribers[i];
callback = subscribers[i + settled];
if (child) {
lib$rsvp$$internal$$invokeCallback(settled, child, callback, detail);
} else {
callback(detail);
}
}
promise._subscribers.length = 0;
}
function lib$rsvp$$internal$$ErrorObject() {
this.error = null;
}
var lib$rsvp$$internal$$TRY_CATCH_ERROR = new lib$rsvp$$internal$$ErrorObject();
function lib$rsvp$$internal$$tryCatch(callback, detail) {
try {
return callback(detail);
} catch(e) {
lib$rsvp$$internal$$TRY_CATCH_ERROR.error = e;
return lib$rsvp$$internal$$TRY_CATCH_ERROR;
}
}
function lib$rsvp$$internal$$invokeCallback(settled, promise, callback, detail) {
var hasCallback = lib$rsvp$utils$$isFunction(callback),
value, error, succeeded, failed;
if (hasCallback) {
value = lib$rsvp$$internal$$tryCatch(callback, detail);
if (value === lib$rsvp$$internal$$TRY_CATCH_ERROR) {
failed = true;
error = value.error;
value = null;
} else {
succeeded = true;
}
if (promise === value) {
lib$rsvp$$internal$$reject(promise, lib$rsvp$$internal$$withOwnPromise());
return;
}
} else {
value = detail;
succeeded = true;
}
if (promise._state !== lib$rsvp$$internal$$PENDING) {
// noop
} else if (hasCallback && succeeded) {
lib$rsvp$$internal$$resolve(promise, value);
} else if (failed) {
lib$rsvp$$internal$$reject(promise, error);
} else if (settled === lib$rsvp$$internal$$FULFILLED) {
lib$rsvp$$internal$$fulfill(promise, value);
} else if (settled === lib$rsvp$$internal$$REJECTED) {
lib$rsvp$$internal$$reject(promise, value);
}
}
function lib$rsvp$$internal$$initializePromise(promise, resolver) {
var resolved = false;
try {
resolver(function resolvePromise(value){
if (resolved) { return; }
resolved = true;
lib$rsvp$$internal$$resolve(promise, value);
}, function rejectPromise(reason) {
if (resolved) { return; }
resolved = true;
lib$rsvp$$internal$$reject(promise, reason);
});
} catch(e) {
lib$rsvp$$internal$$reject(promise, e);
}
}
function lib$rsvp$enumerator$$makeSettledResult(state, position, value) {
if (state === lib$rsvp$$internal$$FULFILLED) {
return {
state: 'fulfilled',
value: value
};
} else {
return {
state: 'rejected',
reason: value
};
}
}
function lib$rsvp$enumerator$$Enumerator(Constructor, input, abortOnReject, label) {
var enumerator = this;
enumerator._instanceConstructor = Constructor;
enumerator.promise = new Constructor(lib$rsvp$$internal$$noop, label);
enumerator._abortOnReject = abortOnReject;
if (enumerator._validateInput(input)) {
enumerator._input = input;
enumerator.length = input.length;
enumerator._remaining = input.length;
enumerator._init();
if (enumerator.length === 0) {
lib$rsvp$$internal$$fulfill(enumerator.promise, enumerator._result);
} else {
enumerator.length = enumerator.length || 0;
enumerator._enumerate();
if (enumerator._remaining === 0) {
lib$rsvp$$internal$$fulfill(enumerator.promise, enumerator._result);
}
}
} else {
lib$rsvp$$internal$$reject(enumerator.promise, enumerator._validationError());
}
}
var lib$rsvp$enumerator$$default = lib$rsvp$enumerator$$Enumerator;
lib$rsvp$enumerator$$Enumerator.prototype._validateInput = function(input) {
return lib$rsvp$utils$$isArray(input);
};
lib$rsvp$enumerator$$Enumerator.prototype._validationError = function() {
return new Error('Array Methods must be provided an Array');
};
lib$rsvp$enumerator$$Enumerator.prototype._init = function() {
this._result = new Array(this.length);
};
lib$rsvp$enumerator$$Enumerator.prototype._enumerate = function() {
var enumerator = this;
var length = enumerator.length;
var promise = enumerator.promise;
var input = enumerator._input;
for (var i = 0; promise._state === lib$rsvp$$internal$$PENDING && i < length; i++) {
enumerator._eachEntry(input[i], i);
}
};
lib$rsvp$enumerator$$Enumerator.prototype._eachEntry = function(entry, i) {
var enumerator = this;
var c = enumerator._instanceConstructor;
if (lib$rsvp$utils$$isMaybeThenable(entry)) {
if (entry.constructor === c && entry._state !== lib$rsvp$$internal$$PENDING) {
entry._onError = null;
enumerator._settledAt(entry._state, i, entry._result);
} else {
enumerator._willSettleAt(c.resolve(entry), i);
}
} else {
enumerator._remaining--;
enumerator._result[i] = enumerator._makeResult(lib$rsvp$$internal$$FULFILLED, i, entry);
}
};
lib$rsvp$enumerator$$Enumerator.prototype._settledAt = function(state, i, value) {
var enumerator = this;
var promise = enumerator.promise;
if (promise._state === lib$rsvp$$internal$$PENDING) {
enumerator._remaining--;
if (enumerator._abortOnReject && state === lib$rsvp$$internal$$REJECTED) {
lib$rsvp$$internal$$reject(promise, value);
} else {
enumerator._result[i] = enumerator._makeResult(state, i, value);
}
}
if (enumerator._remaining === 0) {
lib$rsvp$$internal$$fulfill(promise, enumerator._result);
}
};
lib$rsvp$enumerator$$Enumerator.prototype._makeResult = function(state, i, value) {
return value;
};
lib$rsvp$enumerator$$Enumerator.prototype._willSettleAt = function(promise, i) {
var enumerator = this;
lib$rsvp$$internal$$subscribe(promise, undefined, function(value) {
enumerator._settledAt(lib$rsvp$$internal$$FULFILLED, i, value);
}, function(reason) {
enumerator._settledAt(lib$rsvp$$internal$$REJECTED, i, reason);
});
};
function lib$rsvp$promise$all$$all(entries, label) {
return new lib$rsvp$enumerator$$default(this, entries, true /* abort on reject */, label).promise;
}
var lib$rsvp$promise$all$$default = lib$rsvp$promise$all$$all;
function lib$rsvp$promise$race$$race(entries, label) {
/*jshint validthis:true */
var Constructor = this;
var promise = new Constructor(lib$rsvp$$internal$$noop, label);
if (!lib$rsvp$utils$$isArray(entries)) {
lib$rsvp$$internal$$reject(promise, new TypeError('You must pass an array to race.'));
return promise;
}
var length = entries.length;
function onFulfillment(value) {
lib$rsvp$$internal$$resolve(promise, value);
}
function onRejection(reason) {
lib$rsvp$$internal$$reject(promise, reason);
}
for (var i = 0; promise._state === lib$rsvp$$internal$$PENDING && i < length; i++) {
lib$rsvp$$internal$$subscribe(Constructor.resolve(entries[i]), undefined, onFulfillment, onRejection);
}
return promise;
}
var lib$rsvp$promise$race$$default = lib$rsvp$promise$race$$race;
function lib$rsvp$promise$resolve$$resolve(object, label) {
/*jshint validthis:true */
var Constructor = this;
if (object && typeof object === 'object' && object.constructor === Constructor) {
return object;
}
var promise = new Constructor(lib$rsvp$$internal$$noop, label);
lib$rsvp$$internal$$resolve(promise, object);
return promise;
}
var lib$rsvp$promise$resolve$$default = lib$rsvp$promise$resolve$$resolve;
function lib$rsvp$promise$reject$$reject(reason, label) {
/*jshint validthis:true */
var Constructor = this;
var promise = new Constructor(lib$rsvp$$internal$$noop, label);
lib$rsvp$$internal$$reject(promise, reason);
return promise;
}
var lib$rsvp$promise$reject$$default = lib$rsvp$promise$reject$$reject;
var lib$rsvp$promise$$guidKey = 'rsvp_' + lib$rsvp$utils$$now() + '-';
var lib$rsvp$promise$$counter = 0;
function lib$rsvp$promise$$needsResolver() {
throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
}
function lib$rsvp$promise$$needsNew() {
throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
}
function lib$rsvp$promise$$Promise(resolver, label) {
var promise = this;
promise._id = lib$rsvp$promise$$counter++;
promise._label = label;
promise._state = undefined;
promise._result = undefined;
promise._subscribers = [];
if (lib$rsvp$config$$config.instrument) {
lib$rsvp$instrument$$default('created', promise);
}
if (lib$rsvp$$internal$$noop !== resolver) {
if (!lib$rsvp$utils$$isFunction(resolver)) {
lib$rsvp$promise$$needsResolver();
}
if (!(promise instanceof lib$rsvp$promise$$Promise)) {
lib$rsvp$promise$$needsNew();
}
lib$rsvp$$internal$$initializePromise(promise, resolver);
}
}
var lib$rsvp$promise$$default = lib$rsvp$promise$$Promise;
// deprecated
lib$rsvp$promise$$Promise.cast = lib$rsvp$promise$resolve$$default;
lib$rsvp$promise$$Promise.all = lib$rsvp$promise$all$$default;
lib$rsvp$promise$$Promise.race = lib$rsvp$promise$race$$default;
lib$rsvp$promise$$Promise.resolve = lib$rsvp$promise$resolve$$default;
lib$rsvp$promise$$Promise.reject = lib$rsvp$promise$reject$$default;
lib$rsvp$promise$$Promise.prototype = {
constructor: lib$rsvp$promise$$Promise,
_guidKey: lib$rsvp$promise$$guidKey,
_onError: function (reason) {
var promise = this;
lib$rsvp$config$$config.after(function() {
if (promise._onError) {
lib$rsvp$config$$config['trigger']('error', reason);
}
});
},
/**
The primary way of interacting with a promise is through its `then` method,
which registers callbacks to receive either a promise's eventual value or the
reason why the promise cannot be fulfilled.
```js
findUser().then(function(user){
// user is available
}, function(reason){
// user is unavailable, and you are given the reason why
});
```
Chaining
--------
The return value of `then` is itself a promise. This second, 'downstream'
promise is resolved with the return value of the first promise's fulfillment
or rejection handler, or rejected if the handler throws an exception.
```js
findUser().then(function (user) {
return user.name;
}, function (reason) {
return 'default name';
}).then(function (userName) {
// If `findUser` fulfilled, `userName` will be the user's name, otherwise it
// will be `'default name'`
});
findUser().then(function (user) {
throw new Error('Found user, but still unhappy');
}, function (reason) {
throw new Error('`findUser` rejected and we're unhappy');
}).then(function (value) {
// never reached
}, function (reason) {
// if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
// If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
});
```
If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
```js
findUser().then(function (user) {
throw new PedagogicalException('Upstream error');
}).then(function (value) {
// never reached
}).then(function (value) {
// never reached
}, function (reason) {
// The `PedgagocialException` is propagated all the way down to here
});
```
Assimilation
------------
Sometimes the value you want to propagate to a downstream promise can only be
retrieved asynchronously. This can be achieved by returning a promise in the
fulfillment or rejection handler. The downstream promise will then be pending
until the returned promise is settled. This is called *assimilation*.
```js
findUser().then(function (user) {
return findCommentsByAuthor(user);
}).then(function (comments) {
// The user's comments are now available
});
```
If the assimliated promise rejects, then the downstream promise will also reject.
```js
findUser().then(function (user) {
return findCommentsByAuthor(user);
}).then(function (comments) {
// If `findCommentsByAuthor` fulfills, we'll have the value here
}, function (reason) {
// If `findCommentsByAuthor` rejects, we'll have the reason here
});
```
Simple Example
--------------
Synchronous Example
```javascript
var result;
try {
result = findResult();
// success
} catch(reason) {
// failure
}
```
Errback Example
```js
findResult(function(result, err){
if (err) {
// failure
} else {
// success
}
});
```
Promise Example;
```javascript
findResult().then(function(result){
// success
}, function(reason){
// failure
});
```
Advanced Example
--------------
Synchronous Example
```javascript
var author, books;
try {
author = findAuthor();
books = findBooksByAuthor(author);
// success
} catch(reason) {
// failure
}
```
Errback Example
```js
function foundBooks(books) {
}
function failure(reason) {
}
findAuthor(function(author, err){
if (err) {
failure(err);
// failure
} else {
try {
findBoooksByAuthor(author, function(books, err) {
if (err) {
failure(err);
} else {
try {
foundBooks(books);
} catch(reason) {
failure(reason);
}
}
});
} catch(error) {
failure(err);
}
// success
}
});
```
Promise Example;
```javascript
findAuthor().
then(findBooksByAuthor).
then(function(books){
// found books
}).catch(function(reason){
// something went wrong
});
```
@method then
@param {Function} onFulfillment
@param {Function} onRejection
@param {String} label optional string for labeling the promise.
Useful for tooling.
@return {Promise}
*/
then: function(onFulfillment, onRejection, label) {
var parent = this;
var state = parent._state;
if (state === lib$rsvp$$internal$$FULFILLED && !onFulfillment || state === lib$rsvp$$internal$$REJECTED && !onRejection) {
if (lib$rsvp$config$$config.instrument) {
lib$rsvp$instrument$$default('chained', parent, parent);
}
return parent;
}
parent._onError = null;
var child = new parent.constructor(lib$rsvp$$internal$$noop, label);
var result = parent._result;
if (lib$rsvp$config$$config.instrument) {
lib$rsvp$instrument$$default('chained', parent, child);
}
if (state) {
var callback = arguments[state - 1];
lib$rsvp$config$$config.async(function(){
lib$rsvp$$internal$$invokeCallback(state, child, callback, result);
});
} else {
lib$rsvp$$internal$$subscribe(parent, child, onFulfillment, onRejection);
}
return child;
},
/**
`catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
as the catch block of a try/catch statement.
```js
function findAuthor(){
throw new Error('couldn't find that author');
}
// synchronous
try {
findAuthor();
} catch(reason) {
// something went wrong
}
// async with promises
findAuthor().catch(function(reason){
// something went wrong
});
```
@method catch
@param {Function} onRejection
@param {String} label optional string for labeling the promise.
Useful for tooling.
@return {Promise}
*/
'catch': function(onRejection, label) {
return this.then(undefined, onRejection, label);
},
/**
`finally` will be invoked regardless of the promise's fate just as native
try/catch/finally behaves
Synchronous example:
```js
findAuthor() {
if (Math.random() > 0.5) {
throw new Error();
}
return new Author();
}
try {
return findAuthor(); // succeed or fail
} catch(error) {
return findOtherAuther();
} finally {
// always runs
// doesn't affect the return value
}
```
Asynchronous example:
```js
findAuthor().catch(function(reason){
return findOtherAuther();
}).finally(function(){
// author was either found, or not
});
```
@method finally
@param {Function} callback
@param {String} label optional string for labeling the promise.
Useful for tooling.
@return {Promise}
*/
'finally': function(callback, label) {
var promise = this;
var constructor = promise.constructor;
return promise.then(function(value) {
return constructor.resolve(callback()).then(function(){
return value;
});
}, function(reason) {
return constructor.resolve(callback()).then(function(){
throw reason;
});
}, label);
}
};
function lib$rsvp$all$settled$$AllSettled(Constructor, entries, label) {
this._superConstructor(Constructor, entries, false /* don't abort on reject */, label);
}
lib$rsvp$all$settled$$AllSettled.prototype = lib$rsvp$utils$$o_create(lib$rsvp$enumerator$$default.prototype);
lib$rsvp$all$settled$$AllSettled.prototype._superConstructor = lib$rsvp$enumerator$$default;
lib$rsvp$all$settled$$AllSettled.prototype._makeResult = lib$rsvp$enumerator$$makeSettledResult;
lib$rsvp$all$settled$$AllSettled.prototype._validationError = function() {
return new Error('allSettled must be called with an array');
};
function lib$rsvp$all$settled$$allSettled(entries, label) {
return new lib$rsvp$all$settled$$AllSettled(lib$rsvp$promise$$default, entries, label).promise;
}
var lib$rsvp$all$settled$$default = lib$rsvp$all$settled$$allSettled;
function lib$rsvp$all$$all(array, label) {
return lib$rsvp$promise$$default.all(array, label);
}
var lib$rsvp$all$$default = lib$rsvp$all$$all;
var lib$rsvp$asap$$len = 0;
var lib$rsvp$asap$$toString = {}.toString;
var lib$rsvp$asap$$vertxNext;
function lib$rsvp$asap$$asap(callback, arg) {
lib$rsvp$asap$$queue[lib$rsvp$asap$$len] = callback;
lib$rsvp$asap$$queue[lib$rsvp$asap$$len + 1] = arg;
lib$rsvp$asap$$len += 2;
if (lib$rsvp$asap$$len === 2) {
// If len is 1, that means that we need to schedule an async flush.
// If additional callbacks are queued before the queue is flushed, they
// will be processed by this flush that we are scheduling.
lib$rsvp$asap$$scheduleFlush();
}
}
var lib$rsvp$asap$$default = lib$rsvp$asap$$asap;
var lib$rsvp$asap$$browserWindow = (typeof window !== 'undefined') ? window : undefined;
var lib$rsvp$asap$$browserGlobal = lib$rsvp$asap$$browserWindow || {};
var lib$rsvp$asap$$BrowserMutationObserver = lib$rsvp$asap$$browserGlobal.MutationObserver || lib$rsvp$asap$$browserGlobal.WebKitMutationObserver;
var lib$rsvp$asap$$isNode = typeof self === 'undefined' &&
typeof process !== 'undefined' && {}.toString.call(process) === '[object process]';
// test for web worker but not in IE10
var lib$rsvp$asap$$isWorker = typeof Uint8ClampedArray !== 'undefined' &&
typeof importScripts !== 'undefined' &&
typeof MessageChannel !== 'undefined';
// node
function lib$rsvp$asap$$useNextTick() {
var nextTick = process.nextTick;
// node version 0.10.x displays a deprecation warning when nextTick is used recursively
// setImmediate should be used instead instead
var version = process.versions.node.match(/^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$/);
if (Array.isArray(version) && version[1] === '0' && version[2] === '10') {
nextTick = setImmediate;
}
return function() {
nextTick(lib$rsvp$asap$$flush);
};
}
// vertx
function lib$rsvp$asap$$useVertxTimer() {
return function() {
lib$rsvp$asap$$vertxNext(lib$rsvp$asap$$flush);
};
}
function lib$rsvp$asap$$useMutationObserver() {
var iterations = 0;
var observer = new lib$rsvp$asap$$BrowserMutationObserver(lib$rsvp$asap$$flush);
var node = document.createTextNode('');
observer.observe(node, { characterData: true });
return function() {
node.data = (iterations = ++iterations % 2);
};
}
// web worker
function lib$rsvp$asap$$useMessageChannel() {
var channel = new MessageChannel();
channel.port1.onmessage = lib$rsvp$asap$$flush;
return function () {
channel.port2.postMessage(0);
};
}
function lib$rsvp$asap$$useSetTimeout() {
return function() {
setTimeout(lib$rsvp$asap$$flush, 1);
};
}
var lib$rsvp$asap$$queue = new Array(1000);
function lib$rsvp$asap$$flush() {
for (var i = 0; i < lib$rsvp$asap$$len; i+=2) {
var callback = lib$rsvp$asap$$queue[i];
var arg = lib$rsvp$asap$$queue[i+1];
callback(arg);
lib$rsvp$asap$$queue[i] = undefined;
lib$rsvp$asap$$queue[i+1] = undefined;
}
lib$rsvp$asap$$len = 0;
}
function lib$rsvp$asap$$attemptVertex() {
try {
var r = require;
var vertx = r('vertx');
lib$rsvp$asap$$vertxNext = vertx.runOnLoop || vertx.runOnContext;
return lib$rsvp$asap$$useVertxTimer();
} catch(e) {
return lib$rsvp$asap$$useSetTimeout();
}
}
var lib$rsvp$asap$$scheduleFlush;
// Decide what async method to use to triggering processing of queued callbacks:
if (lib$rsvp$asap$$isNode) {
lib$rsvp$asap$$scheduleFlush = lib$rsvp$asap$$useNextTick();
} else if (lib$rsvp$asap$$BrowserMutationObserver) {
lib$rsvp$asap$$scheduleFlush = lib$rsvp$asap$$useMutationObserver();
} else if (lib$rsvp$asap$$isWorker) {
lib$rsvp$asap$$scheduleFlush = lib$rsvp$asap$$useMessageChannel();
} else if (lib$rsvp$asap$$browserWindow === undefined && typeof require === 'function') {
lib$rsvp$asap$$scheduleFlush = lib$rsvp$asap$$attemptVertex();
} else {
lib$rsvp$asap$$scheduleFlush = lib$rsvp$asap$$useSetTimeout();
}
function lib$rsvp$defer$$defer(label) {
var deferred = {};
deferred['promise'] = new lib$rsvp$promise$$default(function(resolve, reject) {
deferred['resolve'] = resolve;
deferred['reject'] = reject;
}, label);
return deferred;
}
var lib$rsvp$defer$$default = lib$rsvp$defer$$defer;
function lib$rsvp$filter$$filter(promises, filterFn, label) {
return lib$rsvp$promise$$default.all(promises, label).then(function(values) {
if (!lib$rsvp$utils$$isFunction(filterFn)) {
throw new TypeError("You must pass a function as filter's second argument.");
}
var length = values.length;
var filtered = new Array(length);
for (var i = 0; i < length; i++) {
filtered[i] = filterFn(values[i]);
}
return lib$rsvp$promise$$default.all(filtered, label).then(function(filtered) {
var results = new Array(length);
var newLength = 0;
for (var i = 0; i < length; i++) {
if (filtered[i]) {
results[newLength] = values[i];
newLength++;
}
}
results.length = newLength;
return results;
});
});
}
var lib$rsvp$filter$$default = lib$rsvp$filter$$filter;
function lib$rsvp$promise$hash$$PromiseHash(Constructor, object, label) {
this._superConstructor(Constructor, object, true, label);
}
var lib$rsvp$promise$hash$$default = lib$rsvp$promise$hash$$PromiseHash;
lib$rsvp$promise$hash$$PromiseHash.prototype = lib$rsvp$utils$$o_create(lib$rsvp$enumerator$$default.prototype);
lib$rsvp$promise$hash$$PromiseHash.prototype._superConstructor = lib$rsvp$enumerator$$default;
lib$rsvp$promise$hash$$PromiseHash.prototype._init = function() {
this._result = {};
};
lib$rsvp$promise$hash$$PromiseHash.prototype._validateInput = function(input) {
return input && typeof input === 'object';
};
lib$rsvp$promise$hash$$PromiseHash.prototype._validationError = function() {
return new Error('Promise.hash must be called with an object');
};
lib$rsvp$promise$hash$$PromiseHash.prototype._enumerate = function() {
var enumerator = this;
var promise = enumerator.promise;
var input = enumerator._input;
var results = [];
for (var key in input) {
if (promise._state === lib$rsvp$$internal$$PENDING && Object.prototype.hasOwnProperty.call(input, key)) {
results.push({
position: key,
entry: input[key]
});
}
}
var length = results.length;
enumerator._remaining = length;
var result;
for (var i = 0; promise._state === lib$rsvp$$internal$$PENDING && i < length; i++) {
result = results[i];
enumerator._eachEntry(result.entry, result.position);
}
};
function lib$rsvp$hash$settled$$HashSettled(Constructor, object, label) {
this._superConstructor(Constructor, object, false, label);
}
lib$rsvp$hash$settled$$HashSettled.prototype = lib$rsvp$utils$$o_create(lib$rsvp$promise$hash$$default.prototype);
lib$rsvp$hash$settled$$HashSettled.prototype._superConstructor = lib$rsvp$enumerator$$default;
lib$rsvp$hash$settled$$HashSettled.prototype._makeResult = lib$rsvp$enumerator$$makeSettledResult;
lib$rsvp$hash$settled$$HashSettled.prototype._validationError = function() {
return new Error('hashSettled must be called with an object');
};
function lib$rsvp$hash$settled$$hashSettled(object, label) {
return new lib$rsvp$hash$settled$$HashSettled(lib$rsvp$promise$$default, object, label).promise;
}
var lib$rsvp$hash$settled$$default = lib$rsvp$hash$settled$$hashSettled;
function lib$rsvp$hash$$hash(object, label) {
return new lib$rsvp$promise$hash$$default(lib$rsvp$promise$$default, object, label).promise;
}
var lib$rsvp$hash$$default = lib$rsvp$hash$$hash;
function lib$rsvp$map$$map(promises, mapFn, label) {
return lib$rsvp$promise$$default.all(promises, label).then(function(values) {
if (!lib$rsvp$utils$$isFunction(mapFn)) {
throw new TypeError("You must pass a function as map's second argument.");
}
var length = values.length;
var results = new Array(length);
for (var i = 0; i < length; i++) {
results[i] = mapFn(values[i]);
}
return lib$rsvp$promise$$default.all(results, label);
});
}
var lib$rsvp$map$$default = lib$rsvp$map$$map;
function lib$rsvp$node$$Result() {
this.value = undefined;
}
var lib$rsvp$node$$ERROR = new lib$rsvp$node$$Result();
var lib$rsvp$node$$GET_THEN_ERROR = new lib$rsvp$node$$Result();
function lib$rsvp$node$$getThen(obj) {
try {
return obj.then;
} catch(error) {
lib$rsvp$node$$ERROR.value= error;
return lib$rsvp$node$$ERROR;
}
}
function lib$rsvp$node$$tryApply(f, s, a) {
try {
f.apply(s, a);
} catch(error) {
lib$rsvp$node$$ERROR.value = error;
return lib$rsvp$node$$ERROR;
}
}
function lib$rsvp$node$$makeObject(_, argumentNames) {
var obj = {};
var name;
var i;
var length = _.length;
var args = new Array(length);
for (var x = 0; x < length; x++) {
args[x] = _[x];
}
for (i = 0; i < argumentNames.length; i++) {
name = argumentNames[i];
obj[name] = args[i + 1];
}
return obj;
}
function lib$rsvp$node$$arrayResult(_) {
var length = _.length;
var args = new Array(length - 1);
for (var i = 1; i < length; i++) {
args[i - 1] = _[i];
}
return args;
}
function lib$rsvp$node$$wrapThenable(then, promise) {
return {
then: function(onFulFillment, onRejection) {
return then.call(promise, onFulFillment, onRejection);
}
};
}
function lib$rsvp$node$$denodeify(nodeFunc, options) {
var fn = function() {
var self = this;
var l = arguments.length;
var args = new Array(l + 1);
var arg;
var promiseInput = false;
for (var i = 0; i < l; ++i) {
arg = arguments[i];
if (!promiseInput) {
// TODO: clean this up
promiseInput = lib$rsvp$node$$needsPromiseInput(arg);
if (promiseInput === lib$rsvp$node$$GET_THEN_ERROR) {
var p = new lib$rsvp$promise$$default(lib$rsvp$$internal$$noop);
lib$rsvp$$internal$$reject(p, lib$rsvp$node$$GET_THEN_ERROR.value);
return p;
} else if (promiseInput && promiseInput !== true) {
arg = lib$rsvp$node$$wrapThenable(promiseInput, arg);
}
}
args[i] = arg;
}
var promise = new lib$rsvp$promise$$default(lib$rsvp$$internal$$noop);
args[l] = function(err, val) {
if (err)
lib$rsvp$$internal$$reject(promise, err);
else if (options === undefined)
lib$rsvp$$internal$$resolve(promise, val);
else if (options === true)
lib$rsvp$$internal$$resolve(promise, lib$rsvp$node$$arrayResult(arguments));
else if (lib$rsvp$utils$$isArray(options))
lib$rsvp$$internal$$resolve(promise, lib$rsvp$node$$makeObject(arguments, options));
else
lib$rsvp$$internal$$resolve(promise, val);
};
if (promiseInput) {
return lib$rsvp$node$$handlePromiseInput(promise, args, nodeFunc, self);
} else {
return lib$rsvp$node$$handleValueInput(promise, args, nodeFunc, self);
}
};
fn.__proto__ = nodeFunc;
return fn;
}
var lib$rsvp$node$$default = lib$rsvp$node$$denodeify;
function lib$rsvp$node$$handleValueInput(promise, args, nodeFunc, self) {
var result = lib$rsvp$node$$tryApply(nodeFunc, self, args);
if (result === lib$rsvp$node$$ERROR) {
lib$rsvp$$internal$$reject(promise, result.value);
}
return promise;
}
function lib$rsvp$node$$handlePromiseInput(promise, args, nodeFunc, self){
return lib$rsvp$promise$$default.all(args).then(function(args){
var result = lib$rsvp$node$$tryApply(nodeFunc, self, args);
if (result === lib$rsvp$node$$ERROR) {
lib$rsvp$$internal$$reject(promise, result.value);
}
return promise;
});
}
function lib$rsvp$node$$needsPromiseInput(arg) {
if (arg && typeof arg === 'object') {
if (arg.constructor === lib$rsvp$promise$$default) {
return true;
} else {
return lib$rsvp$node$$getThen(arg);
}
} else {
return false;
}
}
var lib$rsvp$platform$$platform;
/* global self */
if (typeof self === 'object') {
lib$rsvp$platform$$platform = self;
/* global global */
} else if (typeof global === 'object') {
lib$rsvp$platform$$platform = global;
} else {
throw new Error('no global: `self` or `global` found');
}
var lib$rsvp$platform$$default = lib$rsvp$platform$$platform;
function lib$rsvp$race$$race(array, label) {
return lib$rsvp$promise$$default.race(array, label);
}
var lib$rsvp$race$$default = lib$rsvp$race$$race;
function lib$rsvp$reject$$reject(reason, label) {
return lib$rsvp$promise$$default.reject(reason, label);
}
var lib$rsvp$reject$$default = lib$rsvp$reject$$reject;
function lib$rsvp$resolve$$resolve(value, label) {
return lib$rsvp$promise$$default.resolve(value, label);
}
var lib$rsvp$resolve$$default = lib$rsvp$resolve$$resolve;
function lib$rsvp$rethrow$$rethrow(reason) {
setTimeout(function() {
throw reason;
});
throw reason;
}
var lib$rsvp$rethrow$$default = lib$rsvp$rethrow$$rethrow;
// defaults
lib$rsvp$config$$config.async = lib$rsvp$asap$$default;
lib$rsvp$config$$config.after = function(cb) {
setTimeout(cb, 0);
};
var lib$rsvp$$cast = lib$rsvp$resolve$$default;
function lib$rsvp$$async(callback, arg) {
lib$rsvp$config$$config.async(callback, arg);
}
function lib$rsvp$$on() {
lib$rsvp$config$$config['on'].apply(lib$rsvp$config$$config, arguments);
}
function lib$rsvp$$off() {
lib$rsvp$config$$config['off'].apply(lib$rsvp$config$$config, arguments);
}
// Set up instrumentation through `window.__PROMISE_INTRUMENTATION__`
if (typeof window !== 'undefined' && typeof window['__PROMISE_INSTRUMENTATION__'] === 'object') {
var lib$rsvp$$callbacks = window['__PROMISE_INSTRUMENTATION__'];
lib$rsvp$config$$configure('instrument', true);
for (var lib$rsvp$$eventName in lib$rsvp$$callbacks) {
if (lib$rsvp$$callbacks.hasOwnProperty(lib$rsvp$$eventName)) {
lib$rsvp$$on(lib$rsvp$$eventName, lib$rsvp$$callbacks[lib$rsvp$$eventName]);
}
}
}
var lib$rsvp$umd$$RSVP = {
'race': lib$rsvp$race$$default,
'Promise': lib$rsvp$promise$$default,
'allSettled': lib$rsvp$all$settled$$default,
'hash': lib$rsvp$hash$$default,
'hashSettled': lib$rsvp$hash$settled$$default,
'denodeify': lib$rsvp$node$$default,
'on': lib$rsvp$$on,