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