1 |
|
2 |
|
3 |
|
4 |
|
5 | (function(define) { 'use strict';
|
6 | define(function() {
|
7 |
|
8 | return function makePromise(environment) {
|
9 |
|
10 | var tasks = environment.scheduler;
|
11 |
|
12 | var objectCreate = Object.create ||
|
13 | function(proto) {
|
14 | function Child() {}
|
15 | Child.prototype = proto;
|
16 | return new Child();
|
17 | };
|
18 |
|
19 | |
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 | function Promise(resolver, handler) {
|
26 | this._handler = resolver === Handler ? handler : init(resolver);
|
27 | }
|
28 |
|
29 | |
30 |
|
31 |
|
32 |
|
33 |
|
34 | function init(resolver) {
|
35 | var handler = new Pending();
|
36 |
|
37 | try {
|
38 | resolver(promiseResolve, promiseReject, promiseNotify);
|
39 | } catch (e) {
|
40 | promiseReject(e);
|
41 | }
|
42 |
|
43 | return handler;
|
44 |
|
45 | |
46 |
|
47 |
|
48 |
|
49 |
|
50 | function promiseResolve (x) {
|
51 | handler.resolve(x);
|
52 | }
|
53 | |
54 |
|
55 |
|
56 |
|
57 |
|
58 | function promiseReject (reason) {
|
59 | handler.reject(reason);
|
60 | }
|
61 |
|
62 | |
63 |
|
64 |
|
65 |
|
66 | function promiseNotify (x) {
|
67 | handler.notify(x);
|
68 | }
|
69 | }
|
70 |
|
71 |
|
72 |
|
73 | Promise.resolve = resolve;
|
74 | Promise.reject = reject;
|
75 | Promise.never = never;
|
76 |
|
77 | Promise._defer = defer;
|
78 | Promise._handler = getHandler;
|
79 |
|
80 | |
81 |
|
82 |
|
83 |
|
84 |
|
85 |
|
86 | function resolve(x) {
|
87 | return isPromise(x) ? x
|
88 | : new Promise(Handler, new Async(getHandler(x)));
|
89 | }
|
90 |
|
91 | |
92 |
|
93 |
|
94 |
|
95 |
|
96 | function reject(x) {
|
97 | return new Promise(Handler, new Async(new Rejected(x)));
|
98 | }
|
99 |
|
100 | |
101 |
|
102 |
|
103 |
|
104 | function never() {
|
105 | return foreverPendingPromise;
|
106 | }
|
107 |
|
108 | |
109 |
|
110 |
|
111 |
|
112 |
|
113 | function defer() {
|
114 | return new Promise(Handler, new Pending());
|
115 | }
|
116 |
|
117 |
|
118 |
|
119 | |
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 |
|
128 |
|
129 | Promise.prototype.then = function(onFulfilled, onRejected) {
|
130 | var parent = this._handler;
|
131 |
|
132 | if (typeof onFulfilled !== 'function' && parent.join().state() > 0) {
|
133 |
|
134 | return new Promise(Handler, parent);
|
135 | }
|
136 |
|
137 | var p = this._beget();
|
138 | var child = p._handler;
|
139 |
|
140 | parent.chain(child, parent.receiver, onFulfilled, onRejected,
|
141 | arguments.length > 2 ? arguments[2] : void 0);
|
142 |
|
143 | return p;
|
144 | };
|
145 |
|
146 | |
147 |
|
148 |
|
149 |
|
150 |
|
151 |
|
152 | Promise.prototype['catch'] = function(onRejected) {
|
153 | return this.then(void 0, onRejected);
|
154 | };
|
155 |
|
156 | |
157 |
|
158 |
|
159 |
|
160 |
|
161 | Promise.prototype._beget = function() {
|
162 | var parent = this._handler;
|
163 | var child = new Pending(parent.receiver, parent.join().context);
|
164 | return new this.constructor(Handler, child);
|
165 | };
|
166 |
|
167 |
|
168 |
|
169 | Promise.all = all;
|
170 | Promise.race = race;
|
171 |
|
172 | |
173 |
|
174 |
|
175 |
|
176 |
|
177 |
|
178 |
|
179 | function all(promises) {
|
180 |
|
181 | var resolver = new Pending();
|
182 | var pending = promises.length >>> 0;
|
183 | var results = new Array(pending);
|
184 |
|
185 | var i, h, x, s;
|
186 | for (i = 0; i < promises.length; ++i) {
|
187 | x = promises[i];
|
188 |
|
189 | if (x === void 0 && !(i in promises)) {
|
190 | --pending;
|
191 | continue;
|
192 | }
|
193 |
|
194 | if (maybeThenable(x)) {
|
195 | h = isPromise(x)
|
196 | ? x._handler.join()
|
197 | : getHandlerUntrusted(x);
|
198 |
|
199 | s = h.state();
|
200 | if (s === 0) {
|
201 | h.fold(settleAt, i, results, resolver);
|
202 | } else if (s > 0) {
|
203 | results[i] = h.value;
|
204 | --pending;
|
205 | } else {
|
206 | resolver.become(h);
|
207 | break;
|
208 | }
|
209 |
|
210 | } else {
|
211 | results[i] = x;
|
212 | --pending;
|
213 | }
|
214 | }
|
215 |
|
216 | if(pending === 0) {
|
217 | resolver.become(new Fulfilled(results));
|
218 | }
|
219 |
|
220 | return new Promise(Handler, resolver);
|
221 |
|
222 | function settleAt(i, x, resolver) {
|
223 |
|
224 | this[i] = x;
|
225 | if(--pending === 0) {
|
226 | resolver.become(new Fulfilled(this));
|
227 | }
|
228 | }
|
229 | }
|
230 |
|
231 | |
232 |
|
233 |
|
234 |
|
235 |
|
236 |
|
237 |
|
238 |
|
239 |
|
240 |
|
241 |
|
242 |
|
243 |
|
244 |
|
245 | function race(promises) {
|
246 |
|
247 |
|
248 | if(Object(promises) === promises && promises.length === 0) {
|
249 | return never();
|
250 | }
|
251 |
|
252 | var h = new Pending();
|
253 | var i, x;
|
254 | for(i=0; i<promises.length; ++i) {
|
255 | x = promises[i];
|
256 | if (x !== void 0 && i in promises) {
|
257 | getHandler(x).visit(h, h.resolve, h.reject);
|
258 | }
|
259 | }
|
260 | return new Promise(Handler, h);
|
261 | }
|
262 |
|
263 |
|
264 |
|
265 |
|
266 | |
267 |
|
268 |
|
269 |
|
270 |
|
271 | function getHandler(x) {
|
272 | if(isPromise(x)) {
|
273 | return x._handler.join();
|
274 | }
|
275 | return maybeThenable(x) ? getHandlerUntrusted(x) : new Fulfilled(x);
|
276 | }
|
277 |
|
278 | |
279 |
|
280 |
|
281 |
|
282 |
|
283 | function getHandlerUntrusted(x) {
|
284 | try {
|
285 | var untrustedThen = x.then;
|
286 | return typeof untrustedThen === 'function'
|
287 | ? new Thenable(untrustedThen, x)
|
288 | : new Fulfilled(x);
|
289 | } catch(e) {
|
290 | return new Rejected(e);
|
291 | }
|
292 | }
|
293 |
|
294 | |
295 |
|
296 |
|
297 |
|
298 | function Handler() {}
|
299 |
|
300 | Handler.prototype.when
|
301 | = Handler.prototype.become
|
302 | = Handler.prototype.notify
|
303 | = Handler.prototype.fail
|
304 | = Handler.prototype._unreport
|
305 | = Handler.prototype._report
|
306 | = noop;
|
307 |
|
308 | Handler.prototype._state = 0;
|
309 |
|
310 | Handler.prototype.state = function() {
|
311 | return this._state;
|
312 | };
|
313 |
|
314 | |
315 |
|
316 |
|
317 |
|
318 |
|
319 | Handler.prototype.join = function() {
|
320 | var h = this;
|
321 | while(h.handler !== void 0) {
|
322 | h = h.handler;
|
323 | }
|
324 | return h;
|
325 | };
|
326 |
|
327 | Handler.prototype.chain = function(to, receiver, fulfilled, rejected, progress) {
|
328 | this.when({
|
329 | resolver: to,
|
330 | receiver: receiver,
|
331 | fulfilled: fulfilled,
|
332 | rejected: rejected,
|
333 | progress: progress
|
334 | });
|
335 | };
|
336 |
|
337 | Handler.prototype.visit = function(receiver, fulfilled, rejected, progress) {
|
338 | this.chain(failIfRejected, receiver, fulfilled, rejected, progress);
|
339 | };
|
340 |
|
341 | Handler.prototype.fold = function(f, z, c, to) {
|
342 | this.visit(to, function(x) {
|
343 | f.call(c, z, x, this);
|
344 | }, to.reject, to.notify);
|
345 | };
|
346 |
|
347 | |
348 |
|
349 |
|
350 |
|
351 | function FailIfRejected() {}
|
352 |
|
353 | inherit(Handler, FailIfRejected);
|
354 |
|
355 | FailIfRejected.prototype.become = function(h) {
|
356 | h.fail();
|
357 | };
|
358 |
|
359 | var failIfRejected = new FailIfRejected();
|
360 |
|
361 | |
362 |
|
363 |
|
364 |
|
365 | function Pending(receiver, inheritedContext) {
|
366 | Promise.createContext(this, inheritedContext);
|
367 |
|
368 | this.consumers = void 0;
|
369 | this.receiver = receiver;
|
370 | this.handler = void 0;
|
371 | this.resolved = false;
|
372 | }
|
373 |
|
374 | inherit(Handler, Pending);
|
375 |
|
376 | Pending.prototype._state = 0;
|
377 |
|
378 | Pending.prototype.resolve = function(x) {
|
379 | this.become(getHandler(x));
|
380 | };
|
381 |
|
382 | Pending.prototype.reject = function(x) {
|
383 | if(this.resolved) {
|
384 | return;
|
385 | }
|
386 |
|
387 | this.become(new Rejected(x));
|
388 | };
|
389 |
|
390 | Pending.prototype.join = function() {
|
391 | if (!this.resolved) {
|
392 | return this;
|
393 | }
|
394 |
|
395 | var h = this;
|
396 |
|
397 | while (h.handler !== void 0) {
|
398 | h = h.handler;
|
399 | if (h === this) {
|
400 | return this.handler = cycle();
|
401 | }
|
402 | }
|
403 |
|
404 | return h;
|
405 | };
|
406 |
|
407 | Pending.prototype.run = function() {
|
408 | var q = this.consumers;
|
409 | var handler = this.join();
|
410 | this.consumers = void 0;
|
411 |
|
412 | for (var i = 0; i < q.length; ++i) {
|
413 | handler.when(q[i]);
|
414 | }
|
415 | };
|
416 |
|
417 | Pending.prototype.become = function(handler) {
|
418 | if(this.resolved) {
|
419 | return;
|
420 | }
|
421 |
|
422 | this.resolved = true;
|
423 | this.handler = handler;
|
424 | if(this.consumers !== void 0) {
|
425 | tasks.enqueue(this);
|
426 | }
|
427 |
|
428 | if(this.context !== void 0) {
|
429 | handler._report(this.context);
|
430 | }
|
431 | };
|
432 |
|
433 | Pending.prototype.when = function(continuation) {
|
434 | if(this.resolved) {
|
435 | tasks.enqueue(new ContinuationTask(continuation, this.handler));
|
436 | } else {
|
437 | if(this.consumers === void 0) {
|
438 | this.consumers = [continuation];
|
439 | } else {
|
440 | this.consumers.push(continuation);
|
441 | }
|
442 | }
|
443 | };
|
444 |
|
445 | Pending.prototype.notify = function(x) {
|
446 | if(!this.resolved) {
|
447 | tasks.enqueue(new ProgressTask(x, this));
|
448 | }
|
449 | };
|
450 |
|
451 | Pending.prototype.fail = function(context) {
|
452 | var c = typeof context === 'undefined' ? this.context : context;
|
453 | this.resolved && this.handler.join().fail(c);
|
454 | };
|
455 |
|
456 | Pending.prototype._report = function(context) {
|
457 | this.resolved && this.handler.join()._report(context);
|
458 | };
|
459 |
|
460 | Pending.prototype._unreport = function() {
|
461 | this.resolved && this.handler.join()._unreport();
|
462 | };
|
463 |
|
464 | |
465 |
|
466 |
|
467 |
|
468 |
|
469 | function Delegating(handler) {
|
470 | this.handler = handler;
|
471 | }
|
472 |
|
473 | inherit(Handler, Delegating);
|
474 |
|
475 | Delegating.prototype._report = function(context) {
|
476 | this.join()._report(context);
|
477 | };
|
478 |
|
479 | Delegating.prototype._unreport = function() {
|
480 | this.join()._unreport();
|
481 | };
|
482 |
|
483 | |
484 |
|
485 |
|
486 |
|
487 |
|
488 | function Async(handler) {
|
489 | Delegating.call(this, handler);
|
490 | }
|
491 |
|
492 | inherit(Delegating, Async);
|
493 |
|
494 | Async.prototype.when = function(continuation) {
|
495 | tasks.enqueue(new ContinuationTask(continuation, this));
|
496 | };
|
497 |
|
498 | |
499 |
|
500 |
|
501 |
|
502 |
|
503 |
|
504 | function Thenable(then, thenable) {
|
505 | Pending.call(this);
|
506 | tasks.enqueue(new AssimilateTask(then, thenable, this));
|
507 | }
|
508 |
|
509 | inherit(Pending, Thenable);
|
510 |
|
511 | |
512 |
|
513 |
|
514 |
|
515 |
|
516 | function Fulfilled(x) {
|
517 | Promise.createContext(this);
|
518 | this.value = x;
|
519 | }
|
520 |
|
521 | inherit(Handler, Fulfilled);
|
522 |
|
523 | Fulfilled.prototype._state = 1;
|
524 |
|
525 | Fulfilled.prototype.fold = function(f, z, c, to) {
|
526 | runContinuation3(f, z, this, c, to);
|
527 | };
|
528 |
|
529 | Fulfilled.prototype.when = function(cont) {
|
530 | runContinuation1(cont.fulfilled, this, cont.receiver, cont.resolver);
|
531 | };
|
532 |
|
533 | var errorId = 0;
|
534 |
|
535 | |
536 |
|
537 |
|
538 |
|
539 |
|
540 | function Rejected(x) {
|
541 | Promise.createContext(this);
|
542 |
|
543 | this.id = ++errorId;
|
544 | this.value = x;
|
545 | this.handled = false;
|
546 | this.reported = false;
|
547 |
|
548 | this._report();
|
549 | }
|
550 |
|
551 | inherit(Handler, Rejected);
|
552 |
|
553 | Rejected.prototype._state = -1;
|
554 |
|
555 | Rejected.prototype.fold = function(f, z, c, to) {
|
556 | to.become(this);
|
557 | };
|
558 |
|
559 | Rejected.prototype.when = function(cont) {
|
560 | if(typeof cont.rejected === 'function') {
|
561 | this._unreport();
|
562 | }
|
563 | runContinuation1(cont.rejected, this, cont.receiver, cont.resolver);
|
564 | };
|
565 |
|
566 | Rejected.prototype._report = function(context) {
|
567 | tasks.afterQueue(new ReportTask(this, context));
|
568 | };
|
569 |
|
570 | Rejected.prototype._unreport = function() {
|
571 | this.handled = true;
|
572 | tasks.afterQueue(new UnreportTask(this));
|
573 | };
|
574 |
|
575 | Rejected.prototype.fail = function(context) {
|
576 | Promise.onFatalRejection(this, context === void 0 ? this.context : context);
|
577 | };
|
578 |
|
579 | function ReportTask(rejection, context) {
|
580 | this.rejection = rejection;
|
581 | this.context = context;
|
582 | }
|
583 |
|
584 | ReportTask.prototype.run = function() {
|
585 | if(!this.rejection.handled) {
|
586 | this.rejection.reported = true;
|
587 | Promise.onPotentiallyUnhandledRejection(this.rejection, this.context);
|
588 | }
|
589 | };
|
590 |
|
591 | function UnreportTask(rejection) {
|
592 | this.rejection = rejection;
|
593 | }
|
594 |
|
595 | UnreportTask.prototype.run = function() {
|
596 | if(this.rejection.reported) {
|
597 | Promise.onPotentiallyUnhandledRejectionHandled(this.rejection);
|
598 | }
|
599 | };
|
600 |
|
601 |
|
602 |
|
603 |
|
604 |
|
605 | Promise.createContext
|
606 | = Promise.enterContext
|
607 | = Promise.exitContext
|
608 | = Promise.onPotentiallyUnhandledRejection
|
609 | = Promise.onPotentiallyUnhandledRejectionHandled
|
610 | = Promise.onFatalRejection
|
611 | = noop;
|
612 |
|
613 |
|
614 |
|
615 | var foreverPendingHandler = new Handler();
|
616 | var foreverPendingPromise = new Promise(Handler, foreverPendingHandler);
|
617 |
|
618 | function cycle() {
|
619 | return new Rejected(new TypeError('Promise cycle'));
|
620 | }
|
621 |
|
622 |
|
623 |
|
624 | |
625 |
|
626 |
|
627 |
|
628 | function ContinuationTask(continuation, handler) {
|
629 | this.continuation = continuation;
|
630 | this.handler = handler;
|
631 | }
|
632 |
|
633 | ContinuationTask.prototype.run = function() {
|
634 | this.handler.join().when(this.continuation);
|
635 | };
|
636 |
|
637 | |
638 |
|
639 |
|
640 |
|
641 | function ProgressTask(value, handler) {
|
642 | this.handler = handler;
|
643 | this.value = value;
|
644 | }
|
645 |
|
646 | ProgressTask.prototype.run = function() {
|
647 | var q = this.handler.consumers;
|
648 | if(q === void 0) {
|
649 | return;
|
650 | }
|
651 |
|
652 | for (var c, i = 0; i < q.length; ++i) {
|
653 | c = q[i];
|
654 | runNotify(c.progress, this.value, this.handler, c.receiver, c.resolver);
|
655 | }
|
656 | };
|
657 |
|
658 | |
659 |
|
660 |
|
661 |
|
662 |
|
663 |
|
664 |
|
665 | function AssimilateTask(then, thenable, resolver) {
|
666 | this._then = then;
|
667 | this.thenable = thenable;
|
668 | this.resolver = resolver;
|
669 | }
|
670 |
|
671 | AssimilateTask.prototype.run = function() {
|
672 | var h = this.resolver;
|
673 | tryAssimilate(this._then, this.thenable, _resolve, _reject, _notify);
|
674 |
|
675 | function _resolve(x) { h.resolve(x); }
|
676 | function _reject(x) { h.reject(x); }
|
677 | function _notify(x) { h.notify(x); }
|
678 | };
|
679 |
|
680 | function tryAssimilate(then, thenable, resolve, reject, notify) {
|
681 | try {
|
682 | then.call(thenable, resolve, reject, notify);
|
683 | } catch (e) {
|
684 | reject(e);
|
685 | }
|
686 | }
|
687 |
|
688 |
|
689 |
|
690 | |
691 |
|
692 |
|
693 |
|
694 | function isPromise(x) {
|
695 | return x instanceof Promise;
|
696 | }
|
697 |
|
698 | |
699 |
|
700 |
|
701 |
|
702 |
|
703 |
|
704 | function maybeThenable(x) {
|
705 | return (typeof x === 'object' || typeof x === 'function') && x !== null;
|
706 | }
|
707 |
|
708 | function runContinuation1(f, h, receiver, next) {
|
709 | if(typeof f !== 'function') {
|
710 | return next.become(h);
|
711 | }
|
712 |
|
713 | Promise.enterContext(h);
|
714 | tryCatchReject(f, h.value, receiver, next);
|
715 | Promise.exitContext();
|
716 | }
|
717 |
|
718 | function runContinuation3(f, x, h, receiver, next) {
|
719 | if(typeof f !== 'function') {
|
720 | return next.become(h);
|
721 | }
|
722 |
|
723 | Promise.enterContext(h);
|
724 | tryCatchReject3(f, x, h.value, receiver, next);
|
725 | Promise.exitContext();
|
726 | }
|
727 |
|
728 | function runNotify(f, x, h, receiver, next) {
|
729 | if(typeof f !== 'function') {
|
730 | return next.notify(x);
|
731 | }
|
732 |
|
733 | Promise.enterContext(h);
|
734 | tryCatchReturn(f, x, receiver, next);
|
735 | Promise.exitContext();
|
736 | }
|
737 |
|
738 | |
739 |
|
740 |
|
741 |
|
742 | function tryCatchReject(f, x, thisArg, next) {
|
743 | try {
|
744 | next.become(getHandler(f.call(thisArg, x)));
|
745 | } catch(e) {
|
746 | next.become(new Rejected(e));
|
747 | }
|
748 | }
|
749 |
|
750 | |
751 |
|
752 |
|
753 | function tryCatchReject3(f, x, y, thisArg, next) {
|
754 | try {
|
755 | f.call(thisArg, x, y, next);
|
756 | } catch(e) {
|
757 | next.become(new Rejected(e));
|
758 | }
|
759 | }
|
760 |
|
761 | |
762 |
|
763 |
|
764 | function tryCatchReturn(f, x, thisArg, next) {
|
765 | try {
|
766 | next.notify(f.call(thisArg, x));
|
767 | } catch(e) {
|
768 | next.notify(e);
|
769 | }
|
770 | }
|
771 |
|
772 | function inherit(Parent, Child) {
|
773 | Child.prototype = objectCreate(Parent.prototype);
|
774 | Child.prototype.constructor = Child;
|
775 | }
|
776 |
|
777 | function noop() {}
|
778 |
|
779 | return Promise;
|
780 | };
|
781 | });
|
782 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
|