1 | /*!
|
2 | * @overview RSVP - a tiny implementation of Promises/A+.
|
3 | * @copyright Copyright (c) 2016 Yehuda Katz, Tom Dale, Stefan Penner and contributors
|
4 | * @license Licensed under MIT license
|
5 | * See https://raw.githubusercontent.com/tildeio/rsvp.js/master/LICENSE
|
6 | * @version 4.7.0
|
7 | */
|
8 |
|
9 | function callbacksFor(object) {
|
10 | var callbacks = object._promiseCallbacks;
|
11 |
|
12 | if (!callbacks) {
|
13 | callbacks = object._promiseCallbacks = {};
|
14 | }
|
15 |
|
16 | return callbacks;
|
17 | }
|
18 |
|
19 | /**
|
20 | @class RSVP.EventTarget
|
21 | */
|
22 | var EventTarget = {
|
23 |
|
24 | /**
|
25 | `RSVP.EventTarget.mixin` extends an object with EventTarget methods. For
|
26 | Example:
|
27 | ```javascript
|
28 | let object = {};
|
29 | RSVP.EventTarget.mixin(object);
|
30 | object.on('finished', function(event) {
|
31 | // handle event
|
32 | });
|
33 | object.trigger('finished', { detail: value });
|
34 | ```
|
35 | `EventTarget.mixin` also works with prototypes:
|
36 | ```javascript
|
37 | let Person = function() {};
|
38 | RSVP.EventTarget.mixin(Person.prototype);
|
39 | let yehuda = new Person();
|
40 | let tom = new Person();
|
41 | yehuda.on('poke', function(event) {
|
42 | console.log('Yehuda says OW');
|
43 | });
|
44 | tom.on('poke', function(event) {
|
45 | console.log('Tom says OW');
|
46 | });
|
47 | yehuda.trigger('poke');
|
48 | tom.trigger('poke');
|
49 | ```
|
50 | @method mixin
|
51 | @for RSVP.EventTarget
|
52 | @private
|
53 | @param {Object} object object to extend with EventTarget methods
|
54 | */
|
55 | mixin: function (object) {
|
56 | object['on'] = this['on'];
|
57 | object['off'] = this['off'];
|
58 | object['trigger'] = this['trigger'];
|
59 | object._promiseCallbacks = undefined;
|
60 | return object;
|
61 | },
|
62 |
|
63 |
|
64 | /**
|
65 | Registers a callback to be executed when `eventName` is triggered
|
66 | ```javascript
|
67 | object.on('event', function(eventInfo){
|
68 | // handle the event
|
69 | });
|
70 | object.trigger('event');
|
71 | ```
|
72 | @method on
|
73 | @for RSVP.EventTarget
|
74 | @private
|
75 | @param {String} eventName name of the event to listen for
|
76 | @param {Function} callback function to be called when the event is triggered.
|
77 | */
|
78 | on: function (eventName, callback) {
|
79 | if (typeof callback !== 'function') {
|
80 | throw new TypeError('Callback must be a function');
|
81 | }
|
82 |
|
83 | var allCallbacks = callbacksFor(this),
|
84 | callbacks = void 0;
|
85 |
|
86 | callbacks = allCallbacks[eventName];
|
87 |
|
88 | if (!callbacks) {
|
89 | callbacks = allCallbacks[eventName] = [];
|
90 | }
|
91 |
|
92 | if (callbacks.indexOf(callback)) {
|
93 | callbacks.push(callback);
|
94 | }
|
95 | },
|
96 |
|
97 |
|
98 | /**
|
99 | You can use `off` to stop firing a particular callback for an event:
|
100 | ```javascript
|
101 | function doStuff() { // do stuff! }
|
102 | object.on('stuff', doStuff);
|
103 | object.trigger('stuff'); // doStuff will be called
|
104 | // Unregister ONLY the doStuff callback
|
105 | object.off('stuff', doStuff);
|
106 | object.trigger('stuff'); // doStuff will NOT be called
|
107 | ```
|
108 | If you don't pass a `callback` argument to `off`, ALL callbacks for the
|
109 | event will not be executed when the event fires. For example:
|
110 | ```javascript
|
111 | let callback1 = function(){};
|
112 | let callback2 = function(){};
|
113 | object.on('stuff', callback1);
|
114 | object.on('stuff', callback2);
|
115 | object.trigger('stuff'); // callback1 and callback2 will be executed.
|
116 | object.off('stuff');
|
117 | object.trigger('stuff'); // callback1 and callback2 will not be executed!
|
118 | ```
|
119 | @method off
|
120 | @for RSVP.EventTarget
|
121 | @private
|
122 | @param {String} eventName event to stop listening to
|
123 | @param {Function} callback optional argument. If given, only the function
|
124 | given will be removed from the event's callback queue. If no `callback`
|
125 | argument is given, all callbacks will be removed from the event's callback
|
126 | queue.
|
127 | */
|
128 | off: function (eventName, callback) {
|
129 | var allCallbacks = callbacksFor(this),
|
130 | callbacks = void 0,
|
131 | index = void 0;
|
132 |
|
133 | if (!callback) {
|
134 | allCallbacks[eventName] = [];
|
135 | return;
|
136 | }
|
137 |
|
138 | callbacks = allCallbacks[eventName];
|
139 |
|
140 | index = callbacks.indexOf(callback);
|
141 |
|
142 | if (index !== -1) {
|
143 | callbacks.splice(index, 1);
|
144 | }
|
145 | },
|
146 |
|
147 |
|
148 | /**
|
149 | Use `trigger` to fire custom events. For example:
|
150 | ```javascript
|
151 | object.on('foo', function(){
|
152 | console.log('foo event happened!');
|
153 | });
|
154 | object.trigger('foo');
|
155 | // 'foo event happened!' logged to the console
|
156 | ```
|
157 | You can also pass a value as a second argument to `trigger` that will be
|
158 | passed as an argument to all event listeners for the event:
|
159 | ```javascript
|
160 | object.on('foo', function(value){
|
161 | console.log(value.name);
|
162 | });
|
163 | object.trigger('foo', { name: 'bar' });
|
164 | // 'bar' logged to the console
|
165 | ```
|
166 | @method trigger
|
167 | @for RSVP.EventTarget
|
168 | @private
|
169 | @param {String} eventName name of the event to be triggered
|
170 | @param {*} options optional value to be passed to any event handlers for
|
171 | the given `eventName`
|
172 | */
|
173 | trigger: function (eventName, options, label) {
|
174 | var allCallbacks = callbacksFor(this),
|
175 | callbacks = void 0,
|
176 | callback = void 0;
|
177 |
|
178 | if (callbacks = allCallbacks[eventName]) {
|
179 | // Don't cache the callbacks.length since it may grow
|
180 | for (var i = 0; i < callbacks.length; i++) {
|
181 | callback = callbacks[i];
|
182 |
|
183 | callback(options, label);
|
184 | }
|
185 | }
|
186 | }
|
187 | };
|
188 |
|
189 | var config = {
|
190 | instrument: false
|
191 | };
|
192 |
|
193 | EventTarget['mixin'](config);
|
194 |
|
195 | function configure(name, value) {
|
196 | if (arguments.length === 2) {
|
197 | config[name] = value;
|
198 | } else {
|
199 | return config[name];
|
200 | }
|
201 | }
|
202 |
|
203 | var queue = [];
|
204 |
|
205 | function scheduleFlush() {
|
206 | setTimeout(function () {
|
207 | for (var i = 0; i < queue.length; i++) {
|
208 | var entry = queue[i];
|
209 |
|
210 | var payload = entry.payload;
|
211 |
|
212 | payload.guid = payload.key + payload.id;
|
213 | payload.childGuid = payload.key + payload.childId;
|
214 | if (payload.error) {
|
215 | payload.stack = payload.error.stack;
|
216 | }
|
217 |
|
218 | config['trigger'](entry.name, entry.payload);
|
219 | }
|
220 | queue.length = 0;
|
221 | }, 50);
|
222 | }
|
223 |
|
224 | function instrument(eventName, promise, child) {
|
225 | if (1 === queue.push({
|
226 | name: eventName,
|
227 | payload: {
|
228 | key: promise._guidKey,
|
229 | id: promise._id,
|
230 | eventName: eventName,
|
231 | detail: promise._result,
|
232 | childId: child && child._id,
|
233 | label: promise._label,
|
234 | timeStamp: Date.now(),
|
235 | error: config["instrument-with-stack"] ? new Error(promise._label) : null
|
236 | } })) {
|
237 | scheduleFlush();
|
238 | }
|
239 | }
|
240 |
|
241 | /**
|
242 | `RSVP.Promise.resolve` returns a promise that will become resolved with the
|
243 | passed `value`. It is shorthand for the following:
|
244 |
|
245 | ```javascript
|
246 | let promise = new RSVP.Promise(function(resolve, reject){
|
247 | resolve(1);
|
248 | });
|
249 |
|
250 | promise.then(function(value){
|
251 | // value === 1
|
252 | });
|
253 | ```
|
254 |
|
255 | Instead of writing the above, your code now simply becomes the following:
|
256 |
|
257 | ```javascript
|
258 | let promise = RSVP.Promise.resolve(1);
|
259 |
|
260 | promise.then(function(value){
|
261 | // value === 1
|
262 | });
|
263 | ```
|
264 |
|
265 | @method resolve
|
266 | @static
|
267 | @param {*} object value that the returned promise will be resolved with
|
268 | @param {String} label optional string for identifying the returned promise.
|
269 | Useful for tooling.
|
270 | @return {Promise} a promise that will become fulfilled with the given
|
271 | `value`
|
272 | */
|
273 | function resolve$1(object, label) {
|
274 | /*jshint validthis:true */
|
275 | var Constructor = this;
|
276 |
|
277 | if (object && typeof object === 'object' && object.constructor === Constructor) {
|
278 | return object;
|
279 | }
|
280 |
|
281 | var promise = new Constructor(noop, label);
|
282 | resolve(promise, object);
|
283 | return promise;
|
284 | }
|
285 |
|
286 | function withOwnPromise() {
|
287 | return new TypeError('A promises callback cannot return that same promise.');
|
288 | }
|
289 |
|
290 | function objectOrFunction(x) {
|
291 | var type = typeof x;
|
292 | return x !== null && (type === 'object' || type === 'function');
|
293 | }
|
294 |
|
295 | function noop() {}
|
296 |
|
297 | var PENDING = void 0;
|
298 | var FULFILLED = 1;
|
299 | var REJECTED = 2;
|
300 |
|
301 | function ErrorObject() {
|
302 | this.error = null;
|
303 | }
|
304 |
|
305 | var GET_THEN_ERROR = new ErrorObject();
|
306 |
|
307 | function getThen(promise) {
|
308 | try {
|
309 | return promise.then;
|
310 | } catch (error) {
|
311 | GET_THEN_ERROR.error = error;
|
312 | return GET_THEN_ERROR;
|
313 | }
|
314 | }
|
315 |
|
316 | var TRY_CATCH_ERROR = new ErrorObject();
|
317 |
|
318 | var tryCatchCallback = void 0;
|
319 | function tryCatcher() {
|
320 | try {
|
321 | var target = tryCatchCallback;
|
322 | tryCatchCallback = null;
|
323 | return target.apply(this, arguments);
|
324 | } catch (e) {
|
325 | TRY_CATCH_ERROR.error = e;
|
326 | return TRY_CATCH_ERROR;
|
327 | }
|
328 | }
|
329 |
|
330 | function tryCatch(fn) {
|
331 | tryCatchCallback = fn;
|
332 | return tryCatcher;
|
333 | }
|
334 |
|
335 | function tryThen(then$$1, value, fulfillmentHandler, rejectionHandler) {
|
336 | try {
|
337 | then$$1.call(value, fulfillmentHandler, rejectionHandler);
|
338 | } catch (e) {
|
339 | return e;
|
340 | }
|
341 | }
|
342 |
|
343 | function handleForeignThenable(promise, thenable, then$$1) {
|
344 | config.async(function (promise) {
|
345 | var sealed = false;
|
346 | var error = tryThen(then$$1, thenable, function (value) {
|
347 | if (sealed) {
|
348 | return;
|
349 | }
|
350 | sealed = true;
|
351 | if (thenable !== value) {
|
352 | resolve(promise, value, undefined);
|
353 | } else {
|
354 | fulfill(promise, value);
|
355 | }
|
356 | }, function (reason) {
|
357 | if (sealed) {
|
358 | return;
|
359 | }
|
360 | sealed = true;
|
361 |
|
362 | reject(promise, reason);
|
363 | }, 'Settle: ' + (promise._label || ' unknown promise'));
|
364 |
|
365 | if (!sealed && error) {
|
366 | sealed = true;
|
367 | reject(promise, error);
|
368 | }
|
369 | }, promise);
|
370 | }
|
371 |
|
372 | function handleOwnThenable(promise, thenable) {
|
373 | if (thenable._state === FULFILLED) {
|
374 | fulfill(promise, thenable._result);
|
375 | } else if (thenable._state === REJECTED) {
|
376 | thenable._onError = null;
|
377 | reject(promise, thenable._result);
|
378 | } else {
|
379 | subscribe(thenable, undefined, function (value) {
|
380 | if (thenable === value) {
|
381 | fulfill(promise, value);
|
382 | } else {
|
383 | resolve(promise, value);
|
384 | }
|
385 | }, function (reason) {
|
386 | return reject(promise, reason);
|
387 | });
|
388 | }
|
389 | }
|
390 |
|
391 | function handleMaybeThenable(promise, maybeThenable, then$$1) {
|
392 | var isOwnThenable = maybeThenable.constructor === promise.constructor && then$$1 === then && promise.constructor.resolve === resolve$1;
|
393 |
|
394 | if (isOwnThenable) {
|
395 | handleOwnThenable(promise, maybeThenable);
|
396 | } else if (then$$1 === GET_THEN_ERROR) {
|
397 | var error = GET_THEN_ERROR.error;
|
398 | GET_THEN_ERROR.error = null;
|
399 | reject(promise, error);
|
400 | } else if (typeof then$$1 === 'function') {
|
401 | handleForeignThenable(promise, maybeThenable, then$$1);
|
402 | } else {
|
403 | fulfill(promise, maybeThenable);
|
404 | }
|
405 | }
|
406 |
|
407 | function resolve(promise, value) {
|
408 | if (promise === value) {
|
409 | fulfill(promise, value);
|
410 | } else if (objectOrFunction(value)) {
|
411 | handleMaybeThenable(promise, value, getThen(value));
|
412 | } else {
|
413 | fulfill(promise, value);
|
414 | }
|
415 | }
|
416 |
|
417 | function publishRejection(promise) {
|
418 | if (promise._onError) {
|
419 | promise._onError(promise._result);
|
420 | }
|
421 |
|
422 | publish(promise);
|
423 | }
|
424 |
|
425 | function fulfill(promise, value) {
|
426 | if (promise._state !== PENDING) {
|
427 | return;
|
428 | }
|
429 |
|
430 | promise._result = value;
|
431 | promise._state = FULFILLED;
|
432 |
|
433 | if (promise._subscribers.length === 0) {
|
434 | if (config.instrument) {
|
435 | instrument('fulfilled', promise);
|
436 | }
|
437 | } else {
|
438 | config.async(publish, promise);
|
439 | }
|
440 | }
|
441 |
|
442 | function reject(promise, reason) {
|
443 | if (promise._state !== PENDING) {
|
444 | return;
|
445 | }
|
446 | promise._state = REJECTED;
|
447 | promise._result = reason;
|
448 | config.async(publishRejection, promise);
|
449 | }
|
450 |
|
451 | function subscribe(parent, child, onFulfillment, onRejection) {
|
452 | var subscribers = parent._subscribers;
|
453 | var length = subscribers.length;
|
454 |
|
455 | parent._onError = null;
|
456 |
|
457 | subscribers[length] = child;
|
458 | subscribers[length + FULFILLED] = onFulfillment;
|
459 | subscribers[length + REJECTED] = onRejection;
|
460 |
|
461 | if (length === 0 && parent._state) {
|
462 | config.async(publish, parent);
|
463 | }
|
464 | }
|
465 |
|
466 | function publish(promise) {
|
467 | var subscribers = promise._subscribers;
|
468 | var settled = promise._state;
|
469 |
|
470 | if (config.instrument) {
|
471 | instrument(settled === FULFILLED ? 'fulfilled' : 'rejected', promise);
|
472 | }
|
473 |
|
474 | if (subscribers.length === 0) {
|
475 | return;
|
476 | }
|
477 |
|
478 | var child = void 0,
|
479 | callback = void 0,
|
480 | result = promise._result;
|
481 |
|
482 | for (var i = 0; i < subscribers.length; i += 3) {
|
483 | child = subscribers[i];
|
484 | callback = subscribers[i + settled];
|
485 |
|
486 | if (child) {
|
487 | invokeCallback(settled, child, callback, result);
|
488 | } else {
|
489 | callback(result);
|
490 | }
|
491 | }
|
492 |
|
493 | promise._subscribers.length = 0;
|
494 | }
|
495 |
|
496 | function invokeCallback(state, promise, callback, result) {
|
497 | var hasCallback = typeof callback === 'function';
|
498 | var value = void 0;
|
499 |
|
500 | if (hasCallback) {
|
501 | value = tryCatch(callback)(result);
|
502 | } else {
|
503 | value = result;
|
504 | }
|
505 |
|
506 | if (promise._state !== PENDING) {
|
507 | // noop
|
508 | } else if (value === promise) {
|
509 | reject(promise, withOwnPromise());
|
510 | } else if (value === TRY_CATCH_ERROR) {
|
511 | var error = value.error;
|
512 | value.error = null; // release
|
513 | reject(promise, error);
|
514 | } else if (hasCallback) {
|
515 | resolve(promise, value);
|
516 | } else if (state === FULFILLED) {
|
517 | fulfill(promise, value);
|
518 | } else if (state === REJECTED) {
|
519 | reject(promise, value);
|
520 | }
|
521 | }
|
522 |
|
523 | function initializePromise(promise, resolver) {
|
524 | var resolved = false;
|
525 | try {
|
526 | resolver(function (value) {
|
527 | if (resolved) {
|
528 | return;
|
529 | }
|
530 | resolved = true;
|
531 | resolve(promise, value);
|
532 | }, function (reason) {
|
533 | if (resolved) {
|
534 | return;
|
535 | }
|
536 | resolved = true;
|
537 | reject(promise, reason);
|
538 | });
|
539 | } catch (e) {
|
540 | reject(promise, e);
|
541 | }
|
542 | }
|
543 |
|
544 | function then(onFulfillment, onRejection, label) {
|
545 | var parent = this;
|
546 | var state = parent._state;
|
547 |
|
548 | if (state === FULFILLED && !onFulfillment || state === REJECTED && !onRejection) {
|
549 | config.instrument && instrument('chained', parent, parent);
|
550 | return parent;
|
551 | }
|
552 |
|
553 | parent._onError = null;
|
554 |
|
555 | var child = new parent.constructor(noop, label);
|
556 | var result = parent._result;
|
557 |
|
558 | config.instrument && instrument('chained', parent, child);
|
559 |
|
560 | if (state === PENDING) {
|
561 | subscribe(parent, child, onFulfillment, onRejection);
|
562 | } else {
|
563 | var callback = state === FULFILLED ? onFulfillment : onRejection;
|
564 | config.async(function () {
|
565 | return invokeCallback(state, child, callback, result);
|
566 | });
|
567 | }
|
568 |
|
569 | return child;
|
570 | }
|
571 |
|
572 | var Enumerator = function () {
|
573 | function Enumerator(Constructor, input, abortOnReject, label) {
|
574 | this._instanceConstructor = Constructor;
|
575 | this.promise = new Constructor(noop, label);
|
576 | this._abortOnReject = abortOnReject;
|
577 | this.isUsingOwnPromise = Constructor === Promise;
|
578 |
|
579 | this._init.apply(this, arguments);
|
580 | }
|
581 |
|
582 | Enumerator.prototype._init = function _init(Constructor, input) {
|
583 | var len = input.length || 0;
|
584 | this.length = len;
|
585 | this._remaining = len;
|
586 | this._result = new Array(len);
|
587 |
|
588 | this._enumerate(input);
|
589 | };
|
590 |
|
591 | Enumerator.prototype._enumerate = function _enumerate(input) {
|
592 | var length = this.length;
|
593 | var promise = this.promise;
|
594 |
|
595 | for (var i = 0; promise._state === PENDING && i < length; i++) {
|
596 | this._eachEntry(input[i], i, true);
|
597 | }
|
598 |
|
599 | this._checkFullfillment();
|
600 | };
|
601 |
|
602 | Enumerator.prototype._checkFullfillment = function _checkFullfillment() {
|
603 | if (this._remaining === 0) {
|
604 | fulfill(this.promise, this._result);
|
605 | }
|
606 | };
|
607 |
|
608 | Enumerator.prototype._settleMaybeThenable = function _settleMaybeThenable(entry, i, firstPass) {
|
609 | var c = this._instanceConstructor;
|
610 | var resolve$$1 = c.resolve;
|
611 |
|
612 | if (resolve$$1 === resolve$1) {
|
613 | var then$$1 = getThen(entry);
|
614 |
|
615 | if (then$$1 === then && entry._state !== PENDING) {
|
616 | entry._onError = null;
|
617 | this._settledAt(entry._state, i, entry._result, firstPass);
|
618 | } else if (typeof then$$1 !== 'function') {
|
619 | this._settledAt(FULFILLED, i, entry, firstPass);
|
620 | } else if (this.isUsingOwnPromise) {
|
621 | var promise = new c(noop);
|
622 | handleMaybeThenable(promise, entry, then$$1);
|
623 | this._willSettleAt(promise, i, firstPass);
|
624 | } else {
|
625 | this._willSettleAt(new c(function (resolve$$1) {
|
626 | return resolve$$1(entry);
|
627 | }), i, firstPass);
|
628 | }
|
629 | } else {
|
630 | this._willSettleAt(resolve$$1(entry), i, firstPass);
|
631 | }
|
632 | };
|
633 |
|
634 | Enumerator.prototype._eachEntry = function _eachEntry(entry, i, firstPass) {
|
635 | if (entry !== null && typeof entry === 'object') {
|
636 | this._settleMaybeThenable(entry, i, firstPass);
|
637 | } else {
|
638 | this._setResultAt(FULFILLED, i, entry, firstPass);
|
639 | }
|
640 | };
|
641 |
|
642 | Enumerator.prototype._settledAt = function _settledAt(state, i, value, firstPass) {
|
643 | var promise = this.promise;
|
644 |
|
645 | if (promise._state === PENDING) {
|
646 | if (this._abortOnReject && state === REJECTED) {
|
647 | reject(promise, value);
|
648 | } else {
|
649 | this._setResultAt(state, i, value, firstPass);
|
650 | this._checkFullfillment();
|
651 | }
|
652 | }
|
653 | };
|
654 |
|
655 | Enumerator.prototype._setResultAt = function _setResultAt(state, i, value, firstPass) {
|
656 | this._remaining--;
|
657 | this._result[i] = value;
|
658 | };
|
659 |
|
660 | Enumerator.prototype._willSettleAt = function _willSettleAt(promise, i, firstPass) {
|
661 | var _this = this;
|
662 |
|
663 | subscribe(promise, undefined, function (value) {
|
664 | return _this._settledAt(FULFILLED, i, value, firstPass);
|
665 | }, function (reason) {
|
666 | return _this._settledAt(REJECTED, i, reason, firstPass);
|
667 | });
|
668 | };
|
669 |
|
670 | return Enumerator;
|
671 | }();
|
672 |
|
673 | function setSettledResult(state, i, value) {
|
674 | this._remaining--;
|
675 | if (state === FULFILLED) {
|
676 | this._result[i] = {
|
677 | state: 'fulfilled',
|
678 | value: value
|
679 | };
|
680 | } else {
|
681 | this._result[i] = {
|
682 | state: 'rejected',
|
683 | reason: value
|
684 | };
|
685 | }
|
686 | }
|
687 |
|
688 | /**
|
689 | `RSVP.Promise.all` accepts an array of promises, and returns a new promise which
|
690 | is fulfilled with an array of fulfillment values for the passed promises, or
|
691 | rejected with the reason of the first passed promise to be rejected. It casts all
|
692 | elements of the passed iterable to promises as it runs this algorithm.
|
693 |
|
694 | Example:
|
695 |
|
696 | ```javascript
|
697 | let promise1 = RSVP.resolve(1);
|
698 | let promise2 = RSVP.resolve(2);
|
699 | let promise3 = RSVP.resolve(3);
|
700 | let promises = [ promise1, promise2, promise3 ];
|
701 |
|
702 | RSVP.Promise.all(promises).then(function(array){
|
703 | // The array here would be [ 1, 2, 3 ];
|
704 | });
|
705 | ```
|
706 |
|
707 | If any of the `promises` given to `RSVP.all` are rejected, the first promise
|
708 | that is rejected will be given as an argument to the returned promises's
|
709 | rejection handler. For example:
|
710 |
|
711 | Example:
|
712 |
|
713 | ```javascript
|
714 | let promise1 = RSVP.resolve(1);
|
715 | let promise2 = RSVP.reject(new Error("2"));
|
716 | let promise3 = RSVP.reject(new Error("3"));
|
717 | let promises = [ promise1, promise2, promise3 ];
|
718 |
|
719 | RSVP.Promise.all(promises).then(function(array){
|
720 | // Code here never runs because there are rejected promises!
|
721 | }, function(error) {
|
722 | // error.message === "2"
|
723 | });
|
724 | ```
|
725 |
|
726 | @method all
|
727 | @static
|
728 | @param {Array} entries array of promises
|
729 | @param {String} label optional string for labeling the promise.
|
730 | Useful for tooling.
|
731 | @return {Promise} promise that is fulfilled when all `promises` have been
|
732 | fulfilled, or rejected if any of them become rejected.
|
733 | @static
|
734 | */
|
735 | function all(entries, label) {
|
736 | if (!Array.isArray(entries)) {
|
737 | return this.reject(new TypeError("Promise.all must be called with an array"), label);
|
738 | }
|
739 | return new Enumerator(this, entries, true /* abort on reject */, label).promise;
|
740 | }
|
741 |
|
742 | /**
|
743 | `RSVP.Promise.race` returns a new promise which is settled in the same way as the
|
744 | first passed promise to settle.
|
745 |
|
746 | Example:
|
747 |
|
748 | ```javascript
|
749 | let promise1 = new RSVP.Promise(function(resolve, reject){
|
750 | setTimeout(function(){
|
751 | resolve('promise 1');
|
752 | }, 200);
|
753 | });
|
754 |
|
755 | let promise2 = new RSVP.Promise(function(resolve, reject){
|
756 | setTimeout(function(){
|
757 | resolve('promise 2');
|
758 | }, 100);
|
759 | });
|
760 |
|
761 | RSVP.Promise.race([promise1, promise2]).then(function(result){
|
762 | // result === 'promise 2' because it was resolved before promise1
|
763 | // was resolved.
|
764 | });
|
765 | ```
|
766 |
|
767 | `RSVP.Promise.race` is deterministic in that only the state of the first
|
768 | settled promise matters. For example, even if other promises given to the
|
769 | `promises` array argument are resolved, but the first settled promise has
|
770 | become rejected before the other promises became fulfilled, the returned
|
771 | promise will become rejected:
|
772 |
|
773 | ```javascript
|
774 | let promise1 = new RSVP.Promise(function(resolve, reject){
|
775 | setTimeout(function(){
|
776 | resolve('promise 1');
|
777 | }, 200);
|
778 | });
|
779 |
|
780 | let promise2 = new RSVP.Promise(function(resolve, reject){
|
781 | setTimeout(function(){
|
782 | reject(new Error('promise 2'));
|
783 | }, 100);
|
784 | });
|
785 |
|
786 | RSVP.Promise.race([promise1, promise2]).then(function(result){
|
787 | // Code here never runs
|
788 | }, function(reason){
|
789 | // reason.message === 'promise 2' because promise 2 became rejected before
|
790 | // promise 1 became fulfilled
|
791 | });
|
792 | ```
|
793 |
|
794 | An example real-world use case is implementing timeouts:
|
795 |
|
796 | ```javascript
|
797 | RSVP.Promise.race([ajax('foo.json'), timeout(5000)])
|
798 | ```
|
799 |
|
800 | @method race
|
801 | @static
|
802 | @param {Array} entries array of promises to observe
|
803 | @param {String} label optional string for describing the promise returned.
|
804 | Useful for tooling.
|
805 | @return {Promise} a promise which settles in the same way as the first passed
|
806 | promise to settle.
|
807 | */
|
808 | function race(entries, label) {
|
809 | /*jshint validthis:true */
|
810 | var Constructor = this;
|
811 |
|
812 | var promise = new Constructor(noop, label);
|
813 |
|
814 | if (!Array.isArray(entries)) {
|
815 | reject(promise, new TypeError('Promise.race must be called with an array'));
|
816 | return promise;
|
817 | }
|
818 |
|
819 | for (var i = 0; promise._state === PENDING && i < entries.length; i++) {
|
820 | subscribe(Constructor.resolve(entries[i]), undefined, function (value) {
|
821 | return resolve(promise, value);
|
822 | }, function (reason) {
|
823 | return reject(promise, reason);
|
824 | });
|
825 | }
|
826 |
|
827 | return promise;
|
828 | }
|
829 |
|
830 | /**
|
831 | `RSVP.Promise.reject` returns a promise rejected with the passed `reason`.
|
832 | It is shorthand for the following:
|
833 |
|
834 | ```javascript
|
835 | let promise = new RSVP.Promise(function(resolve, reject){
|
836 | reject(new Error('WHOOPS'));
|
837 | });
|
838 |
|
839 | promise.then(function(value){
|
840 | // Code here doesn't run because the promise is rejected!
|
841 | }, function(reason){
|
842 | // reason.message === 'WHOOPS'
|
843 | });
|
844 | ```
|
845 |
|
846 | Instead of writing the above, your code now simply becomes the following:
|
847 |
|
848 | ```javascript
|
849 | let promise = RSVP.Promise.reject(new Error('WHOOPS'));
|
850 |
|
851 | promise.then(function(value){
|
852 | // Code here doesn't run because the promise is rejected!
|
853 | }, function(reason){
|
854 | // reason.message === 'WHOOPS'
|
855 | });
|
856 | ```
|
857 |
|
858 | @method reject
|
859 | @static
|
860 | @param {*} reason value that the returned promise will be rejected with.
|
861 | @param {String} label optional string for identifying the returned promise.
|
862 | Useful for tooling.
|
863 | @return {Promise} a promise rejected with the given `reason`.
|
864 | */
|
865 | function reject$1(reason, label) {
|
866 | /*jshint validthis:true */
|
867 | var Constructor = this;
|
868 | var promise = new Constructor(noop, label);
|
869 | reject(promise, reason);
|
870 | return promise;
|
871 | }
|
872 |
|
873 | var guidKey = 'rsvp_' + Date.now() + '-';
|
874 | var counter = 0;
|
875 |
|
876 | function needsResolver() {
|
877 | throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
|
878 | }
|
879 |
|
880 | function needsNew() {
|
881 | throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
|
882 | }
|
883 |
|
884 | /**
|
885 | Promise objects represent the eventual result of an asynchronous operation. The
|
886 | primary way of interacting with a promise is through its `then` method, which
|
887 | registers callbacks to receive either a promise’s eventual value or the reason
|
888 | why the promise cannot be fulfilled.
|
889 |
|
890 | Terminology
|
891 | -----------
|
892 |
|
893 | - `promise` is an object or function with a `then` method whose behavior conforms to this specification.
|
894 | - `thenable` is an object or function that defines a `then` method.
|
895 | - `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
|
896 | - `exception` is a value that is thrown using the throw statement.
|
897 | - `reason` is a value that indicates why a promise was rejected.
|
898 | - `settled` the final resting state of a promise, fulfilled or rejected.
|
899 |
|
900 | A promise can be in one of three states: pending, fulfilled, or rejected.
|
901 |
|
902 | Promises that are fulfilled have a fulfillment value and are in the fulfilled
|
903 | state. Promises that are rejected have a rejection reason and are in the
|
904 | rejected state. A fulfillment value is never a thenable.
|
905 |
|
906 | Promises can also be said to *resolve* a value. If this value is also a
|
907 | promise, then the original promise's settled state will match the value's
|
908 | settled state. So a promise that *resolves* a promise that rejects will
|
909 | itself reject, and a promise that *resolves* a promise that fulfills will
|
910 | itself fulfill.
|
911 |
|
912 |
|
913 | Basic Usage:
|
914 | ------------
|
915 |
|
916 | ```js
|
917 | let promise = new Promise(function(resolve, reject) {
|
918 | // on success
|
919 | resolve(value);
|
920 |
|
921 | // on failure
|
922 | reject(reason);
|
923 | });
|
924 |
|
925 | promise.then(function(value) {
|
926 | // on fulfillment
|
927 | }, function(reason) {
|
928 | // on rejection
|
929 | });
|
930 | ```
|
931 |
|
932 | Advanced Usage:
|
933 | ---------------
|
934 |
|
935 | Promises shine when abstracting away asynchronous interactions such as
|
936 | `XMLHttpRequest`s.
|
937 |
|
938 | ```js
|
939 | function getJSON(url) {
|
940 | return new Promise(function(resolve, reject){
|
941 | let xhr = new XMLHttpRequest();
|
942 |
|
943 | xhr.open('GET', url);
|
944 | xhr.onreadystatechange = handler;
|
945 | xhr.responseType = 'json';
|
946 | xhr.setRequestHeader('Accept', 'application/json');
|
947 | xhr.send();
|
948 |
|
949 | function handler() {
|
950 | if (this.readyState === this.DONE) {
|
951 | if (this.status === 200) {
|
952 | resolve(this.response);
|
953 | } else {
|
954 | reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
|
955 | }
|
956 | }
|
957 | };
|
958 | });
|
959 | }
|
960 |
|
961 | getJSON('/posts.json').then(function(json) {
|
962 | // on fulfillment
|
963 | }, function(reason) {
|
964 | // on rejection
|
965 | });
|
966 | ```
|
967 |
|
968 | Unlike callbacks, promises are great composable primitives.
|
969 |
|
970 | ```js
|
971 | Promise.all([
|
972 | getJSON('/posts'),
|
973 | getJSON('/comments')
|
974 | ]).then(function(values){
|
975 | values[0] // => postsJSON
|
976 | values[1] // => commentsJSON
|
977 |
|
978 | return values;
|
979 | });
|
980 | ```
|
981 |
|
982 | @class RSVP.Promise
|
983 | @param {function} resolver
|
984 | @param {String} label optional string for labeling the promise.
|
985 | Useful for tooling.
|
986 | @constructor
|
987 | */
|
988 |
|
989 | var Promise = function () {
|
990 | function Promise(resolver, label) {
|
991 | this._id = counter++;
|
992 | this._label = label;
|
993 | this._state = undefined;
|
994 | this._result = undefined;
|
995 | this._subscribers = [];
|
996 |
|
997 | config.instrument && instrument('created', this);
|
998 |
|
999 | if (noop !== resolver) {
|
1000 | typeof resolver !== 'function' && needsResolver();
|
1001 | this instanceof Promise ? initializePromise(this, resolver) : needsNew();
|
1002 | }
|
1003 | }
|
1004 |
|
1005 | Promise.prototype._onError = function _onError(reason) {
|
1006 | var _this = this;
|
1007 |
|
1008 | config.after(function () {
|
1009 | if (_this._onError) {
|
1010 | config.trigger('error', reason, _this._label);
|
1011 | }
|
1012 | });
|
1013 | };
|
1014 |
|
1015 | /**
|
1016 | `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
|
1017 | as the catch block of a try/catch statement.
|
1018 |
|
1019 | ```js
|
1020 | function findAuthor(){
|
1021 | throw new Error('couldn\'t find that author');
|
1022 | }
|
1023 |
|
1024 | // synchronous
|
1025 | try {
|
1026 | findAuthor();
|
1027 | } catch(reason) {
|
1028 | // something went wrong
|
1029 | }
|
1030 |
|
1031 | // async with promises
|
1032 | findAuthor().catch(function(reason){
|
1033 | // something went wrong
|
1034 | });
|
1035 | ```
|
1036 |
|
1037 | @method catch
|
1038 | @param {Function} onRejection
|
1039 | @param {String} label optional string for labeling the promise.
|
1040 | Useful for tooling.
|
1041 | @return {Promise}
|
1042 | */
|
1043 |
|
1044 |
|
1045 | Promise.prototype.catch = function _catch(onRejection, label) {
|
1046 | return this.then(undefined, onRejection, label);
|
1047 | };
|
1048 |
|
1049 | /**
|
1050 | `finally` will be invoked regardless of the promise's fate just as native
|
1051 | try/catch/finally behaves
|
1052 |
|
1053 | Synchronous example:
|
1054 |
|
1055 | ```js
|
1056 | findAuthor() {
|
1057 | if (Math.random() > 0.5) {
|
1058 | throw new Error();
|
1059 | }
|
1060 | return new Author();
|
1061 | }
|
1062 |
|
1063 | try {
|
1064 | return findAuthor(); // succeed or fail
|
1065 | } catch(error) {
|
1066 | return findOtherAuthor();
|
1067 | } finally {
|
1068 | // always runs
|
1069 | // doesn't affect the return value
|
1070 | }
|
1071 | ```
|
1072 |
|
1073 | Asynchronous example:
|
1074 |
|
1075 | ```js
|
1076 | findAuthor().catch(function(reason){
|
1077 | return findOtherAuthor();
|
1078 | }).finally(function(){
|
1079 | // author was either found, or not
|
1080 | });
|
1081 | ```
|
1082 |
|
1083 | @method finally
|
1084 | @param {Function} callback
|
1085 | @param {String} label optional string for labeling the promise.
|
1086 | Useful for tooling.
|
1087 | @return {Promise}
|
1088 | */
|
1089 |
|
1090 |
|
1091 | Promise.prototype.finally = function _finally(callback, label) {
|
1092 | var promise = this;
|
1093 | var constructor = promise.constructor;
|
1094 |
|
1095 | return promise.then(function (value) {
|
1096 | return constructor.resolve(callback()).then(function () {
|
1097 | return value;
|
1098 | });
|
1099 | }, function (reason) {
|
1100 | return constructor.resolve(callback()).then(function () {
|
1101 | throw reason;
|
1102 | });
|
1103 | }, label);
|
1104 | };
|
1105 |
|
1106 | return Promise;
|
1107 | }();
|
1108 |
|
1109 | Promise.cast = resolve$1; // deprecated
|
1110 | Promise.all = all;
|
1111 | Promise.race = race;
|
1112 | Promise.resolve = resolve$1;
|
1113 | Promise.reject = reject$1;
|
1114 |
|
1115 | Promise.prototype._guidKey = guidKey;
|
1116 |
|
1117 | /**
|
1118 | The primary way of interacting with a promise is through its `then` method,
|
1119 | which registers callbacks to receive either a promise's eventual value or the
|
1120 | reason why the promise cannot be fulfilled.
|
1121 |
|
1122 | ```js
|
1123 | findUser().then(function(user){
|
1124 | // user is available
|
1125 | }, function(reason){
|
1126 | // user is unavailable, and you are given the reason why
|
1127 | });
|
1128 | ```
|
1129 |
|
1130 | Chaining
|
1131 | --------
|
1132 |
|
1133 | The return value of `then` is itself a promise. This second, 'downstream'
|
1134 | promise is resolved with the return value of the first promise's fulfillment
|
1135 | or rejection handler, or rejected if the handler throws an exception.
|
1136 |
|
1137 | ```js
|
1138 | findUser().then(function (user) {
|
1139 | return user.name;
|
1140 | }, function (reason) {
|
1141 | return 'default name';
|
1142 | }).then(function (userName) {
|
1143 | // If `findUser` fulfilled, `userName` will be the user's name, otherwise it
|
1144 | // will be `'default name'`
|
1145 | });
|
1146 |
|
1147 | findUser().then(function (user) {
|
1148 | throw new Error('Found user, but still unhappy');
|
1149 | }, function (reason) {
|
1150 | throw new Error('`findUser` rejected and we\'re unhappy');
|
1151 | }).then(function (value) {
|
1152 | // never reached
|
1153 | }, function (reason) {
|
1154 | // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
|
1155 | // If `findUser` rejected, `reason` will be '`findUser` rejected and we\'re unhappy'.
|
1156 | });
|
1157 | ```
|
1158 | If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
|
1159 |
|
1160 | ```js
|
1161 | findUser().then(function (user) {
|
1162 | throw new PedagogicalException('Upstream error');
|
1163 | }).then(function (value) {
|
1164 | // never reached
|
1165 | }).then(function (value) {
|
1166 | // never reached
|
1167 | }, function (reason) {
|
1168 | // The `PedgagocialException` is propagated all the way down to here
|
1169 | });
|
1170 | ```
|
1171 |
|
1172 | Assimilation
|
1173 | ------------
|
1174 |
|
1175 | Sometimes the value you want to propagate to a downstream promise can only be
|
1176 | retrieved asynchronously. This can be achieved by returning a promise in the
|
1177 | fulfillment or rejection handler. The downstream promise will then be pending
|
1178 | until the returned promise is settled. This is called *assimilation*.
|
1179 |
|
1180 | ```js
|
1181 | findUser().then(function (user) {
|
1182 | return findCommentsByAuthor(user);
|
1183 | }).then(function (comments) {
|
1184 | // The user's comments are now available
|
1185 | });
|
1186 | ```
|
1187 |
|
1188 | If the assimliated promise rejects, then the downstream promise will also reject.
|
1189 |
|
1190 | ```js
|
1191 | findUser().then(function (user) {
|
1192 | return findCommentsByAuthor(user);
|
1193 | }).then(function (comments) {
|
1194 | // If `findCommentsByAuthor` fulfills, we'll have the value here
|
1195 | }, function (reason) {
|
1196 | // If `findCommentsByAuthor` rejects, we'll have the reason here
|
1197 | });
|
1198 | ```
|
1199 |
|
1200 | Simple Example
|
1201 | --------------
|
1202 |
|
1203 | Synchronous Example
|
1204 |
|
1205 | ```javascript
|
1206 | let result;
|
1207 |
|
1208 | try {
|
1209 | result = findResult();
|
1210 | // success
|
1211 | } catch(reason) {
|
1212 | // failure
|
1213 | }
|
1214 | ```
|
1215 |
|
1216 | Errback Example
|
1217 |
|
1218 | ```js
|
1219 | findResult(function(result, err){
|
1220 | if (err) {
|
1221 | // failure
|
1222 | } else {
|
1223 | // success
|
1224 | }
|
1225 | });
|
1226 | ```
|
1227 |
|
1228 | Promise Example;
|
1229 |
|
1230 | ```javascript
|
1231 | findResult().then(function(result){
|
1232 | // success
|
1233 | }, function(reason){
|
1234 | // failure
|
1235 | });
|
1236 | ```
|
1237 |
|
1238 | Advanced Example
|
1239 | --------------
|
1240 |
|
1241 | Synchronous Example
|
1242 |
|
1243 | ```javascript
|
1244 | let author, books;
|
1245 |
|
1246 | try {
|
1247 | author = findAuthor();
|
1248 | books = findBooksByAuthor(author);
|
1249 | // success
|
1250 | } catch(reason) {
|
1251 | // failure
|
1252 | }
|
1253 | ```
|
1254 |
|
1255 | Errback Example
|
1256 |
|
1257 | ```js
|
1258 |
|
1259 | function foundBooks(books) {
|
1260 |
|
1261 | }
|
1262 |
|
1263 | function failure(reason) {
|
1264 |
|
1265 | }
|
1266 |
|
1267 | findAuthor(function(author, err){
|
1268 | if (err) {
|
1269 | failure(err);
|
1270 | // failure
|
1271 | } else {
|
1272 | try {
|
1273 | findBoooksByAuthor(author, function(books, err) {
|
1274 | if (err) {
|
1275 | failure(err);
|
1276 | } else {
|
1277 | try {
|
1278 | foundBooks(books);
|
1279 | } catch(reason) {
|
1280 | failure(reason);
|
1281 | }
|
1282 | }
|
1283 | });
|
1284 | } catch(error) {
|
1285 | failure(err);
|
1286 | }
|
1287 | // success
|
1288 | }
|
1289 | });
|
1290 | ```
|
1291 |
|
1292 | Promise Example;
|
1293 |
|
1294 | ```javascript
|
1295 | findAuthor().
|
1296 | then(findBooksByAuthor).
|
1297 | then(function(books){
|
1298 | // found books
|
1299 | }).catch(function(reason){
|
1300 | // something went wrong
|
1301 | });
|
1302 | ```
|
1303 |
|
1304 | @method then
|
1305 | @param {Function} onFulfillment
|
1306 | @param {Function} onRejection
|
1307 | @param {String} label optional string for labeling the promise.
|
1308 | Useful for tooling.
|
1309 | @return {Promise}
|
1310 | */
|
1311 | Promise.prototype.then = then;
|
1312 |
|
1313 | function Result() {
|
1314 | this.value = undefined;
|
1315 | }
|
1316 |
|
1317 | var ERROR = new Result();
|
1318 | var GET_THEN_ERROR$1 = new Result();
|
1319 |
|
1320 | function getThen$1(obj) {
|
1321 | try {
|
1322 | return obj.then;
|
1323 | } catch (error) {
|
1324 | ERROR.value = error;
|
1325 | return ERROR;
|
1326 | }
|
1327 | }
|
1328 |
|
1329 | function tryApply(f, s, a) {
|
1330 | try {
|
1331 | f.apply(s, a);
|
1332 | } catch (error) {
|
1333 | ERROR.value = error;
|
1334 | return ERROR;
|
1335 | }
|
1336 | }
|
1337 |
|
1338 | function makeObject(_, argumentNames) {
|
1339 | var obj = {};
|
1340 | var length = _.length;
|
1341 | var args = new Array(length);
|
1342 |
|
1343 | for (var x = 0; x < length; x++) {
|
1344 | args[x] = _[x];
|
1345 | }
|
1346 |
|
1347 | for (var i = 0; i < argumentNames.length; i++) {
|
1348 | var name = argumentNames[i];
|
1349 | obj[name] = args[i + 1];
|
1350 | }
|
1351 |
|
1352 | return obj;
|
1353 | }
|
1354 |
|
1355 | function arrayResult(_) {
|
1356 | var length = _.length;
|
1357 | var args = new Array(length - 1);
|
1358 |
|
1359 | for (var i = 1; i < length; i++) {
|
1360 | args[i - 1] = _[i];
|
1361 | }
|
1362 |
|
1363 | return args;
|
1364 | }
|
1365 |
|
1366 | function wrapThenable(then, promise) {
|
1367 | return {
|
1368 | then: function (onFulFillment, onRejection) {
|
1369 | return then.call(promise, onFulFillment, onRejection);
|
1370 | }
|
1371 | };
|
1372 | }
|
1373 |
|
1374 | /**
|
1375 | `RSVP.denodeify` takes a 'node-style' function and returns a function that
|
1376 | will return an `RSVP.Promise`. You can use `denodeify` in Node.js or the
|
1377 | browser when you'd prefer to use promises over using callbacks. For example,
|
1378 | `denodeify` transforms the following:
|
1379 |
|
1380 | ```javascript
|
1381 | let fs = require('fs');
|
1382 |
|
1383 | fs.readFile('myfile.txt', function(err, data){
|
1384 | if (err) return handleError(err);
|
1385 | handleData(data);
|
1386 | });
|
1387 | ```
|
1388 |
|
1389 | into:
|
1390 |
|
1391 | ```javascript
|
1392 | let fs = require('fs');
|
1393 | let readFile = RSVP.denodeify(fs.readFile);
|
1394 |
|
1395 | readFile('myfile.txt').then(handleData, handleError);
|
1396 | ```
|
1397 |
|
1398 | If the node function has multiple success parameters, then `denodeify`
|
1399 | just returns the first one:
|
1400 |
|
1401 | ```javascript
|
1402 | let request = RSVP.denodeify(require('request'));
|
1403 |
|
1404 | request('http://example.com').then(function(res) {
|
1405 | // ...
|
1406 | });
|
1407 | ```
|
1408 |
|
1409 | However, if you need all success parameters, setting `denodeify`'s
|
1410 | second parameter to `true` causes it to return all success parameters
|
1411 | as an array:
|
1412 |
|
1413 | ```javascript
|
1414 | let request = RSVP.denodeify(require('request'), true);
|
1415 |
|
1416 | request('http://example.com').then(function(result) {
|
1417 | // result[0] -> res
|
1418 | // result[1] -> body
|
1419 | });
|
1420 | ```
|
1421 |
|
1422 | Or if you pass it an array with names it returns the parameters as a hash:
|
1423 |
|
1424 | ```javascript
|
1425 | let request = RSVP.denodeify(require('request'), ['res', 'body']);
|
1426 |
|
1427 | request('http://example.com').then(function(result) {
|
1428 | // result.res
|
1429 | // result.body
|
1430 | });
|
1431 | ```
|
1432 |
|
1433 | Sometimes you need to retain the `this`:
|
1434 |
|
1435 | ```javascript
|
1436 | let app = require('express')();
|
1437 | let render = RSVP.denodeify(app.render.bind(app));
|
1438 | ```
|
1439 |
|
1440 | The denodified function inherits from the original function. It works in all
|
1441 | environments, except IE 10 and below. Consequently all properties of the original
|
1442 | function are available to you. However, any properties you change on the
|
1443 | denodeified function won't be changed on the original function. Example:
|
1444 |
|
1445 | ```javascript
|
1446 | let request = RSVP.denodeify(require('request')),
|
1447 | cookieJar = request.jar(); // <- Inheritance is used here
|
1448 |
|
1449 | request('http://example.com', {jar: cookieJar}).then(function(res) {
|
1450 | // cookieJar.cookies holds now the cookies returned by example.com
|
1451 | });
|
1452 | ```
|
1453 |
|
1454 | Using `denodeify` makes it easier to compose asynchronous operations instead
|
1455 | of using callbacks. For example, instead of:
|
1456 |
|
1457 | ```javascript
|
1458 | let fs = require('fs');
|
1459 |
|
1460 | fs.readFile('myfile.txt', function(err, data){
|
1461 | if (err) { ... } // Handle error
|
1462 | fs.writeFile('myfile2.txt', data, function(err){
|
1463 | if (err) { ... } // Handle error
|
1464 | console.log('done')
|
1465 | });
|
1466 | });
|
1467 | ```
|
1468 |
|
1469 | you can chain the operations together using `then` from the returned promise:
|
1470 |
|
1471 | ```javascript
|
1472 | let fs = require('fs');
|
1473 | let readFile = RSVP.denodeify(fs.readFile);
|
1474 | let writeFile = RSVP.denodeify(fs.writeFile);
|
1475 |
|
1476 | readFile('myfile.txt').then(function(data){
|
1477 | return writeFile('myfile2.txt', data);
|
1478 | }).then(function(){
|
1479 | console.log('done')
|
1480 | }).catch(function(error){
|
1481 | // Handle error
|
1482 | });
|
1483 | ```
|
1484 |
|
1485 | @method denodeify
|
1486 | @static
|
1487 | @for RSVP
|
1488 | @param {Function} nodeFunc a 'node-style' function that takes a callback as
|
1489 | its last argument. The callback expects an error to be passed as its first
|
1490 | argument (if an error occurred, otherwise null), and the value from the
|
1491 | operation as its second argument ('function(err, value){ }').
|
1492 | @param {Boolean|Array} [options] An optional paramter that if set
|
1493 | to `true` causes the promise to fulfill with the callback's success arguments
|
1494 | as an array. This is useful if the node function has multiple success
|
1495 | paramters. If you set this paramter to an array with names, the promise will
|
1496 | fulfill with a hash with these names as keys and the success parameters as
|
1497 | values.
|
1498 | @return {Function} a function that wraps `nodeFunc` to return an
|
1499 | `RSVP.Promise`
|
1500 | @static
|
1501 | */
|
1502 | function denodeify(nodeFunc, options) {
|
1503 | var fn = function () {
|
1504 | var self = this;
|
1505 | var l = arguments.length;
|
1506 | var args = new Array(l + 1);
|
1507 | var promiseInput = false;
|
1508 |
|
1509 | for (var i = 0; i < l; ++i) {
|
1510 | var arg = arguments[i];
|
1511 |
|
1512 | if (!promiseInput) {
|
1513 | // TODO: clean this up
|
1514 | promiseInput = needsPromiseInput(arg);
|
1515 | if (promiseInput === GET_THEN_ERROR$1) {
|
1516 | var p = new Promise(noop);
|
1517 | reject(p, GET_THEN_ERROR$1.value);
|
1518 | return p;
|
1519 | } else if (promiseInput && promiseInput !== true) {
|
1520 | arg = wrapThenable(promiseInput, arg);
|
1521 | }
|
1522 | }
|
1523 | args[i] = arg;
|
1524 | }
|
1525 |
|
1526 | var promise = new Promise(noop);
|
1527 |
|
1528 | args[l] = function (err, val) {
|
1529 | if (err) reject(promise, err);else if (options === undefined) resolve(promise, val);else if (options === true) resolve(promise, arrayResult(arguments));else if (Array.isArray(options)) resolve(promise, makeObject(arguments, options));else resolve(promise, val);
|
1530 | };
|
1531 |
|
1532 | if (promiseInput) {
|
1533 | return handlePromiseInput(promise, args, nodeFunc, self);
|
1534 | } else {
|
1535 | return handleValueInput(promise, args, nodeFunc, self);
|
1536 | }
|
1537 | };
|
1538 |
|
1539 | fn.__proto__ = nodeFunc;
|
1540 |
|
1541 | return fn;
|
1542 | }
|
1543 |
|
1544 | function handleValueInput(promise, args, nodeFunc, self) {
|
1545 | var result = tryApply(nodeFunc, self, args);
|
1546 | if (result === ERROR) {
|
1547 | reject(promise, result.value);
|
1548 | }
|
1549 | return promise;
|
1550 | }
|
1551 |
|
1552 | function handlePromiseInput(promise, args, nodeFunc, self) {
|
1553 | return Promise.all(args).then(function (args) {
|
1554 | var result = tryApply(nodeFunc, self, args);
|
1555 | if (result === ERROR) {
|
1556 | reject(promise, result.value);
|
1557 | }
|
1558 | return promise;
|
1559 | });
|
1560 | }
|
1561 |
|
1562 | function needsPromiseInput(arg) {
|
1563 | if (arg && typeof arg === 'object') {
|
1564 | if (arg.constructor === Promise) {
|
1565 | return true;
|
1566 | } else {
|
1567 | return getThen$1(arg);
|
1568 | }
|
1569 | } else {
|
1570 | return false;
|
1571 | }
|
1572 | }
|
1573 |
|
1574 | /**
|
1575 | This is a convenient alias for `RSVP.Promise.all`.
|
1576 |
|
1577 | @method all
|
1578 | @static
|
1579 | @for RSVP
|
1580 | @param {Array} array Array of promises.
|
1581 | @param {String} label An optional label. This is useful
|
1582 | for tooling.
|
1583 | */
|
1584 | function all$1(array, label) {
|
1585 | return Promise.all(array, label);
|
1586 | }
|
1587 |
|
1588 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
1589 |
|
1590 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
1591 |
|
1592 | var AllSettled = function (_Enumerator) {
|
1593 | _inherits(AllSettled, _Enumerator);
|
1594 |
|
1595 | function AllSettled(Constructor, entries, label) {
|
1596 | return _possibleConstructorReturn(this, _Enumerator.call(this, Constructor, entries, false /* don't abort on reject */, label));
|
1597 | }
|
1598 |
|
1599 | return AllSettled;
|
1600 | }(Enumerator);
|
1601 |
|
1602 | AllSettled.prototype._setResultAt = setSettledResult;
|
1603 |
|
1604 | /**
|
1605 | `RSVP.allSettled` is similar to `RSVP.all`, but instead of implementing
|
1606 | a fail-fast method, it waits until all the promises have returned and
|
1607 | shows you all the results. This is useful if you want to handle multiple
|
1608 | promises' failure states together as a set.
|
1609 | Returns a promise that is fulfilled when all the given promises have been
|
1610 | settled. The return promise is fulfilled with an array of the states of
|
1611 | the promises passed into the `promises` array argument.
|
1612 | Each state object will either indicate fulfillment or rejection, and
|
1613 | provide the corresponding value or reason. The states will take one of
|
1614 | the following formats:
|
1615 | ```javascript
|
1616 | { state: 'fulfilled', value: value }
|
1617 | or
|
1618 | { state: 'rejected', reason: reason }
|
1619 | ```
|
1620 | Example:
|
1621 | ```javascript
|
1622 | let promise1 = RSVP.Promise.resolve(1);
|
1623 | let promise2 = RSVP.Promise.reject(new Error('2'));
|
1624 | let promise3 = RSVP.Promise.reject(new Error('3'));
|
1625 | let promises = [ promise1, promise2, promise3 ];
|
1626 | RSVP.allSettled(promises).then(function(array){
|
1627 | // array == [
|
1628 | // { state: 'fulfilled', value: 1 },
|
1629 | // { state: 'rejected', reason: Error },
|
1630 | // { state: 'rejected', reason: Error }
|
1631 | // ]
|
1632 | // Note that for the second item, reason.message will be '2', and for the
|
1633 | // third item, reason.message will be '3'.
|
1634 | }, function(error) {
|
1635 | // Not run. (This block would only be called if allSettled had failed,
|
1636 | // for instance if passed an incorrect argument type.)
|
1637 | });
|
1638 | ```
|
1639 | @method allSettled
|
1640 | @static
|
1641 | @for RSVP
|
1642 | @param {Array} entries
|
1643 | @param {String} label - optional string that describes the promise.
|
1644 | Useful for tooling.
|
1645 | @return {Promise} promise that is fulfilled with an array of the settled
|
1646 | states of the constituent promises.
|
1647 | */
|
1648 |
|
1649 | function allSettled(entries, label) {
|
1650 | if (!Array.isArray(entries)) {
|
1651 | return Promise.reject(new TypeError("Promise.allSettled must be called with an array"), label);
|
1652 | }
|
1653 |
|
1654 | return new AllSettled(Promise, entries, label).promise;
|
1655 | }
|
1656 |
|
1657 | /**
|
1658 | This is a convenient alias for `RSVP.Promise.race`.
|
1659 |
|
1660 | @method race
|
1661 | @static
|
1662 | @for RSVP
|
1663 | @param {Array} array Array of promises.
|
1664 | @param {String} label An optional label. This is useful
|
1665 | for tooling.
|
1666 | */
|
1667 | function race$1(array, label) {
|
1668 | return Promise.race(array, label);
|
1669 | }
|
1670 |
|
1671 | function _possibleConstructorReturn$1(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
1672 |
|
1673 | function _inherits$1(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
1674 |
|
1675 | var hasOwnProperty = Object.prototype.hasOwnProperty;
|
1676 |
|
1677 | var PromiseHash = function (_Enumerator) {
|
1678 | _inherits$1(PromiseHash, _Enumerator);
|
1679 |
|
1680 | function PromiseHash(Constructor, object) {
|
1681 | var abortOnReject = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
1682 | var label = arguments[3];
|
1683 | return _possibleConstructorReturn$1(this, _Enumerator.call(this, Constructor, object, abortOnReject, label));
|
1684 | }
|
1685 |
|
1686 | PromiseHash.prototype._init = function _init(Constructor, object) {
|
1687 | this._result = {};
|
1688 |
|
1689 | this._enumerate(object);
|
1690 | if (this._remaining === 0) {
|
1691 | fulfill(this.promise, this._result);
|
1692 | }
|
1693 | };
|
1694 |
|
1695 | PromiseHash.prototype._enumerate = function _enumerate(input) {
|
1696 | var promise = this.promise;
|
1697 | var results = [];
|
1698 |
|
1699 | for (var key in input) {
|
1700 | if (hasOwnProperty.call(input, key)) {
|
1701 | results.push({
|
1702 | position: key,
|
1703 | entry: input[key]
|
1704 | });
|
1705 | }
|
1706 | }
|
1707 |
|
1708 | var length = results.length;
|
1709 | this._remaining = length;
|
1710 | var result = void 0;
|
1711 |
|
1712 | for (var i = 0; promise._state === PENDING && i < length; i++) {
|
1713 | result = results[i];
|
1714 | this._eachEntry(result.entry, result.position);
|
1715 | }
|
1716 | };
|
1717 |
|
1718 | return PromiseHash;
|
1719 | }(Enumerator);
|
1720 |
|
1721 | /**
|
1722 | `RSVP.hash` is similar to `RSVP.all`, but takes an object instead of an array
|
1723 | for its `promises` argument.
|
1724 |
|
1725 | Returns a promise that is fulfilled when all the given promises have been
|
1726 | fulfilled, or rejected if any of them become rejected. The returned promise
|
1727 | is fulfilled with a hash that has the same key names as the `promises` object
|
1728 | argument. If any of the values in the object are not promises, they will
|
1729 | simply be copied over to the fulfilled object.
|
1730 |
|
1731 | Example:
|
1732 |
|
1733 | ```javascript
|
1734 | let promises = {
|
1735 | myPromise: RSVP.resolve(1),
|
1736 | yourPromise: RSVP.resolve(2),
|
1737 | theirPromise: RSVP.resolve(3),
|
1738 | notAPromise: 4
|
1739 | };
|
1740 |
|
1741 | RSVP.hash(promises).then(function(hash){
|
1742 | // hash here is an object that looks like:
|
1743 | // {
|
1744 | // myPromise: 1,
|
1745 | // yourPromise: 2,
|
1746 | // theirPromise: 3,
|
1747 | // notAPromise: 4
|
1748 | // }
|
1749 | });
|
1750 | ````
|
1751 |
|
1752 | If any of the `promises` given to `RSVP.hash` are rejected, the first promise
|
1753 | that is rejected will be given as the reason to the rejection handler.
|
1754 |
|
1755 | Example:
|
1756 |
|
1757 | ```javascript
|
1758 | let promises = {
|
1759 | myPromise: RSVP.resolve(1),
|
1760 | rejectedPromise: RSVP.reject(new Error('rejectedPromise')),
|
1761 | anotherRejectedPromise: RSVP.reject(new Error('anotherRejectedPromise')),
|
1762 | };
|
1763 |
|
1764 | RSVP.hash(promises).then(function(hash){
|
1765 | // Code here never runs because there are rejected promises!
|
1766 | }, function(reason) {
|
1767 | // reason.message === 'rejectedPromise'
|
1768 | });
|
1769 | ```
|
1770 |
|
1771 | An important note: `RSVP.hash` is intended for plain JavaScript objects that
|
1772 | are just a set of keys and values. `RSVP.hash` will NOT preserve prototype
|
1773 | chains.
|
1774 |
|
1775 | Example:
|
1776 |
|
1777 | ```javascript
|
1778 | function MyConstructor(){
|
1779 | this.example = RSVP.resolve('Example');
|
1780 | }
|
1781 |
|
1782 | MyConstructor.prototype = {
|
1783 | protoProperty: RSVP.resolve('Proto Property')
|
1784 | };
|
1785 |
|
1786 | let myObject = new MyConstructor();
|
1787 |
|
1788 | RSVP.hash(myObject).then(function(hash){
|
1789 | // protoProperty will not be present, instead you will just have an
|
1790 | // object that looks like:
|
1791 | // {
|
1792 | // example: 'Example'
|
1793 | // }
|
1794 | //
|
1795 | // hash.hasOwnProperty('protoProperty'); // false
|
1796 | // 'undefined' === typeof hash.protoProperty
|
1797 | });
|
1798 | ```
|
1799 |
|
1800 | @method hash
|
1801 | @static
|
1802 | @for RSVP
|
1803 | @param {Object} object
|
1804 | @param {String} label optional string that describes the promise.
|
1805 | Useful for tooling.
|
1806 | @return {Promise} promise that is fulfilled when all properties of `promises`
|
1807 | have been fulfilled, or rejected if any of them become rejected.
|
1808 | */
|
1809 | function hash(object, label) {
|
1810 | if (object === null || typeof object !== 'object') {
|
1811 | return Promise.reject(new TypeError("Promise.hash must be called with an object"), label);
|
1812 | }
|
1813 |
|
1814 | return new PromiseHash(Promise, object, label).promise;
|
1815 | }
|
1816 |
|
1817 | function _possibleConstructorReturn$2(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
1818 |
|
1819 | function _inherits$2(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
1820 |
|
1821 | var HashSettled = function (_PromiseHash) {
|
1822 | _inherits$2(HashSettled, _PromiseHash);
|
1823 |
|
1824 | function HashSettled(Constructor, object, label) {
|
1825 | return _possibleConstructorReturn$2(this, _PromiseHash.call(this, Constructor, object, false, label));
|
1826 | }
|
1827 |
|
1828 | return HashSettled;
|
1829 | }(PromiseHash);
|
1830 |
|
1831 | HashSettled.prototype._setResultAt = setSettledResult;
|
1832 |
|
1833 | /**
|
1834 | `RSVP.hashSettled` is similar to `RSVP.allSettled`, but takes an object
|
1835 | instead of an array for its `promises` argument.
|
1836 |
|
1837 | Unlike `RSVP.all` or `RSVP.hash`, which implement a fail-fast method,
|
1838 | but like `RSVP.allSettled`, `hashSettled` waits until all the
|
1839 | constituent promises have returned and then shows you all the results
|
1840 | with their states and values/reasons. This is useful if you want to
|
1841 | handle multiple promises' failure states together as a set.
|
1842 |
|
1843 | Returns a promise that is fulfilled when all the given promises have been
|
1844 | settled, or rejected if the passed parameters are invalid.
|
1845 |
|
1846 | The returned promise is fulfilled with a hash that has the same key names as
|
1847 | the `promises` object argument. If any of the values in the object are not
|
1848 | promises, they will be copied over to the fulfilled object and marked with state
|
1849 | 'fulfilled'.
|
1850 |
|
1851 | Example:
|
1852 |
|
1853 | ```javascript
|
1854 | let promises = {
|
1855 | myPromise: RSVP.Promise.resolve(1),
|
1856 | yourPromise: RSVP.Promise.resolve(2),
|
1857 | theirPromise: RSVP.Promise.resolve(3),
|
1858 | notAPromise: 4
|
1859 | };
|
1860 |
|
1861 | RSVP.hashSettled(promises).then(function(hash){
|
1862 | // hash here is an object that looks like:
|
1863 | // {
|
1864 | // myPromise: { state: 'fulfilled', value: 1 },
|
1865 | // yourPromise: { state: 'fulfilled', value: 2 },
|
1866 | // theirPromise: { state: 'fulfilled', value: 3 },
|
1867 | // notAPromise: { state: 'fulfilled', value: 4 }
|
1868 | // }
|
1869 | });
|
1870 | ```
|
1871 |
|
1872 | If any of the `promises` given to `RSVP.hash` are rejected, the state will
|
1873 | be set to 'rejected' and the reason for rejection provided.
|
1874 |
|
1875 | Example:
|
1876 |
|
1877 | ```javascript
|
1878 | let promises = {
|
1879 | myPromise: RSVP.Promise.resolve(1),
|
1880 | rejectedPromise: RSVP.Promise.reject(new Error('rejection')),
|
1881 | anotherRejectedPromise: RSVP.Promise.reject(new Error('more rejection')),
|
1882 | };
|
1883 |
|
1884 | RSVP.hashSettled(promises).then(function(hash){
|
1885 | // hash here is an object that looks like:
|
1886 | // {
|
1887 | // myPromise: { state: 'fulfilled', value: 1 },
|
1888 | // rejectedPromise: { state: 'rejected', reason: Error },
|
1889 | // anotherRejectedPromise: { state: 'rejected', reason: Error },
|
1890 | // }
|
1891 | // Note that for rejectedPromise, reason.message == 'rejection',
|
1892 | // and for anotherRejectedPromise, reason.message == 'more rejection'.
|
1893 | });
|
1894 | ```
|
1895 |
|
1896 | An important note: `RSVP.hashSettled` is intended for plain JavaScript objects that
|
1897 | are just a set of keys and values. `RSVP.hashSettled` will NOT preserve prototype
|
1898 | chains.
|
1899 |
|
1900 | Example:
|
1901 |
|
1902 | ```javascript
|
1903 | function MyConstructor(){
|
1904 | this.example = RSVP.Promise.resolve('Example');
|
1905 | }
|
1906 |
|
1907 | MyConstructor.prototype = {
|
1908 | protoProperty: RSVP.Promise.resolve('Proto Property')
|
1909 | };
|
1910 |
|
1911 | let myObject = new MyConstructor();
|
1912 |
|
1913 | RSVP.hashSettled(myObject).then(function(hash){
|
1914 | // protoProperty will not be present, instead you will just have an
|
1915 | // object that looks like:
|
1916 | // {
|
1917 | // example: { state: 'fulfilled', value: 'Example' }
|
1918 | // }
|
1919 | //
|
1920 | // hash.hasOwnProperty('protoProperty'); // false
|
1921 | // 'undefined' === typeof hash.protoProperty
|
1922 | });
|
1923 | ```
|
1924 |
|
1925 | @method hashSettled
|
1926 | @for RSVP
|
1927 | @param {Object} object
|
1928 | @param {String} label optional string that describes the promise.
|
1929 | Useful for tooling.
|
1930 | @return {Promise} promise that is fulfilled when when all properties of `promises`
|
1931 | have been settled.
|
1932 | @static
|
1933 | */
|
1934 |
|
1935 | function hashSettled(object, label) {
|
1936 | if (object === null || typeof object !== 'object') {
|
1937 | return Promise.reject(new TypeError("RSVP.hashSettled must be called with an object"), label);
|
1938 | }
|
1939 |
|
1940 | return new HashSettled(Promise, object, false, label).promise;
|
1941 | }
|
1942 |
|
1943 | /**
|
1944 | `RSVP.rethrow` will rethrow an error on the next turn of the JavaScript event
|
1945 | loop in order to aid debugging.
|
1946 |
|
1947 | Promises A+ specifies that any exceptions that occur with a promise must be
|
1948 | caught by the promises implementation and bubbled to the last handler. For
|
1949 | this reason, it is recommended that you always specify a second rejection
|
1950 | handler function to `then`. However, `RSVP.rethrow` will throw the exception
|
1951 | outside of the promise, so it bubbles up to your console if in the browser,
|
1952 | or domain/cause uncaught exception in Node. `rethrow` will also throw the
|
1953 | error again so the error can be handled by the promise per the spec.
|
1954 |
|
1955 | ```javascript
|
1956 | function throws(){
|
1957 | throw new Error('Whoops!');
|
1958 | }
|
1959 |
|
1960 | let promise = new RSVP.Promise(function(resolve, reject){
|
1961 | throws();
|
1962 | });
|
1963 |
|
1964 | promise.catch(RSVP.rethrow).then(function(){
|
1965 | // Code here doesn't run because the promise became rejected due to an
|
1966 | // error!
|
1967 | }, function (err){
|
1968 | // handle the error here
|
1969 | });
|
1970 | ```
|
1971 |
|
1972 | The 'Whoops' error will be thrown on the next turn of the event loop
|
1973 | and you can watch for it in your console. You can also handle it using a
|
1974 | rejection handler given to `.then` or `.catch` on the returned promise.
|
1975 |
|
1976 | @method rethrow
|
1977 | @static
|
1978 | @for RSVP
|
1979 | @param {Error} reason reason the promise became rejected.
|
1980 | @throws Error
|
1981 | @static
|
1982 | */
|
1983 | function rethrow(reason) {
|
1984 | setTimeout(function () {
|
1985 | throw reason;
|
1986 | });
|
1987 | throw reason;
|
1988 | }
|
1989 |
|
1990 | /**
|
1991 | `RSVP.defer` returns an object similar to jQuery's `$.Deferred`.
|
1992 | `RSVP.defer` should be used when porting over code reliant on `$.Deferred`'s
|
1993 | interface. New code should use the `RSVP.Promise` constructor instead.
|
1994 |
|
1995 | The object returned from `RSVP.defer` is a plain object with three properties:
|
1996 |
|
1997 | * promise - an `RSVP.Promise`.
|
1998 | * reject - a function that causes the `promise` property on this object to
|
1999 | become rejected
|
2000 | * resolve - a function that causes the `promise` property on this object to
|
2001 | become fulfilled.
|
2002 |
|
2003 | Example:
|
2004 |
|
2005 | ```javascript
|
2006 | let deferred = RSVP.defer();
|
2007 |
|
2008 | deferred.resolve("Success!");
|
2009 |
|
2010 | deferred.promise.then(function(value){
|
2011 | // value here is "Success!"
|
2012 | });
|
2013 | ```
|
2014 |
|
2015 | @method defer
|
2016 | @static
|
2017 | @for RSVP
|
2018 | @param {String} label optional string for labeling the promise.
|
2019 | Useful for tooling.
|
2020 | @return {Object}
|
2021 | */
|
2022 |
|
2023 | function defer(label) {
|
2024 | var deferred = { resolve: undefined, reject: undefined };
|
2025 |
|
2026 | deferred.promise = new Promise(function (resolve, reject) {
|
2027 | deferred.resolve = resolve;
|
2028 | deferred.reject = reject;
|
2029 | }, label);
|
2030 |
|
2031 | return deferred;
|
2032 | }
|
2033 |
|
2034 | function _possibleConstructorReturn$3(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
2035 |
|
2036 | function _inherits$3(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
2037 |
|
2038 | var MapEnumerator = function (_Enumerator) {
|
2039 | _inherits$3(MapEnumerator, _Enumerator);
|
2040 |
|
2041 | function MapEnumerator(Constructor, entries, mapFn, label) {
|
2042 | return _possibleConstructorReturn$3(this, _Enumerator.call(this, Constructor, entries, true, label, mapFn));
|
2043 | }
|
2044 |
|
2045 | MapEnumerator.prototype._init = function _init(Constructor, input, bool, label, mapFn) {
|
2046 | var len = input.length || 0;
|
2047 | this.length = len;
|
2048 | this._remaining = len;
|
2049 | this._result = new Array(len);
|
2050 | this._mapFn = mapFn;
|
2051 |
|
2052 | this._enumerate(input);
|
2053 | };
|
2054 |
|
2055 | MapEnumerator.prototype._setResultAt = function _setResultAt(state, i, value, firstPass) {
|
2056 | if (firstPass) {
|
2057 | var val = tryCatch(this._mapFn)(value, i);
|
2058 | if (val === TRY_CATCH_ERROR) {
|
2059 | this._settledAt(REJECTED, i, val.error, false);
|
2060 | } else {
|
2061 | this._eachEntry(val, i, false);
|
2062 | }
|
2063 | } else {
|
2064 | this._remaining--;
|
2065 | this._result[i] = value;
|
2066 | }
|
2067 | };
|
2068 |
|
2069 | return MapEnumerator;
|
2070 | }(Enumerator);
|
2071 |
|
2072 | /**
|
2073 | `RSVP.map` is similar to JavaScript's native `map` method. `mapFn` is eagerly called
|
2074 | meaning that as soon as any promise resolves its value will be passed to `mapFn`.
|
2075 | `RSVP.map` returns a promise that will become fulfilled with the result of running
|
2076 | `mapFn` on the values the promises become fulfilled with.
|
2077 |
|
2078 | For example:
|
2079 |
|
2080 | ```javascript
|
2081 |
|
2082 | let promise1 = RSVP.resolve(1);
|
2083 | let promise2 = RSVP.resolve(2);
|
2084 | let promise3 = RSVP.resolve(3);
|
2085 | let promises = [ promise1, promise2, promise3 ];
|
2086 |
|
2087 | let mapFn = function(item){
|
2088 | return item + 1;
|
2089 | };
|
2090 |
|
2091 | RSVP.map(promises, mapFn).then(function(result){
|
2092 | // result is [ 2, 3, 4 ]
|
2093 | });
|
2094 | ```
|
2095 |
|
2096 | If any of the `promises` given to `RSVP.map` are rejected, the first promise
|
2097 | that is rejected will be given as an argument to the returned promise's
|
2098 | rejection handler. For example:
|
2099 |
|
2100 | ```javascript
|
2101 | let promise1 = RSVP.resolve(1);
|
2102 | let promise2 = RSVP.reject(new Error('2'));
|
2103 | let promise3 = RSVP.reject(new Error('3'));
|
2104 | let promises = [ promise1, promise2, promise3 ];
|
2105 |
|
2106 | let mapFn = function(item){
|
2107 | return item + 1;
|
2108 | };
|
2109 |
|
2110 | RSVP.map(promises, mapFn).then(function(array){
|
2111 | // Code here never runs because there are rejected promises!
|
2112 | }, function(reason) {
|
2113 | // reason.message === '2'
|
2114 | });
|
2115 | ```
|
2116 |
|
2117 | `RSVP.map` will also wait if a promise is returned from `mapFn`. For example,
|
2118 | say you want to get all comments from a set of blog posts, but you need
|
2119 | the blog posts first because they contain a url to those comments.
|
2120 |
|
2121 | ```javscript
|
2122 |
|
2123 | let mapFn = function(blogPost){
|
2124 | // getComments does some ajax and returns an RSVP.Promise that is fulfilled
|
2125 | // with some comments data
|
2126 | return getComments(blogPost.comments_url);
|
2127 | };
|
2128 |
|
2129 | // getBlogPosts does some ajax and returns an RSVP.Promise that is fulfilled
|
2130 | // with some blog post data
|
2131 | RSVP.map(getBlogPosts(), mapFn).then(function(comments){
|
2132 | // comments is the result of asking the server for the comments
|
2133 | // of all blog posts returned from getBlogPosts()
|
2134 | });
|
2135 | ```
|
2136 |
|
2137 | @method map
|
2138 | @static
|
2139 | @for RSVP
|
2140 | @param {Array} promises
|
2141 | @param {Function} mapFn function to be called on each fulfilled promise.
|
2142 | @param {String} label optional string for labeling the promise.
|
2143 | Useful for tooling.
|
2144 | @return {Promise} promise that is fulfilled with the result of calling
|
2145 | `mapFn` on each fulfilled promise or value when they become fulfilled.
|
2146 | The promise will be rejected if any of the given `promises` become rejected.
|
2147 | @static
|
2148 | */
|
2149 |
|
2150 |
|
2151 | function map(promises, mapFn, label) {
|
2152 | if (!Array.isArray(promises)) {
|
2153 | return Promise.reject(new TypeError("RSVP.map must be called with an array"), label);
|
2154 | }
|
2155 |
|
2156 | if (typeof mapFn !== 'function') {
|
2157 | return Promise.reject(new TypeError("RSVP.map expects a function as a second argument"), label);
|
2158 | }
|
2159 |
|
2160 | return new MapEnumerator(Promise, promises, mapFn, label).promise;
|
2161 | }
|
2162 |
|
2163 | /**
|
2164 | This is a convenient alias for `RSVP.Promise.resolve`.
|
2165 |
|
2166 | @method resolve
|
2167 | @static
|
2168 | @for RSVP
|
2169 | @param {*} value value that the returned promise will be resolved with
|
2170 | @param {String} label optional string for identifying the returned promise.
|
2171 | Useful for tooling.
|
2172 | @return {Promise} a promise that will become fulfilled with the given
|
2173 | `value`
|
2174 | */
|
2175 | function resolve$2(value, label) {
|
2176 | return Promise.resolve(value, label);
|
2177 | }
|
2178 |
|
2179 | /**
|
2180 | This is a convenient alias for `RSVP.Promise.reject`.
|
2181 |
|
2182 | @method reject
|
2183 | @static
|
2184 | @for RSVP
|
2185 | @param {*} reason value that the returned promise will be rejected with.
|
2186 | @param {String} label optional string for identifying the returned promise.
|
2187 | Useful for tooling.
|
2188 | @return {Promise} a promise rejected with the given `reason`.
|
2189 | */
|
2190 | function reject$2(reason, label) {
|
2191 | return Promise.reject(reason, label);
|
2192 | }
|
2193 |
|
2194 | function _possibleConstructorReturn$4(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
2195 |
|
2196 | function _inherits$4(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
2197 |
|
2198 | var EMPTY_OBJECT = {};
|
2199 |
|
2200 | var FilterEnumerator = function (_Enumerator) {
|
2201 | _inherits$4(FilterEnumerator, _Enumerator);
|
2202 |
|
2203 | function FilterEnumerator(Constructor, entries, filterFn, label) {
|
2204 | return _possibleConstructorReturn$4(this, _Enumerator.call(this, Constructor, entries, true, label, filterFn));
|
2205 | }
|
2206 |
|
2207 | FilterEnumerator.prototype._init = function _init(Constructor, input, bool, label, filterFn) {
|
2208 | var len = input.length || 0;
|
2209 | this.length = len;
|
2210 | this._remaining = len;
|
2211 |
|
2212 | this._result = new Array(len);
|
2213 | this._filterFn = filterFn;
|
2214 |
|
2215 | this._enumerate(input);
|
2216 | };
|
2217 |
|
2218 | FilterEnumerator.prototype._checkFullfillment = function _checkFullfillment() {
|
2219 | if (this._remaining === 0) {
|
2220 | this._result = this._result.filter(function (val) {
|
2221 | return val !== EMPTY_OBJECT;
|
2222 | });
|
2223 | fulfill(this.promise, this._result);
|
2224 | }
|
2225 | };
|
2226 |
|
2227 | FilterEnumerator.prototype._setResultAt = function _setResultAt(state, i, value, firstPass) {
|
2228 | if (firstPass) {
|
2229 | this._result[i] = value;
|
2230 | var val = tryCatch(this._filterFn)(value, i);
|
2231 | if (val === TRY_CATCH_ERROR) {
|
2232 | this._settledAt(REJECTED, i, val.error, false);
|
2233 | } else {
|
2234 | this._eachEntry(val, i, false);
|
2235 | }
|
2236 | } else {
|
2237 | this._remaining--;
|
2238 | if (!value) {
|
2239 | this._result[i] = EMPTY_OBJECT;
|
2240 | }
|
2241 | }
|
2242 | };
|
2243 |
|
2244 | return FilterEnumerator;
|
2245 | }(Enumerator);
|
2246 |
|
2247 | /**
|
2248 | `RSVP.filter` is similar to JavaScript's native `filter` method.
|
2249 | `filterFn` is eagerly called meaning that as soon as any promise
|
2250 | resolves its value will be passed to `filterFn`. `RSVP.filter` returns
|
2251 | a promise that will become fulfilled with the result of running
|
2252 | `filterFn` on the values the promises become fulfilled with.
|
2253 |
|
2254 | For example:
|
2255 |
|
2256 | ```javascript
|
2257 |
|
2258 | let promise1 = RSVP.resolve(1);
|
2259 | let promise2 = RSVP.resolve(2);
|
2260 | let promise3 = RSVP.resolve(3);
|
2261 |
|
2262 | let promises = [promise1, promise2, promise3];
|
2263 |
|
2264 | let filterFn = function(item){
|
2265 | return item > 1;
|
2266 | };
|
2267 |
|
2268 | RSVP.filter(promises, filterFn).then(function(result){
|
2269 | // result is [ 2, 3 ]
|
2270 | });
|
2271 | ```
|
2272 |
|
2273 | If any of the `promises` given to `RSVP.filter` are rejected, the first promise
|
2274 | that is rejected will be given as an argument to the returned promise's
|
2275 | rejection handler. For example:
|
2276 |
|
2277 | ```javascript
|
2278 | let promise1 = RSVP.resolve(1);
|
2279 | let promise2 = RSVP.reject(new Error('2'));
|
2280 | let promise3 = RSVP.reject(new Error('3'));
|
2281 | let promises = [ promise1, promise2, promise3 ];
|
2282 |
|
2283 | let filterFn = function(item){
|
2284 | return item > 1;
|
2285 | };
|
2286 |
|
2287 | RSVP.filter(promises, filterFn).then(function(array){
|
2288 | // Code here never runs because there are rejected promises!
|
2289 | }, function(reason) {
|
2290 | // reason.message === '2'
|
2291 | });
|
2292 | ```
|
2293 |
|
2294 | `RSVP.filter` will also wait for any promises returned from `filterFn`.
|
2295 | For instance, you may want to fetch a list of users then return a subset
|
2296 | of those users based on some asynchronous operation:
|
2297 |
|
2298 | ```javascript
|
2299 |
|
2300 | let alice = { name: 'alice' };
|
2301 | let bob = { name: 'bob' };
|
2302 | let users = [ alice, bob ];
|
2303 |
|
2304 | let promises = users.map(function(user){
|
2305 | return RSVP.resolve(user);
|
2306 | });
|
2307 |
|
2308 | let filterFn = function(user){
|
2309 | // Here, Alice has permissions to create a blog post, but Bob does not.
|
2310 | return getPrivilegesForUser(user).then(function(privs){
|
2311 | return privs.can_create_blog_post === true;
|
2312 | });
|
2313 | };
|
2314 | RSVP.filter(promises, filterFn).then(function(users){
|
2315 | // true, because the server told us only Alice can create a blog post.
|
2316 | users.length === 1;
|
2317 | // false, because Alice is the only user present in `users`
|
2318 | users[0] === bob;
|
2319 | });
|
2320 | ```
|
2321 |
|
2322 | @method filter
|
2323 | @static
|
2324 | @for RSVP
|
2325 | @param {Array} promises
|
2326 | @param {Function} filterFn - function to be called on each resolved value to
|
2327 | filter the final results.
|
2328 | @param {String} label optional string describing the promise. Useful for
|
2329 | tooling.
|
2330 | @return {Promise}
|
2331 | */
|
2332 |
|
2333 | function filter(promises, filterFn, label) {
|
2334 | if (!Array.isArray(promises) && !(promises !== null && typeof promises === 'object' && promises.then !== undefined)) {
|
2335 | return Promise.reject(new TypeError("RSVP.filter must be called with an array or promise"), label);
|
2336 | }
|
2337 |
|
2338 | if (typeof filterFn !== 'function') {
|
2339 | return Promise.reject(new TypeError("RSVP.filter expects function as a second argument"), label);
|
2340 | }
|
2341 |
|
2342 | return Promise.resolve(promises, label).then(function (promises) {
|
2343 | return new FilterEnumerator(Promise, promises, filterFn, label).promise;
|
2344 | });
|
2345 | }
|
2346 |
|
2347 | var len = 0;
|
2348 | var vertxNext = void 0;
|
2349 | function asap(callback, arg) {
|
2350 | queue$1[len] = callback;
|
2351 | queue$1[len + 1] = arg;
|
2352 | len += 2;
|
2353 | if (len === 2) {
|
2354 | // If len is 1, that means that we need to schedule an async flush.
|
2355 | // If additional callbacks are queued before the queue is flushed, they
|
2356 | // will be processed by this flush that we are scheduling.
|
2357 | scheduleFlush$1();
|
2358 | }
|
2359 | }
|
2360 |
|
2361 | var browserWindow = typeof window !== 'undefined' ? window : undefined;
|
2362 | var browserGlobal = browserWindow || {};
|
2363 | var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
|
2364 | var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && {}.toString.call(process) === '[object process]';
|
2365 |
|
2366 | // test for web worker but not in IE10
|
2367 | var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined';
|
2368 |
|
2369 | // node
|
2370 | function useNextTick() {
|
2371 | var nextTick = process.nextTick;
|
2372 | // node version 0.10.x displays a deprecation warning when nextTick is used recursively
|
2373 | // setImmediate should be used instead instead
|
2374 | var version = process.versions.node.match(/^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$/);
|
2375 | if (Array.isArray(version) && version[1] === '0' && version[2] === '10') {
|
2376 | nextTick = setImmediate;
|
2377 | }
|
2378 | return function () {
|
2379 | return nextTick(flush);
|
2380 | };
|
2381 | }
|
2382 |
|
2383 | // vertx
|
2384 | function useVertxTimer() {
|
2385 | if (typeof vertxNext !== 'undefined') {
|
2386 | return function () {
|
2387 | vertxNext(flush);
|
2388 | };
|
2389 | }
|
2390 | return useSetTimeout();
|
2391 | }
|
2392 |
|
2393 | function useMutationObserver() {
|
2394 | var iterations = 0;
|
2395 | var observer = new BrowserMutationObserver(flush);
|
2396 | var node = document.createTextNode('');
|
2397 | observer.observe(node, { characterData: true });
|
2398 |
|
2399 | return function () {
|
2400 | return node.data = iterations = ++iterations % 2;
|
2401 | };
|
2402 | }
|
2403 |
|
2404 | // web worker
|
2405 | function useMessageChannel() {
|
2406 | var channel = new MessageChannel();
|
2407 | channel.port1.onmessage = flush;
|
2408 | return function () {
|
2409 | return channel.port2.postMessage(0);
|
2410 | };
|
2411 | }
|
2412 |
|
2413 | function useSetTimeout() {
|
2414 | return function () {
|
2415 | return setTimeout(flush, 1);
|
2416 | };
|
2417 | }
|
2418 |
|
2419 | var queue$1 = new Array(1000);
|
2420 |
|
2421 | function flush() {
|
2422 | for (var i = 0; i < len; i += 2) {
|
2423 | var callback = queue$1[i];
|
2424 | var arg = queue$1[i + 1];
|
2425 |
|
2426 | callback(arg);
|
2427 |
|
2428 | queue$1[i] = undefined;
|
2429 | queue$1[i + 1] = undefined;
|
2430 | }
|
2431 |
|
2432 | len = 0;
|
2433 | }
|
2434 |
|
2435 | function attemptVertex() {
|
2436 | try {
|
2437 | var r = require;
|
2438 | var vertx = r('vertx');
|
2439 | vertxNext = vertx.runOnLoop || vertx.runOnContext;
|
2440 | return useVertxTimer();
|
2441 | } catch (e) {
|
2442 | return useSetTimeout();
|
2443 | }
|
2444 | }
|
2445 |
|
2446 | var scheduleFlush$1 = void 0;
|
2447 | // Decide what async method to use to triggering processing of queued callbacks:
|
2448 | if (isNode) {
|
2449 | scheduleFlush$1 = useNextTick();
|
2450 | } else if (BrowserMutationObserver) {
|
2451 | scheduleFlush$1 = useMutationObserver();
|
2452 | } else if (isWorker) {
|
2453 | scheduleFlush$1 = useMessageChannel();
|
2454 | } else if (browserWindow === undefined && typeof require === 'function') {
|
2455 | scheduleFlush$1 = attemptVertex();
|
2456 | } else {
|
2457 | scheduleFlush$1 = useSetTimeout();
|
2458 | }
|
2459 |
|
2460 | var platform = void 0;
|
2461 |
|
2462 | /* global self */
|
2463 | if (typeof self === 'object') {
|
2464 | platform = self;
|
2465 |
|
2466 | /* global global */
|
2467 | } else if (typeof global === 'object') {
|
2468 | platform = global;
|
2469 | } else {
|
2470 | throw new Error('no global: `self` or `global` found');
|
2471 | }
|
2472 |
|
2473 | var _asap$cast$Promise$Ev;
|
2474 |
|
2475 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
2476 |
|
2477 | // defaults
|
2478 | config.async = asap;
|
2479 | config.after = function (cb) {
|
2480 | return setTimeout(cb, 0);
|
2481 | };
|
2482 | var cast = resolve$2;
|
2483 |
|
2484 | var async = function (callback, arg) {
|
2485 | return config.async(callback, arg);
|
2486 | };
|
2487 |
|
2488 | function on() {
|
2489 | config['on'].apply(config, arguments);
|
2490 | }
|
2491 |
|
2492 | function off() {
|
2493 | config['off'].apply(config, arguments);
|
2494 | }
|
2495 |
|
2496 | // Set up instrumentation through `window.__PROMISE_INTRUMENTATION__`
|
2497 | if (typeof window !== 'undefined' && typeof window['__PROMISE_INSTRUMENTATION__'] === 'object') {
|
2498 | var callbacks = window['__PROMISE_INSTRUMENTATION__'];
|
2499 | configure('instrument', true);
|
2500 | for (var eventName in callbacks) {
|
2501 | if (callbacks.hasOwnProperty(eventName)) {
|
2502 | on(eventName, callbacks[eventName]);
|
2503 | }
|
2504 | }
|
2505 | }
|
2506 |
|
2507 | // the default export here is for backwards compat:
|
2508 | // https://github.com/tildeio/rsvp.js/issues/434
|
2509 | var rsvp = (_asap$cast$Promise$Ev = {
|
2510 | asap: asap,
|
2511 | cast: cast,
|
2512 | Promise: Promise,
|
2513 | EventTarget: EventTarget,
|
2514 | all: all$1,
|
2515 | allSettled: allSettled,
|
2516 | race: race$1,
|
2517 | hash: hash,
|
2518 | hashSettled: hashSettled,
|
2519 | rethrow: rethrow,
|
2520 | defer: defer,
|
2521 | denodeify: denodeify,
|
2522 | configure: configure,
|
2523 | on: on,
|
2524 | off: off,
|
2525 | resolve: resolve$2,
|
2526 | reject: reject$2,
|
2527 | map: map
|
2528 | }, _defineProperty(_asap$cast$Promise$Ev, 'async', async), _defineProperty(_asap$cast$Promise$Ev, 'filter', filter), _asap$cast$Promise$Ev);
|
2529 |
|
2530 | export { asap, cast, Promise, EventTarget, all$1 as all, allSettled, race$1 as race, hash, hashSettled, rethrow, defer, denodeify, configure, on, off, resolve$2 as resolve, reject$2 as reject, map, async, filter };export default rsvp;
|
2531 |
|
2532 | //# sourceMappingURL=rsvp.es.map
|