├── server
├── .jshintrc
└── index.js
├── lib
├── es6-promise.auto.js
├── es6-promise.js
└── es6-promise
│ ├── utils.js
│ ├── then.js
│ ├── polyfill.js
│ ├── promise
│ ├── resolve.js
│ ├── reject.js
│ ├── all.js
│ └── race.js
│ ├── enumerator.js
│ ├── asap.js
│ ├── -internal.js
│ └── promise.js
├── .gitignore
├── test
├── index.js
├── worker.js
├── index.html
├── test-adapter.js
├── scheduler-test.js
└── extension-test.js
├── .spmignore
├── auto.js
├── testem.json
├── config
├── versionTemplate.txt
└── s3ProjectConfig.js
├── .release.json
├── bower.json
├── .travis.yml
├── bin
└── publish_to_s3.js
├── .eslintrc
├── .jshintrc
├── LICENSE
├── vendor
└── loader.js
├── package.json
├── README.md
├── Brocfile.js
├── CHANGELOG.md
├── es6-promise.d.ts
└── dist
├── es6-promise.min.js
├── es6-promise.auto.min.js
├── es6-promise.js
└── es6-promise.auto.js
/server/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "node": true
3 | }
4 |
--------------------------------------------------------------------------------
/lib/es6-promise.auto.js:
--------------------------------------------------------------------------------
1 | import Promise from './es6-promise';
2 | Promise.polyfill();
3 | export default Promise;
4 |
--------------------------------------------------------------------------------
/server/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function(app) {
2 | app.get('/', function(req, res) {
3 | res.redirect('/test/');
4 | })
5 | };
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /promises_tests
3 | /main.js
4 | /tmp
5 | /docs
6 | /dist/test
7 | !/dist/es6-promise.js
8 | !/dist/es6-promise.min.js
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | require('./test-adapter.js');
2 | require('./scheduler-test.js');
3 | require('./extension-test.js');
4 | require('promises-aplus-tests-phantom/lib/testFiles');
5 |
--------------------------------------------------------------------------------
/.spmignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 | /tmp
3 | /tasks
4 | /test
5 | /vendor
6 | /.jshintrc
7 | /.npmignore
8 | /.travis.yml
9 | /Gruntfile.js
10 | /component.json
11 | /index.html
12 |
--------------------------------------------------------------------------------
/auto.js:
--------------------------------------------------------------------------------
1 | // This file can be required in Browserify and Node.js for automatic polyfill
2 | // To use it: require('es6-promise/auto');
3 | 'use strict';
4 | module.exports = require('./').polyfill();
5 |
--------------------------------------------------------------------------------
/lib/es6-promise.js:
--------------------------------------------------------------------------------
1 | import Promise from './es6-promise/promise';
2 | import polyfill from './es6-promise/polyfill';
3 |
4 | // Strange compat..
5 | Promise.polyfill = polyfill;
6 | Promise.Promise = Promise;
7 | export default Promise;
8 |
--------------------------------------------------------------------------------
/testem.json:
--------------------------------------------------------------------------------
1 | {
2 | "test_page": "test/index.html",
3 | "parallel": 5,
4 | "frameworks": "mocha",
5 | "launchers": {
6 | "Mocha": {
7 | "command": "./node_modules/.bin/mocha dist/test/browserify.js"
8 | }
9 | },
10 | "launch_in_ci": [
11 | "PhantomJS",
12 | "Mocha"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/config/versionTemplate.txt:
--------------------------------------------------------------------------------
1 | /*!
2 | * @overview es6-promise - a tiny implementation of Promises/A+.
3 | * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
4 | * @license Licensed under MIT license
5 | * See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE
6 | * @version VERSION_PLACEHOLDER_STRING
7 | */
8 |
--------------------------------------------------------------------------------
/test/worker.js:
--------------------------------------------------------------------------------
1 | importScripts('es6-promise.js');
2 | new ES6Promise.Promise(function(resolve, reject) {
3 | self.onmessage = function (e) {
4 | if (e.data === 'ping') {
5 | resolve('pong');
6 | } else {
7 | reject(new Error('wrong message'));
8 | }
9 | };
10 | }).then(function (result) {
11 | self.postMessage(result);
12 | }, function (err){
13 | setTimeout(function () {
14 | throw err;
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/.release.json:
--------------------------------------------------------------------------------
1 | {
2 | "non-interactive": true,
3 | "dry-run": false,
4 | "verbose": false,
5 | "force": false,
6 | "pkgFiles": ["package.json", "bower.json"],
7 | "increment": "patch",
8 | "commitMessage": "Release %s",
9 | "tagName": "v%s",
10 | "tagAnnotation": "Release %s",
11 | "buildCommand": "npm run-script build:production",
12 | "dist": {
13 | "repo": "git@github.com:components/es6-promise.git",
14 | "stageDir": "tmp/stage",
15 | "base": "dist",
16 | "files": ["**/*", "../package.json", "../bower.json"]
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lib/es6-promise/utils.js:
--------------------------------------------------------------------------------
1 | export function objectOrFunction(x) {
2 | return typeof x === 'function' || (typeof x === 'object' && x !== null);
3 | }
4 |
5 | export function isFunction(x) {
6 | return typeof x === 'function';
7 | }
8 |
9 | export function isMaybeThenable(x) {
10 | return typeof x === 'object' && x !== null;
11 | }
12 |
13 | let _isArray;
14 | if (!Array.isArray) {
15 | _isArray = x => Object.prototype.toString.call(x) === '[object Array]';
16 | } else {
17 | _isArray = Array.isArray;
18 | }
19 |
20 | export const isArray = _isArray;
21 |
--------------------------------------------------------------------------------
/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | rsvp.js Tests
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
19 |
20 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "es6-promise",
3 | "namespace": "Promise",
4 | "description": "A polyfill for ES6-style Promises, tracking rsvp",
5 | "authors": [
6 | "Stefan Penner "
7 | ],
8 | "main": "dist/es6-promise.js",
9 | "keywords": [
10 | "promise"
11 | ],
12 | "repository": {
13 | "type": "git",
14 | "url": "git://github.com/stefanpenner/es6-promise.git"
15 | },
16 | "bugs": {
17 | "url": "https://github.com/stefanpenner/es6-promise/issues"
18 | },
19 | "license": "MIT",
20 | "ignore": [
21 | "node_modules",
22 | "bower_components",
23 | "test",
24 | "tests",
25 | "vendor",
26 | "tasks"
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------
/test/test-adapter.js:
--------------------------------------------------------------------------------
1 | var assert = require('assert');
2 | var Promise = require('./es6-promise');
3 |
4 | assert(typeof Promise.polyfill === 'function')
5 | assert(typeof Promise.Promise === 'function')
6 | assert(Promise.Promise === Promise)
7 |
8 | function defer() {
9 | var deferred = {};
10 |
11 | deferred.promise = new Promise(function(resolve, reject) {
12 | deferred.resolve = resolve;
13 | deferred.reject = reject;
14 | });
15 |
16 | return deferred;
17 | }
18 |
19 | new Function('return this;')().adapter = {
20 | resolved: function(a) { return Promise.resolve(a); },
21 | rejected: function(a) { return Promise.reject(a); },
22 | deferred: defer,
23 | Promise: Promise
24 | };
25 |
--------------------------------------------------------------------------------
/config/s3ProjectConfig.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Using wildcard because es6-promise does not currently have a
3 | * channel system in place.
4 | */
5 | module.exports = function(revision,tag,date){
6 | return {
7 | 'es6-promise.js':
8 | { contentType: 'text/javascript',
9 | destinations: {
10 | wildcard: [
11 | 'es6-promise-latest.js',
12 | 'es6-promise-' + revision + '.js'
13 | ]
14 | }
15 | },
16 | 'es6-promise.min.js':
17 | { contentType: 'text/javascript',
18 | destinations: {
19 | wildcard: [
20 | 'es6-promise-latest.min.js',
21 | 'es6-promise-' + revision + '.min.js'
22 | ]
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/es6-promise/then.js:
--------------------------------------------------------------------------------
1 | import {
2 | invokeCallback,
3 | subscribe,
4 | FULFILLED,
5 | REJECTED,
6 | noop,
7 | makePromise,
8 | PROMISE_ID
9 | } from './-internal';
10 |
11 | import { asap } from './asap';
12 |
13 | export default function then(onFulfillment, onRejection) {
14 | const parent = this;
15 |
16 | const child = new this.constructor(noop);
17 |
18 | if (child[PROMISE_ID] === undefined) {
19 | makePromise(child);
20 | }
21 |
22 | const { _state } = parent;
23 |
24 | if (_state) {
25 | const callback = arguments[_state - 1];
26 | asap(() => invokeCallback(_state, child, callback, parent._result));
27 | } else {
28 | subscribe(parent, child, onFulfillment, onRejection);
29 | }
30 |
31 | return child;
32 | }
33 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "7"
4 | - "6"
5 | - "4"
6 |
7 | after_success:
8 | - "./bin/publish_to_s3.js"
9 | before_install:
10 | - nvm install 6
11 | - nvm use 6
12 | - export PATH=/usr/local/phantomjs-2.0.0/bin:$PATH
13 | before_script:
14 | - nvm use $TRAVIS_NODE_VERSION
15 | env:
16 | global:
17 | - EMBER_ENV=production
18 | - secure: MiR5zbpHpblG1HcQyxzhYqxcb+3gGsjKWOjLYi1AOU4BG90+Ckim4mCJbneIHaBfeIZKZCm+X1wRRwUE0TlaMFEiXqReHt8k/1ChjfFdTicZtXYytbnGdRlHjvN/LVCaVhBiORSXWPzjIWhwYInMhCtekWTOqChtblRGdbrCLCY=
19 | - secure: LF1yJIzr4z5e4RxFt+ZIwjazDyItPoPtSUgcoSQfTUhRtkxFsIRpOpf4VnzPH2FSpw4wbkNq+hm+K1xrKHNq+OE0PLYtD+H7i03ac993jReSJN8rwb0gpAlwAGWC++uF7j7aMKJAlZA1u4tnPD5cxuk6BKnNSONtD0BwKQ6oXkk=
20 | - secure: MB2RZPsHVuikayckVYCVE9TWiooaFV+jyxEkpSoNJ5pRIVTwy9xRHK56S1sxkXmPIm7sYyaLWpngp13/CN80pT796HS8mEuxJ011XwjY6YutXHnR2gOrCssah6kQ6gaXO1sFVkerBa/GwdkKu/k8LVAiORiz1JlPZvOKDRsJaNw=
21 |
--------------------------------------------------------------------------------
/lib/es6-promise/polyfill.js:
--------------------------------------------------------------------------------
1 | /*global self*/
2 | import Promise from './promise';
3 |
4 | export default function polyfill() {
5 | let local;
6 |
7 | if (typeof global !== 'undefined') {
8 | local = global;
9 | } else if (typeof self !== 'undefined') {
10 | local = self;
11 | } else {
12 | try {
13 | local = Function('return this')();
14 | } catch (e) {
15 | throw new Error('polyfill failed because global object is unavailable in this environment');
16 | }
17 | }
18 |
19 | let P = local.Promise;
20 |
21 | if (P) {
22 | var promiseToString = null;
23 | try {
24 | promiseToString = Object.prototype.toString.call(P.resolve());
25 | } catch(e) {
26 | // silently ignored
27 | }
28 |
29 | if (promiseToString === '[object Promise]' && !P.cast){
30 | return;
31 | }
32 | }
33 |
34 | local.Promise = Promise;
35 | }
36 |
--------------------------------------------------------------------------------
/bin/publish_to_s3.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | // To invoke this from the commandline you need the following to env vars to exist:
4 | //
5 | // S3_BUCKET_NAME
6 | // TRAVIS_BRANCH
7 | // TRAVIS_TAG
8 | // TRAVIS_COMMIT
9 | // S3_SECRET_ACCESS_KEY
10 | // S3_ACCESS_KEY_ID
11 | //
12 | // Once you have those you execute with the following:
13 | //
14 | // ```sh
15 | // ./bin/publish_to_s3.js
16 | // ```
17 | var S3Publisher = require('ember-publisher');
18 | var configPath = require('path').join(__dirname, '../config/s3ProjectConfig.js');
19 | publisher = new S3Publisher({ projectConfigPath: configPath });
20 |
21 | // Always use wildcard section of project config.
22 | // This is useful when the including library does not
23 | // require channels (like in ember.js / ember-data).
24 | publisher.currentBranch = function() {
25 | return (process.env.TRAVIS_BRANCH === 'master') ? 'wildcard' : 'no-op';
26 | };
27 | publisher.publish();
28 |
29 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "ember",
3 |
4 | "parser": "babel-eslint",
5 |
6 | "ecmaFeatures": {
7 | modules: true,
8 | blockBindings: true,
9 | arrowFunctions: true,
10 | objectLiteralShorthandMethods: true,
11 | objectLiteralShorthandProperties: true,
12 | templateStrings: true
13 | },
14 |
15 | "rules": {
16 | "indent": [ 2, "tab", { "SwitchCase": 1 } ],
17 | "object-shorthand": [ 2, "always" ],
18 | "prefer-const": 0,
19 | "comma-dangle": 0,
20 | "spaced-comment": 1,
21 | "object-curly-spacing": [2, "always"],
22 | "arrow-spacing": [ 1, { before: true, after: true } ],
23 | "array-bracket-spacing": [ 2, "always" ],
24 | "no-restricted-syntax": 0,
25 | "no-warning-comments": [ 0, { "terms": [ "todo", "fixme", "xxx" ], "location": "start" } ],
26 | "no-ternary": 0,
27 | "no-nested-ternary": 2,
28 | "brace-style": [ 2, "stroustrup" ],
29 | "no-else-return": 0
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "predef": [
3 | "console",
4 | "require",
5 | "equal",
6 | "test",
7 | "testBoth",
8 | "testWithDefault",
9 | "raises",
10 | "deepEqual",
11 | "start",
12 | "stop",
13 | "ok",
14 | "strictEqual",
15 | "module",
16 | "expect"
17 | ],
18 |
19 | "esnext": true,
20 | "proto": true,
21 | "node" : true,
22 | "browser" : true,
23 |
24 | "boss" : true,
25 | "curly": false,
26 | "debug": false,
27 | "devel": false,
28 | "eqeqeq": true,
29 | "evil": true,
30 | "forin": false,
31 | "immed": false,
32 | "laxbreak": false,
33 | "newcap": true,
34 | "noarg": true,
35 | "noempty": false,
36 | "nonew": false,
37 | "nomen": false,
38 | "onevar": false,
39 | "plusplus": false,
40 | "regexp": false,
41 | "undef": true,
42 | "sub": true,
43 | "strict": false,
44 | "white": false,
45 | "eqnull": true
46 | }
47 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | this software and associated documentation files (the "Software"), to deal in
5 | the Software without restriction, including without limitation the rights to
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7 | of the Software, and to permit persons to whom the Software is furnished to do
8 | so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/lib/es6-promise/promise/resolve.js:
--------------------------------------------------------------------------------
1 | import {
2 | noop,
3 | resolve as _resolve
4 | } from '../-internal';
5 |
6 | /**
7 | `Promise.resolve` returns a promise that will become resolved with the
8 | passed `value`. It is shorthand for the following:
9 |
10 | ```javascript
11 | let promise = new Promise(function(resolve, reject){
12 | resolve(1);
13 | });
14 |
15 | promise.then(function(value){
16 | // value === 1
17 | });
18 | ```
19 |
20 | Instead of writing the above, your code now simply becomes the following:
21 |
22 | ```javascript
23 | let promise = Promise.resolve(1);
24 |
25 | promise.then(function(value){
26 | // value === 1
27 | });
28 | ```
29 |
30 | @method resolve
31 | @static
32 | @param {Any} value value that the returned promise will be resolved with
33 | Useful for tooling.
34 | @return {Promise} a promise that will become fulfilled with the given
35 | `value`
36 | */
37 | export default function resolve(object) {
38 | /*jshint validthis:true */
39 | let Constructor = this;
40 |
41 | if (object && typeof object === 'object' && object.constructor === Constructor) {
42 | return object;
43 | }
44 |
45 | let promise = new Constructor(noop);
46 | _resolve(promise, object);
47 | return promise;
48 | }
49 |
--------------------------------------------------------------------------------
/lib/es6-promise/promise/reject.js:
--------------------------------------------------------------------------------
1 | import {
2 | noop,
3 | reject as _reject
4 | } from '../-internal';
5 |
6 | /**
7 | `Promise.reject` returns a promise rejected with the passed `reason`.
8 | It is shorthand for the following:
9 |
10 | ```javascript
11 | let promise = new Promise(function(resolve, reject){
12 | reject(new Error('WHOOPS'));
13 | });
14 |
15 | promise.then(function(value){
16 | // Code here doesn't run because the promise is rejected!
17 | }, function(reason){
18 | // reason.message === 'WHOOPS'
19 | });
20 | ```
21 |
22 | Instead of writing the above, your code now simply becomes the following:
23 |
24 | ```javascript
25 | let promise = Promise.reject(new Error('WHOOPS'));
26 |
27 | promise.then(function(value){
28 | // Code here doesn't run because the promise is rejected!
29 | }, function(reason){
30 | // reason.message === 'WHOOPS'
31 | });
32 | ```
33 |
34 | @method reject
35 | @static
36 | @param {Any} reason value that the returned promise will be rejected with.
37 | Useful for tooling.
38 | @return {Promise} a promise rejected with the given `reason`.
39 | */
40 | export default function reject(reason) {
41 | /*jshint validthis:true */
42 | let Constructor = this;
43 | let promise = new Constructor(noop);
44 | _reject(promise, reason);
45 | return promise;
46 | }
47 |
--------------------------------------------------------------------------------
/vendor/loader.js:
--------------------------------------------------------------------------------
1 | var define, requireModule, require, requirejs;
2 |
3 | (function() {
4 | var registry = {}, seen = {};
5 |
6 | define = function(name, deps, callback) {
7 | registry[name] = { deps: deps, callback: callback };
8 | };
9 |
10 | requirejs = require = requireModule = function(name) {
11 | requirejs._eak_seen = registry;
12 |
13 | if (seen[name]) { return seen[name]; }
14 | seen[name] = {};
15 |
16 | if (!registry[name]) {
17 | throw new Error("Could not find module " + name);
18 | }
19 |
20 | var mod = registry[name],
21 | deps = mod.deps,
22 | callback = mod.callback,
23 | reified = [],
24 | exports;
25 |
26 | for (var i=0, l=deps.length; i 2 and the overriden scheduling mechanism would not
17 | // be used.
18 | // This is required because the test library uses Promise.
19 | setTimeout(function() {
20 | var microtasks = [];
21 | var resolvedWith = null;
22 |
23 | Promise._setScheduler(function(fn) {
24 | microtasks.push(fn);
25 | });
26 |
27 | Promise.resolve('value').then(function(v) {
28 | resolvedWith = v;
29 | });
30 |
31 | assert.equal(resolvedWith, null);
32 | assert.equal(microtasks.length, 1);
33 |
34 | while (microtasks.length) {
35 | microtasks.shift()();
36 | }
37 |
38 | assert.equal(resolvedWith, 'value');
39 |
40 | // restore the original scheduler
41 | Promise._setScheduler(void 0);
42 | done();
43 | });
44 | });
45 | });
46 |
47 | describe('Promise._asap', function() {
48 | it('should allow enqueuing microtasks', function(done) {
49 | Promise._asap(function(arg) {
50 | assert.equal(arg, 'arg');
51 | done();
52 | }, 'arg');
53 | });
54 | });
55 |
56 | describe('Promise._setAsap', function() {
57 | it('should allow overriding asap', function(done) {
58 | var called = false;
59 |
60 | Promise._setAsap(function(fn, arg) {
61 | called = true;
62 | // call the original implementation
63 | Promise._asap(fn, arg);
64 | // restore the original implementation
65 | Promise._setAsap(Promise._asap);
66 | });
67 |
68 | Promise.resolve('value').then(function(v) {
69 | resolvedWith = v;
70 | assert.equal(v, 'value');
71 | assert.equal(called, true);
72 | done();
73 | });
74 | });
75 | });
76 | });
77 |
--------------------------------------------------------------------------------
/lib/es6-promise/promise/race.js:
--------------------------------------------------------------------------------
1 | import {
2 | isArray
3 | } from "../utils";
4 |
5 | /**
6 | `Promise.race` returns a new promise which is settled in the same way as the
7 | first passed promise to settle.
8 |
9 | Example:
10 |
11 | ```javascript
12 | let promise1 = new Promise(function(resolve, reject){
13 | setTimeout(function(){
14 | resolve('promise 1');
15 | }, 200);
16 | });
17 |
18 | let promise2 = new Promise(function(resolve, reject){
19 | setTimeout(function(){
20 | resolve('promise 2');
21 | }, 100);
22 | });
23 |
24 | Promise.race([promise1, promise2]).then(function(result){
25 | // result === 'promise 2' because it was resolved before promise1
26 | // was resolved.
27 | });
28 | ```
29 |
30 | `Promise.race` is deterministic in that only the state of the first
31 | settled promise matters. For example, even if other promises given to the
32 | `promises` array argument are resolved, but the first settled promise has
33 | become rejected before the other promises became fulfilled, the returned
34 | promise will become rejected:
35 |
36 | ```javascript
37 | let promise1 = new Promise(function(resolve, reject){
38 | setTimeout(function(){
39 | resolve('promise 1');
40 | }, 200);
41 | });
42 |
43 | let promise2 = new Promise(function(resolve, reject){
44 | setTimeout(function(){
45 | reject(new Error('promise 2'));
46 | }, 100);
47 | });
48 |
49 | Promise.race([promise1, promise2]).then(function(result){
50 | // Code here never runs
51 | }, function(reason){
52 | // reason.message === 'promise 2' because promise 2 became rejected before
53 | // promise 1 became fulfilled
54 | });
55 | ```
56 |
57 | An example real-world use case is implementing timeouts:
58 |
59 | ```javascript
60 | Promise.race([ajax('foo.json'), timeout(5000)])
61 | ```
62 |
63 | @method race
64 | @static
65 | @param {Array} promises array of promises to observe
66 | Useful for tooling.
67 | @return {Promise} a promise which settles in the same way as the first passed
68 | promise to settle.
69 | */
70 | export default function race(entries) {
71 | /*jshint validthis:true */
72 | let Constructor = this;
73 |
74 | if (!isArray(entries)) {
75 | return new Constructor((_, reject) => reject(new TypeError('You must pass an array to race.')));
76 | } else {
77 | return new Constructor((resolve, reject) => {
78 | let length = entries.length;
79 | for (let i = 0; i < length; i++) {
80 | Constructor.resolve(entries[i]).then(resolve, reject);
81 | }
82 | });
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ES6-Promise (subset of [rsvp.js](https://github.com/tildeio/rsvp.js)) [](https://travis-ci.org/stefanpenner/es6-promise)
2 |
3 | This is a polyfill of the [ES6 Promise](http://people.mozilla.org/~jorendorff/es6-draft.html#sec-promise-constructor). The implementation is a subset of [rsvp.js](https://github.com/tildeio/rsvp.js) extracted by @jakearchibald, if you're wanting extra features and more debugging options, check out the [full library](https://github.com/tildeio/rsvp.js).
4 |
5 | For API details and how to use promises, see the JavaScript Promises HTML5Rocks article.
6 |
7 | ## Downloads
8 |
9 | * [es6-promise 27.86 KB (7.33 KB gzipped)](https://raw.githubusercontent.com/stefanpenner/es6-promise/master/dist/es6-promise.js)
10 | * [es6-promise-auto 27.78 KB (7.3 KB gzipped)](https://raw.githubusercontent.com/stefanpenner/es6-promise/master/dist/es6-promise.auto.js) - Automatically provides/replaces `Promise` if missing or broken.
11 | * [es6-promise-min 6.17 KB (2.4 KB gzipped)](https://raw.githubusercontent.com/stefanpenner/es6-promise/master/dist/es6-promise.min.js)
12 | * [es6-promise-auto-min 6.19 KB (2.4 KB gzipped)](https://raw.githubusercontent.com/stefanpenner/es6-promise/master/dist/es6-promise.auto.min.js) - Minified version of `es6-promise-auto` above.
13 |
14 | ## Node.js
15 |
16 | To install:
17 |
18 | ```sh
19 | npm install es6-promise
20 | ```
21 |
22 | To use:
23 |
24 | ```js
25 | var Promise = require('es6-promise').Promise;
26 | ```
27 |
28 | ## Bower
29 |
30 | To install:
31 |
32 | ```sh
33 | bower install es6-promise --save
34 | ```
35 |
36 |
37 | ## Usage in IE<9
38 |
39 | `catch` is a reserved word in IE<9, meaning `promise.catch(func)` throws a syntax error. To work around this, you can use a string to access the property as shown in the following example.
40 |
41 | However, please remember that such technique is already provided by most common minifiers, making the resulting code safe for old browsers and production:
42 |
43 | ```js
44 | promise['catch'](function(err) {
45 | // ...
46 | });
47 | ```
48 |
49 | Or use `.then` instead:
50 |
51 | ```js
52 | promise.then(undefined, function(err) {
53 | // ...
54 | });
55 | ```
56 |
57 | ## Auto-polyfill
58 |
59 | To polyfill the global environment (either in Node or in the browser via CommonJS) use the following code snippet:
60 |
61 | ```js
62 | require('es6-promise').polyfill();
63 | ```
64 |
65 | Alternatively
66 |
67 | ```js
68 | require('es6-promise/auto');
69 | ```
70 |
71 | Notice that we don't assign the result of `polyfill()` to any variable. The `polyfill()` method will patch the global environment (in this case to the `Promise` name) when called.
72 |
73 | ## Building & Testing
74 |
75 | You will need to have PhantomJS installed globally in order to run the tests.
76 |
77 | `npm install -g phantomjs`
78 |
79 | * `npm run build` to build
80 | * `npm test` to run tests
81 | * `npm start` to run a build watcher, and webserver to test
82 | * `npm run test:server` for a testem test runner and watching builder
83 |
--------------------------------------------------------------------------------
/Brocfile.js:
--------------------------------------------------------------------------------
1 | /* jshint node:true, undef:true, unused:true */
2 | var Rollup = require('broccoli-rollup');
3 | var Babel = require('broccoli-babel-transpiler');
4 | var merge = require('broccoli-merge-trees');
5 | var uglify = require('broccoli-uglify-js');
6 | var version = require('git-repo-version');
7 | var watchify = require('broccoli-watchify');
8 | var concat = require('broccoli-concat');
9 | var fs = require('fs');
10 |
11 | var stew = require('broccoli-stew');
12 |
13 | var find = stew.find;
14 | var mv = stew.mv;
15 | var rename = stew.rename;
16 | var env = stew.env;
17 | var map = stew.map;
18 |
19 | var lib = find('lib');
20 |
21 | // test stuff
22 | var testDir = find('test');
23 | var testFiles = find('test/{index.html,worker.js}');
24 |
25 | var json3 = mv(find('node_modules/json3/lib/{json3.js}'), 'node_modules/json3/lib/', 'test/');
26 | // mocha doesn't browserify correctly
27 | var mocha = mv(find('node_modules/mocha/mocha.{js,css}'), 'node_modules/mocha/', 'test/');
28 |
29 | var testVendor = merge([ json3, mocha ]);
30 |
31 |
32 | var es5 = new Babel(lib, {
33 | blacklist: ['es6.modules']
34 | });
35 |
36 | function rollupConfig(entry) {
37 | return new Rollup(es5, {
38 | rollup: {
39 | entry: 'lib/' + entry,
40 | targets: [
41 | {
42 | format: 'umd',
43 | moduleName: 'ES6Promise',
44 | dest: entry,
45 | sourceMap: 'inline'
46 | }
47 | ]
48 | }
49 | });
50 | }
51 |
52 | // build RSVP itself
53 | var es6Promise = rollupConfig('es6-promise.js')
54 | var es6PromiseAuto = rollupConfig('es6-promise.auto.js')
55 |
56 | var testBundle = watchify(merge([
57 | mv(es6Promise, 'test'),
58 | testDir
59 | ]), {
60 | browserify: { debug: true, entries: ['./test/index.js'] }
61 | });
62 |
63 | var header = stew.map(find('config/versionTemplate.txt'), function(content) {
64 | return content.replace(/VERSION_PLACEHOLDER_STRING/, version());
65 | });
66 |
67 | function concatAs(outputFile) {
68 | return merge([
69 | concat(merge([es6Promise, header]), {
70 | headerFiles: ['config/versionTemplate.txt'],
71 | inputFiles: ['es6-promise.js'],
72 | outputFile: outputFile
73 | }),
74 |
75 | concat(merge([es6PromiseAuto, header]), {
76 | headerFiles: ['config/versionTemplate.txt'],
77 | inputFiles: ['es6-promise.auto.js'],
78 | outputFile: outputFile.replace('es6-promise', 'es6-promise.auto'),
79 | }),
80 |
81 | ]);
82 | }
83 |
84 | function production() {
85 | var result;
86 | env('production', function(){
87 | result = uglify(concatAs('es6-promise.min.js'), {
88 | compress: true,
89 | mangle: true,
90 | });
91 | })
92 | return result;
93 | }
94 |
95 | function development() {
96 | return concatAs('es6-promise.js');
97 | }
98 |
99 | module.exports = merge([
100 | merge([
101 | production(),
102 | development(),
103 | ].filter(Boolean)),
104 | // test stuff
105 | testFiles,
106 | testVendor,
107 | mv(testBundle, 'test')
108 | ]);
109 |
--------------------------------------------------------------------------------
/lib/es6-promise/enumerator.js:
--------------------------------------------------------------------------------
1 | import {
2 | isArray,
3 | isMaybeThenable
4 | } from './utils';
5 |
6 | import {
7 | noop,
8 | reject,
9 | fulfill,
10 | subscribe,
11 | FULFILLED,
12 | REJECTED,
13 | PENDING,
14 | getThen,
15 | handleMaybeThenable
16 | } from './-internal';
17 |
18 | import then from './then';
19 | import Promise from './promise';
20 | import originalResolve from './promise/resolve';
21 | import originalThen from './then';
22 | import { makePromise, PROMISE_ID } from './-internal';
23 |
24 | export default Enumerator;
25 | function Enumerator(Constructor, input) {
26 | this._instanceConstructor = Constructor;
27 | this.promise = new Constructor(noop);
28 |
29 | if (!this.promise[PROMISE_ID]) {
30 | makePromise(this.promise);
31 | }
32 |
33 | if (isArray(input)) {
34 | this._input = input;
35 | this.length = input.length;
36 | this._remaining = input.length;
37 |
38 | this._result = new Array(this.length);
39 |
40 | if (this.length === 0) {
41 | fulfill(this.promise, this._result);
42 | } else {
43 | this.length = this.length || 0;
44 | this._enumerate();
45 | if (this._remaining === 0) {
46 | fulfill(this.promise, this._result);
47 | }
48 | }
49 | } else {
50 | reject(this.promise, validationError());
51 | }
52 | }
53 |
54 | function validationError() {
55 | return new Error('Array Methods must be provided an Array');
56 | };
57 |
58 | Enumerator.prototype._enumerate = function() {
59 | let { length, _input } = this;
60 |
61 | for (let i = 0; this._state === PENDING && i < length; i++) {
62 | this._eachEntry(_input[i], i);
63 | }
64 | };
65 |
66 | Enumerator.prototype._eachEntry = function(entry, i) {
67 | let c = this._instanceConstructor;
68 | let { resolve } = c;
69 |
70 | if (resolve === originalResolve) {
71 | let then = getThen(entry);
72 |
73 | if (then === originalThen &&
74 | entry._state !== PENDING) {
75 | this._settledAt(entry._state, i, entry._result);
76 | } else if (typeof then !== 'function') {
77 | this._remaining--;
78 | this._result[i] = entry;
79 | } else if (c === Promise) {
80 | let promise = new c(noop);
81 | handleMaybeThenable(promise, entry, then);
82 | this._willSettleAt(promise, i);
83 | } else {
84 | this._willSettleAt(new c(resolve => resolve(entry)), i);
85 | }
86 | } else {
87 | this._willSettleAt(resolve(entry), i);
88 | }
89 | };
90 |
91 | Enumerator.prototype._settledAt = function(state, i, value) {
92 | let { promise } = this;
93 |
94 | if (promise._state === PENDING) {
95 | this._remaining--;
96 |
97 | if (state === REJECTED) {
98 | reject(promise, value);
99 | } else {
100 | this._result[i] = value;
101 | }
102 | }
103 |
104 | if (this._remaining === 0) {
105 | fulfill(promise, this._result);
106 | }
107 | };
108 |
109 | Enumerator.prototype._willSettleAt = function(promise, i) {
110 | let enumerator = this;
111 |
112 | subscribe(promise, undefined, value => enumerator._settledAt(FULFILLED, i, value),
113 | reason => enumerator._settledAt(REJECTED, i, reason));
114 | };
115 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Master
2 |
3 | # 4.1.0
4 |
5 | * [BUGFIX] Fix memory leak [#269]
6 | * [BUGFIX] Auto Bundles within an AMD Environment [#263]
7 |
8 | # 4.0.5
9 |
10 | * fix require('es6-promise/auto') for Node < 4
11 |
12 | # 4.0.4
13 |
14 | * fix asap when using https://github.com/Kinvey/titanium-sdk
15 |
16 | # 4.0.3
17 |
18 | * fix Readme links
19 |
20 | # 4.0.2
21 |
22 | * fix require('es6-promise/auto');
23 |
24 | # 4.0.0
25 |
26 | * no longer polyfill automatically, if needed one can still invoke
27 | `require('es6-promise/auto')` directly.
28 |
29 | # 3.3.1
30 |
31 | * fix links in readme
32 |
33 | # 3.3.0
34 |
35 | * support polyfil on WebMAF (playstation env)
36 | * fix tampering related bug global `constructor` was referenced by mistake.
37 | * provide TS Typings
38 | * increase compatibliity with sinon.useFakeTimers();
39 | * update build tools (use rollup)
40 | * directly export promise;
41 |
42 | # 3.2.2
43 |
44 | * IE8: use isArray
45 | * update build dependencies
46 |
47 | # 3.2.1
48 |
49 | * fix race tampering issue
50 | * use eslint
51 | * fix Promise.all tampering
52 | * remove unused code
53 | * fix issues with NWJS/electron
54 |
55 | # 3.2.0
56 |
57 | * improve tamper resistence of Promise.all Promise.race and
58 | Promise.prototype.then (note, this isn't complete, but addresses an exception
59 | when used \w core-js, follow up work will address entirely)
60 | * remove spec incompatible then chaining fast-path
61 | * add eslint
62 | * update build deps
63 |
64 | # 3.1.2
65 |
66 | * fix node detection issues with NWJS/electron
67 |
68 | # 3.1.0
69 |
70 | * improve performance of Promise.all when it encounters a non-promise input object input
71 | * then/resolve tamper protection
72 | * reduce AST size of promise constructor, to facilitate more inlining
73 | * Update README.md with details about PhantomJS requirement for running tests
74 | * Mangle and compress the minified version
75 |
76 | # 3.0.2
77 |
78 | * correctly bump both bower and package.json versions
79 |
80 | # 3.0.1
81 |
82 | * no longer include dist/test in npm releases
83 |
84 | # 3.0.0
85 |
86 | * use nextTick() instead of setImmediate() to schedule microtasks with node 0.10. Later versions of
87 | nodes are not affected as they were already using nextTick(). Note that using nextTick() might
88 | trigger a depreciation warning on 0.10 as described at https://github.com/cujojs/when/issues/410.
89 | The reason why nextTick() is preferred is that is setImmediate() would schedule a macrotask
90 | instead of a microtask and might result in a different scheduling.
91 | If needed you can revert to the former behavior as follow:
92 |
93 | var Promise = require('es6-promise').Promise;
94 | Promise._setScheduler(setImmediate);
95 |
96 | # 2.3.0
97 |
98 | * #121: Ability to override the internal asap implementation
99 | * #120: Use an ascii character for an apostrophe, for source maps
100 |
101 | # 2.2.0
102 |
103 | * #116: Expose asap() and a way to override the scheduling mechanism on Promise
104 | * Lock to v0.2.3 of ember-cli
105 |
106 | # 2.1.1
107 |
108 | * Fix #100 via #105: tell browserify to ignore vertx require
109 | * Fix #101 via #102: "follow thenable state, not own state"
110 |
111 | # 2.1.0
112 |
113 | * #59: Automatic polyfill. No need to invoke `ES6Promise.polyfill()` anymore.
114 | * ... (see the commit log)
115 |
116 | # 2.0.0
117 |
118 | * re-sync with RSVP. Many large performance improvements and bugfixes.
119 |
120 | # 1.0.0
121 |
122 | * first subset of RSVP
123 |
--------------------------------------------------------------------------------
/lib/es6-promise/asap.js:
--------------------------------------------------------------------------------
1 | let len = 0;
2 | let vertxNext;
3 | let customSchedulerFn;
4 |
5 | export var asap = function asap(callback, arg) {
6 | queue[len] = callback;
7 | queue[len + 1] = arg;
8 | len += 2;
9 | if (len === 2) {
10 | // If len is 2, that means that we need to schedule an async flush.
11 | // If additional callbacks are queued before the queue is flushed, they
12 | // will be processed by this flush that we are scheduling.
13 | if (customSchedulerFn) {
14 | customSchedulerFn(flush);
15 | } else {
16 | scheduleFlush();
17 | }
18 | }
19 | }
20 |
21 | export function setScheduler(scheduleFn) {
22 | customSchedulerFn = scheduleFn;
23 | }
24 |
25 | export function setAsap(asapFn) {
26 | asap = asapFn;
27 | }
28 |
29 | const browserWindow = (typeof window !== 'undefined') ? window : undefined;
30 | const browserGlobal = browserWindow || {};
31 | const BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
32 | const isNode = typeof self === 'undefined' && typeof process !== 'undefined' && {}.toString.call(process) === '[object process]';
33 |
34 | // test for web worker but not in IE10
35 | const isWorker = typeof Uint8ClampedArray !== 'undefined' &&
36 | typeof importScripts !== 'undefined' &&
37 | typeof MessageChannel !== 'undefined';
38 |
39 | // node
40 | function useNextTick() {
41 | // node version 0.10.x displays a deprecation warning when nextTick is used recursively
42 | // see https://github.com/cujojs/when/issues/410 for details
43 | return () => process.nextTick(flush);
44 | }
45 |
46 | // vertx
47 | function useVertxTimer() {
48 | if (typeof vertxNext !== 'undefined') {
49 | return function() {
50 | vertxNext(flush);
51 | };
52 | }
53 |
54 | return useSetTimeout();
55 | }
56 |
57 | function useMutationObserver() {
58 | let iterations = 0;
59 | const observer = new BrowserMutationObserver(flush);
60 | const node = document.createTextNode('');
61 | observer.observe(node, { characterData: true });
62 |
63 | return () => {
64 | node.data = (iterations = ++iterations % 2);
65 | };
66 | }
67 |
68 | // web worker
69 | function useMessageChannel() {
70 | const channel = new MessageChannel();
71 | channel.port1.onmessage = flush;
72 | return () => channel.port2.postMessage(0);
73 | }
74 |
75 | function useSetTimeout() {
76 | // Store setTimeout reference so es6-promise will be unaffected by
77 | // other code modifying setTimeout (like sinon.useFakeTimers())
78 | const globalSetTimeout = setTimeout;
79 | return () => globalSetTimeout(flush, 1);
80 | }
81 |
82 | const queue = new Array(1000);
83 | function flush() {
84 | for (let i = 0; i < len; i+=2) {
85 | let callback = queue[i];
86 | let arg = queue[i+1];
87 |
88 | callback(arg);
89 |
90 | queue[i] = undefined;
91 | queue[i+1] = undefined;
92 | }
93 |
94 | len = 0;
95 | }
96 |
97 | function attemptVertx() {
98 | try {
99 | const r = require;
100 | const vertx = r('vertx');
101 | vertxNext = vertx.runOnLoop || vertx.runOnContext;
102 | return useVertxTimer();
103 | } catch(e) {
104 | return useSetTimeout();
105 | }
106 | }
107 |
108 | let scheduleFlush;
109 | // Decide what async method to use to triggering processing of queued callbacks:
110 | if (isNode) {
111 | scheduleFlush = useNextTick();
112 | } else if (BrowserMutationObserver) {
113 | scheduleFlush = useMutationObserver();
114 | } else if (isWorker) {
115 | scheduleFlush = useMessageChannel();
116 | } else if (browserWindow === undefined && typeof require === 'function') {
117 | scheduleFlush = attemptVertx();
118 | } else {
119 | scheduleFlush = useSetTimeout();
120 | }
121 |
--------------------------------------------------------------------------------
/es6-promise.d.ts:
--------------------------------------------------------------------------------
1 | export interface Thenable {
2 | then (onFulfilled?: (value: R) => U | Thenable, onRejected?: (error: any) => U | Thenable): Thenable;
3 | then (onFulfilled?: (value: R) => U | Thenable, onRejected?: (error: any) => void): Thenable;
4 | }
5 |
6 | export class Promise implements Thenable {
7 | /**
8 | * If you call resolve in the body of the callback passed to the constructor,
9 | * your promise is fulfilled with result object passed to resolve.
10 | * If you call reject your promise is rejected with the object passed to resolve.
11 | * For consistency and debugging (eg stack traces), obj should be an instanceof Error.
12 | * Any errors thrown in the constructor callback will be implicitly passed to reject().
13 | */
14 | constructor (callback: (resolve : (value?: R | Thenable) => void, reject: (error?: any) => void) => void);
15 |
16 | /**
17 | * onFulfilled is called when/if "promise" resolves. onRejected is called when/if "promise" rejects.
18 | * Both are optional, if either/both are omitted the next onFulfilled/onRejected in the chain is called.
19 | * Both callbacks have a single parameter , the fulfillment value or rejection reason.
20 | * "then" returns a new promise equivalent to the value you return from onFulfilled/onRejected after being passed through Promise.resolve.
21 | * If an error is thrown in the callback, the returned promise rejects with that error.
22 | *
23 | * @param onFulfilled called when/if "promise" resolves
24 | * @param onRejected called when/if "promise" rejects
25 | */
26 | then (onFulfilled?: (value: R) => U | Thenable, onRejected?: (error: any) => U | Thenable): Promise;
27 | then (onFulfilled?: (value: R) => U | Thenable, onRejected?: (error: any) => void): Promise;
28 |
29 | /**
30 | * Sugar for promise.then(undefined, onRejected)
31 | *
32 | * @param onRejected called when/if "promise" rejects
33 | */
34 | catch (onRejected?: (error: any) => U | Thenable): Promise;
35 |
36 | /**
37 | * Make a new promise from the thenable.
38 | * A thenable is promise-like in as far as it has a "then" method.
39 | */
40 | static resolve (): Promise;
41 | static resolve (value: R | Thenable): Promise;
42 |
43 | /**
44 | * Make a promise that rejects to obj. For consistency and debugging (eg stack traces), obj should be an instanceof Error
45 | */
46 | static reject (error: any): Promise;
47 |
48 | /**
49 | * Make a promise that fulfills when every item in the array fulfills, and rejects if (and when) any item rejects.
50 | * the array passed to all can be a mixture of promise-like objects and other objects.
51 | * The fulfillment value is an array (in order) of fulfillment values. The rejection value is the first rejection value.
52 | */
53 | static all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable , T5 | Thenable, T6 | Thenable, T7 | Thenable, T8 | Thenable, T9 | Thenable, T10 | Thenable]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>;
54 | static all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable , T5 | Thenable, T6 | Thenable, T7 | Thenable, T8 | Thenable, T9 | Thenable]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>;
55 | static all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable , T5 | Thenable, T6 | Thenable, T7 | Thenable, T8 | Thenable]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8]>;
56 | static all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable , T5 | Thenable, T6 | Thenable, T7 | Thenable]): Promise<[T1, T2, T3, T4, T5, T6, T7]>;
57 | static all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable , T5 | Thenable, T6 | Thenable]): Promise<[T1, T2, T3, T4, T5, T6]>;
58 | static all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable , T5 | Thenable]): Promise<[T1, T2, T3, T4, T5]>;
59 | static all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable ]): Promise<[T1, T2, T3, T4]>;
60 | static all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable]): Promise<[T1, T2, T3]>;
61 | static all(values: [T1 | Thenable, T2 | Thenable]): Promise<[T1, T2]>;
62 | static all(values: [T1 | Thenable]): Promise<[T1]>;
63 | static all(values: Array>): Promise;
64 |
65 | /**
66 | * Make a Promise that fulfills when any item fulfills, and rejects if any item rejects.
67 | */
68 | static race (promises: (R | Thenable)[]): Promise;
69 | }
70 |
71 | /**
72 | * The polyfill method will patch the global environment (in this case to the Promise name) when called.
73 | */
74 | export function polyfill (): void;
75 |
--------------------------------------------------------------------------------
/dist/es6-promise.min.js:
--------------------------------------------------------------------------------
1 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.ES6Promise=e()}(this,function(){"use strict";function t(t){return"function"==typeof t||"object"==typeof t&&null!==t}function e(t){return"function"==typeof t}function n(t){I=t}function r(t){J=t}function o(){return function(){return process.nextTick(a)}}function i(){return"undefined"!=typeof H?function(){H(a)}:c()}function s(){var t=0,e=new V(a),n=document.createTextNode("");return e.observe(n,{characterData:!0}),function(){n.data=t=++t%2}}function u(){var t=new MessageChannel;return t.port1.onmessage=a,function(){return t.port2.postMessage(0)}}function c(){var t=setTimeout;return function(){return t(a,1)}}function a(){for(var t=0;t {
50 | var sealed = false;
51 | var error = tryThen(then, thenable, value => {
52 | if (sealed) { return; }
53 | sealed = true;
54 | if (thenable !== value) {
55 | resolve(promise, value);
56 | } else {
57 | fulfill(promise, value);
58 | }
59 | }, reason => {
60 | if (sealed) { return; }
61 | sealed = true;
62 |
63 | reject(promise, reason);
64 | }, 'Settle: ' + (promise._label || ' unknown promise'));
65 |
66 | if (!sealed && error) {
67 | sealed = true;
68 | reject(promise, error);
69 | }
70 | }, promise);
71 | }
72 |
73 | function handleOwnThenable(promise, thenable) {
74 | if (thenable._state === FULFILLED) {
75 | fulfill(promise, thenable._result);
76 | } else if (thenable._state === REJECTED) {
77 | reject(promise, thenable._result);
78 | } else {
79 | subscribe(thenable, undefined, value => resolve(promise, value),
80 | reason => reject(promise, reason))
81 | }
82 | }
83 |
84 | function handleMaybeThenable(promise, maybeThenable, then) {
85 | if (maybeThenable.constructor === promise.constructor &&
86 | then === originalThen &&
87 | maybeThenable.constructor.resolve === originalResolve) {
88 | handleOwnThenable(promise, maybeThenable);
89 | } else {
90 | if (then === GET_THEN_ERROR) {
91 | reject(promise, GET_THEN_ERROR.error);
92 | GET_THEN_ERROR.error = null;
93 | } else if (then === undefined) {
94 | fulfill(promise, maybeThenable);
95 | } else if (isFunction(then)) {
96 | handleForeignThenable(promise, maybeThenable, then);
97 | } else {
98 | fulfill(promise, maybeThenable);
99 | }
100 | }
101 | }
102 |
103 | function resolve(promise, value) {
104 | if (promise === value) {
105 | reject(promise, selfFulfillment());
106 | } else if (objectOrFunction(value)) {
107 | handleMaybeThenable(promise, value, getThen(value));
108 | } else {
109 | fulfill(promise, value);
110 | }
111 | }
112 |
113 | function publishRejection(promise) {
114 | if (promise._onerror) {
115 | promise._onerror(promise._result);
116 | }
117 |
118 | publish(promise);
119 | }
120 |
121 | function fulfill(promise, value) {
122 | if (promise._state !== PENDING) { return; }
123 |
124 | promise._result = value;
125 | promise._state = FULFILLED;
126 |
127 | if (promise._subscribers.length !== 0) {
128 | asap(publish, promise);
129 | }
130 | }
131 |
132 | function reject(promise, reason) {
133 | if (promise._state !== PENDING) { return; }
134 | promise._state = REJECTED;
135 | promise._result = reason;
136 |
137 | asap(publishRejection, promise);
138 | }
139 |
140 | function subscribe(parent, child, onFulfillment, onRejection) {
141 | let { _subscribers } = parent;
142 | let { length } = _subscribers;
143 |
144 | parent._onerror = null;
145 |
146 | _subscribers[length] = child;
147 | _subscribers[length + FULFILLED] = onFulfillment;
148 | _subscribers[length + REJECTED] = onRejection;
149 |
150 | if (length === 0 && parent._state) {
151 | asap(publish, parent);
152 | }
153 | }
154 |
155 | function publish(promise) {
156 | let subscribers = promise._subscribers;
157 | let settled = promise._state;
158 |
159 | if (subscribers.length === 0) { return; }
160 |
161 | let child, callback, detail = promise._result;
162 |
163 | for (let i = 0; i < subscribers.length; i += 3) {
164 | child = subscribers[i];
165 | callback = subscribers[i + settled];
166 |
167 | if (child) {
168 | invokeCallback(settled, child, callback, detail);
169 | } else {
170 | callback(detail);
171 | }
172 | }
173 |
174 | promise._subscribers.length = 0;
175 | }
176 |
177 | function ErrorObject() {
178 | this.error = null;
179 | }
180 |
181 | const TRY_CATCH_ERROR = new ErrorObject();
182 |
183 | function tryCatch(callback, detail) {
184 | try {
185 | return callback(detail);
186 | } catch(e) {
187 | TRY_CATCH_ERROR.error = e;
188 | return TRY_CATCH_ERROR;
189 | }
190 | }
191 |
192 | function invokeCallback(settled, promise, callback, detail) {
193 | let hasCallback = isFunction(callback),
194 | value, error, succeeded, failed;
195 |
196 | if (hasCallback) {
197 | value = tryCatch(callback, detail);
198 |
199 | if (value === TRY_CATCH_ERROR) {
200 | failed = true;
201 | error = value.error;
202 | value.error = null;
203 | } else {
204 | succeeded = true;
205 | }
206 |
207 | if (promise === value) {
208 | reject(promise, cannotReturnOwn());
209 | return;
210 | }
211 |
212 | } else {
213 | value = detail;
214 | succeeded = true;
215 | }
216 |
217 | if (promise._state !== PENDING) {
218 | // noop
219 | } else if (hasCallback && succeeded) {
220 | resolve(promise, value);
221 | } else if (failed) {
222 | reject(promise, error);
223 | } else if (settled === FULFILLED) {
224 | fulfill(promise, value);
225 | } else if (settled === REJECTED) {
226 | reject(promise, value);
227 | }
228 | }
229 |
230 | function initializePromise(promise, resolver) {
231 | try {
232 | resolver(function resolvePromise(value){
233 | resolve(promise, value);
234 | }, function rejectPromise(reason) {
235 | reject(promise, reason);
236 | });
237 | } catch(e) {
238 | reject(promise, e);
239 | }
240 | }
241 |
242 | let id = 0;
243 | function nextId() {
244 | return id++;
245 | }
246 |
247 | function makePromise(promise) {
248 | promise[PROMISE_ID] = id++;
249 | promise._state = undefined;
250 | promise._result = undefined;
251 | promise._subscribers = [];
252 | }
253 |
254 | export {
255 | nextId,
256 | makePromise,
257 | getThen,
258 | noop,
259 | resolve,
260 | reject,
261 | fulfill,
262 | subscribe,
263 | publish,
264 | publishRejection,
265 | initializePromise,
266 | invokeCallback,
267 | FULFILLED,
268 | REJECTED,
269 | PENDING,
270 | handleMaybeThenable
271 | };
272 |
--------------------------------------------------------------------------------
/lib/es6-promise/promise.js:
--------------------------------------------------------------------------------
1 | import {
2 | isFunction
3 | } from './utils';
4 |
5 | import {
6 | noop,
7 | nextId,
8 | PROMISE_ID,
9 | initializePromise
10 | } from './-internal';
11 |
12 | import {
13 | asap,
14 | setAsap,
15 | setScheduler
16 | } from './asap';
17 |
18 | import all from './promise/all';
19 | import race from './promise/race';
20 | import Resolve from './promise/resolve';
21 | import Reject from './promise/reject';
22 | import then from './then';
23 |
24 |
25 | function needsResolver() {
26 | throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
27 | }
28 |
29 | function needsNew() {
30 | throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
31 | }
32 |
33 | /**
34 | Promise objects represent the eventual result of an asynchronous operation. The
35 | primary way of interacting with a promise is through its `then` method, which
36 | registers callbacks to receive either a promise's eventual value or the reason
37 | why the promise cannot be fulfilled.
38 |
39 | Terminology
40 | -----------
41 |
42 | - `promise` is an object or function with a `then` method whose behavior conforms to this specification.
43 | - `thenable` is an object or function that defines a `then` method.
44 | - `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
45 | - `exception` is a value that is thrown using the throw statement.
46 | - `reason` is a value that indicates why a promise was rejected.
47 | - `settled` the final resting state of a promise, fulfilled or rejected.
48 |
49 | A promise can be in one of three states: pending, fulfilled, or rejected.
50 |
51 | Promises that are fulfilled have a fulfillment value and are in the fulfilled
52 | state. Promises that are rejected have a rejection reason and are in the
53 | rejected state. A fulfillment value is never a thenable.
54 |
55 | Promises can also be said to *resolve* a value. If this value is also a
56 | promise, then the original promise's settled state will match the value's
57 | settled state. So a promise that *resolves* a promise that rejects will
58 | itself reject, and a promise that *resolves* a promise that fulfills will
59 | itself fulfill.
60 |
61 |
62 | Basic Usage:
63 | ------------
64 |
65 | ```js
66 | let promise = new Promise(function(resolve, reject) {
67 | // on success
68 | resolve(value);
69 |
70 | // on failure
71 | reject(reason);
72 | });
73 |
74 | promise.then(function(value) {
75 | // on fulfillment
76 | }, function(reason) {
77 | // on rejection
78 | });
79 | ```
80 |
81 | Advanced Usage:
82 | ---------------
83 |
84 | Promises shine when abstracting away asynchronous interactions such as
85 | `XMLHttpRequest`s.
86 |
87 | ```js
88 | function getJSON(url) {
89 | return new Promise(function(resolve, reject){
90 | let xhr = new XMLHttpRequest();
91 |
92 | xhr.open('GET', url);
93 | xhr.onreadystatechange = handler;
94 | xhr.responseType = 'json';
95 | xhr.setRequestHeader('Accept', 'application/json');
96 | xhr.send();
97 |
98 | function handler() {
99 | if (this.readyState === this.DONE) {
100 | if (this.status === 200) {
101 | resolve(this.response);
102 | } else {
103 | reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
104 | }
105 | }
106 | };
107 | });
108 | }
109 |
110 | getJSON('/posts.json').then(function(json) {
111 | // on fulfillment
112 | }, function(reason) {
113 | // on rejection
114 | });
115 | ```
116 |
117 | Unlike callbacks, promises are great composable primitives.
118 |
119 | ```js
120 | Promise.all([
121 | getJSON('/posts'),
122 | getJSON('/comments')
123 | ]).then(function(values){
124 | values[0] // => postsJSON
125 | values[1] // => commentsJSON
126 |
127 | return values;
128 | });
129 | ```
130 |
131 | @class Promise
132 | @param {function} resolver
133 | Useful for tooling.
134 | @constructor
135 | */
136 | export default function Promise(resolver) {
137 | this[PROMISE_ID] = nextId();
138 | this._result = this._state = undefined;
139 | this._subscribers = [];
140 |
141 | if (noop !== resolver) {
142 | typeof resolver !== 'function' && needsResolver();
143 | this instanceof Promise ? initializePromise(this, resolver) : needsNew();
144 | }
145 | }
146 |
147 | Promise.all = all;
148 | Promise.race = race;
149 | Promise.resolve = Resolve;
150 | Promise.reject = Reject;
151 | Promise._setScheduler = setScheduler;
152 | Promise._setAsap = setAsap;
153 | Promise._asap = asap;
154 |
155 | Promise.prototype = {
156 | constructor: Promise,
157 |
158 | /**
159 | The primary way of interacting with a promise is through its `then` method,
160 | which registers callbacks to receive either a promise's eventual value or the
161 | reason why the promise cannot be fulfilled.
162 |
163 | ```js
164 | findUser().then(function(user){
165 | // user is available
166 | }, function(reason){
167 | // user is unavailable, and you are given the reason why
168 | });
169 | ```
170 |
171 | Chaining
172 | --------
173 |
174 | The return value of `then` is itself a promise. This second, 'downstream'
175 | promise is resolved with the return value of the first promise's fulfillment
176 | or rejection handler, or rejected if the handler throws an exception.
177 |
178 | ```js
179 | findUser().then(function (user) {
180 | return user.name;
181 | }, function (reason) {
182 | return 'default name';
183 | }).then(function (userName) {
184 | // If `findUser` fulfilled, `userName` will be the user's name, otherwise it
185 | // will be `'default name'`
186 | });
187 |
188 | findUser().then(function (user) {
189 | throw new Error('Found user, but still unhappy');
190 | }, function (reason) {
191 | throw new Error('`findUser` rejected and we're unhappy');
192 | }).then(function (value) {
193 | // never reached
194 | }, function (reason) {
195 | // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
196 | // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
197 | });
198 | ```
199 | If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
200 |
201 | ```js
202 | findUser().then(function (user) {
203 | throw new PedagogicalException('Upstream error');
204 | }).then(function (value) {
205 | // never reached
206 | }).then(function (value) {
207 | // never reached
208 | }, function (reason) {
209 | // The `PedgagocialException` is propagated all the way down to here
210 | });
211 | ```
212 |
213 | Assimilation
214 | ------------
215 |
216 | Sometimes the value you want to propagate to a downstream promise can only be
217 | retrieved asynchronously. This can be achieved by returning a promise in the
218 | fulfillment or rejection handler. The downstream promise will then be pending
219 | until the returned promise is settled. This is called *assimilation*.
220 |
221 | ```js
222 | findUser().then(function (user) {
223 | return findCommentsByAuthor(user);
224 | }).then(function (comments) {
225 | // The user's comments are now available
226 | });
227 | ```
228 |
229 | If the assimliated promise rejects, then the downstream promise will also reject.
230 |
231 | ```js
232 | findUser().then(function (user) {
233 | return findCommentsByAuthor(user);
234 | }).then(function (comments) {
235 | // If `findCommentsByAuthor` fulfills, we'll have the value here
236 | }, function (reason) {
237 | // If `findCommentsByAuthor` rejects, we'll have the reason here
238 | });
239 | ```
240 |
241 | Simple Example
242 | --------------
243 |
244 | Synchronous Example
245 |
246 | ```javascript
247 | let result;
248 |
249 | try {
250 | result = findResult();
251 | // success
252 | } catch(reason) {
253 | // failure
254 | }
255 | ```
256 |
257 | Errback Example
258 |
259 | ```js
260 | findResult(function(result, err){
261 | if (err) {
262 | // failure
263 | } else {
264 | // success
265 | }
266 | });
267 | ```
268 |
269 | Promise Example;
270 |
271 | ```javascript
272 | findResult().then(function(result){
273 | // success
274 | }, function(reason){
275 | // failure
276 | });
277 | ```
278 |
279 | Advanced Example
280 | --------------
281 |
282 | Synchronous Example
283 |
284 | ```javascript
285 | let author, books;
286 |
287 | try {
288 | author = findAuthor();
289 | books = findBooksByAuthor(author);
290 | // success
291 | } catch(reason) {
292 | // failure
293 | }
294 | ```
295 |
296 | Errback Example
297 |
298 | ```js
299 |
300 | function foundBooks(books) {
301 |
302 | }
303 |
304 | function failure(reason) {
305 |
306 | }
307 |
308 | findAuthor(function(author, err){
309 | if (err) {
310 | failure(err);
311 | // failure
312 | } else {
313 | try {
314 | findBoooksByAuthor(author, function(books, err) {
315 | if (err) {
316 | failure(err);
317 | } else {
318 | try {
319 | foundBooks(books);
320 | } catch(reason) {
321 | failure(reason);
322 | }
323 | }
324 | });
325 | } catch(error) {
326 | failure(err);
327 | }
328 | // success
329 | }
330 | });
331 | ```
332 |
333 | Promise Example;
334 |
335 | ```javascript
336 | findAuthor().
337 | then(findBooksByAuthor).
338 | then(function(books){
339 | // found books
340 | }).catch(function(reason){
341 | // something went wrong
342 | });
343 | ```
344 |
345 | @method then
346 | @param {Function} onFulfilled
347 | @param {Function} onRejected
348 | Useful for tooling.
349 | @return {Promise}
350 | */
351 | then: then,
352 |
353 | /**
354 | `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
355 | as the catch block of a try/catch statement.
356 |
357 | ```js
358 | function findAuthor(){
359 | throw new Error('couldn't find that author');
360 | }
361 |
362 | // synchronous
363 | try {
364 | findAuthor();
365 | } catch(reason) {
366 | // something went wrong
367 | }
368 |
369 | // async with promises
370 | findAuthor().catch(function(reason){
371 | // something went wrong
372 | });
373 | ```
374 |
375 | @method catch
376 | @param {Function} onRejection
377 | Useful for tooling.
378 | @return {Promise}
379 | */
380 | catch(onRejection) {
381 | return this.then(null, onRejection);
382 | }
383 | };
384 |
--------------------------------------------------------------------------------
/dist/es6-promise.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * @overview es6-promise - a tiny implementation of Promises/A+.
3 | * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
4 | * @license Licensed under MIT license
5 | * See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE
6 | * @version 4.1.0+f9a5575b
7 | */
8 |
9 | (function (global, factory) {
10 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
11 | typeof define === 'function' && define.amd ? define(factory) :
12 | (global.ES6Promise = factory());
13 | }(this, (function () { 'use strict';
14 |
15 | function objectOrFunction(x) {
16 | return typeof x === 'function' || typeof x === 'object' && x !== null;
17 | }
18 |
19 | function isFunction(x) {
20 | return typeof x === 'function';
21 | }
22 |
23 | var _isArray = undefined;
24 | if (!Array.isArray) {
25 | _isArray = function (x) {
26 | return Object.prototype.toString.call(x) === '[object Array]';
27 | };
28 | } else {
29 | _isArray = Array.isArray;
30 | }
31 |
32 | var isArray = _isArray;
33 |
34 | var len = 0;
35 | var vertxNext = undefined;
36 | var customSchedulerFn = undefined;
37 |
38 | var asap = function asap(callback, arg) {
39 | queue[len] = callback;
40 | queue[len + 1] = arg;
41 | len += 2;
42 | if (len === 2) {
43 | // If len is 2, that means that we need to schedule an async flush.
44 | // If additional callbacks are queued before the queue is flushed, they
45 | // will be processed by this flush that we are scheduling.
46 | if (customSchedulerFn) {
47 | customSchedulerFn(flush);
48 | } else {
49 | scheduleFlush();
50 | }
51 | }
52 | };
53 |
54 | function setScheduler(scheduleFn) {
55 | customSchedulerFn = scheduleFn;
56 | }
57 |
58 | function setAsap(asapFn) {
59 | asap = asapFn;
60 | }
61 |
62 | var browserWindow = typeof window !== 'undefined' ? window : undefined;
63 | var browserGlobal = browserWindow || {};
64 | var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
65 | var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && ({}).toString.call(process) === '[object process]';
66 |
67 | // test for web worker but not in IE10
68 | var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined';
69 |
70 | // node
71 | function useNextTick() {
72 | // node version 0.10.x displays a deprecation warning when nextTick is used recursively
73 | // see https://github.com/cujojs/when/issues/410 for details
74 | return function () {
75 | return process.nextTick(flush);
76 | };
77 | }
78 |
79 | // vertx
80 | function useVertxTimer() {
81 | if (typeof vertxNext !== 'undefined') {
82 | return function () {
83 | vertxNext(flush);
84 | };
85 | }
86 |
87 | return useSetTimeout();
88 | }
89 |
90 | function useMutationObserver() {
91 | var iterations = 0;
92 | var observer = new BrowserMutationObserver(flush);
93 | var node = document.createTextNode('');
94 | observer.observe(node, { characterData: true });
95 |
96 | return function () {
97 | node.data = iterations = ++iterations % 2;
98 | };
99 | }
100 |
101 | // web worker
102 | function useMessageChannel() {
103 | var channel = new MessageChannel();
104 | channel.port1.onmessage = flush;
105 | return function () {
106 | return channel.port2.postMessage(0);
107 | };
108 | }
109 |
110 | function useSetTimeout() {
111 | // Store setTimeout reference so es6-promise will be unaffected by
112 | // other code modifying setTimeout (like sinon.useFakeTimers())
113 | var globalSetTimeout = setTimeout;
114 | return function () {
115 | return globalSetTimeout(flush, 1);
116 | };
117 | }
118 |
119 | var queue = new Array(1000);
120 | function flush() {
121 | for (var i = 0; i < len; i += 2) {
122 | var callback = queue[i];
123 | var arg = queue[i + 1];
124 |
125 | callback(arg);
126 |
127 | queue[i] = undefined;
128 | queue[i + 1] = undefined;
129 | }
130 |
131 | len = 0;
132 | }
133 |
134 | function attemptVertx() {
135 | try {
136 | var r = require;
137 | var vertx = r('vertx');
138 | vertxNext = vertx.runOnLoop || vertx.runOnContext;
139 | return useVertxTimer();
140 | } catch (e) {
141 | return useSetTimeout();
142 | }
143 | }
144 |
145 | var scheduleFlush = undefined;
146 | // Decide what async method to use to triggering processing of queued callbacks:
147 | if (isNode) {
148 | scheduleFlush = useNextTick();
149 | } else if (BrowserMutationObserver) {
150 | scheduleFlush = useMutationObserver();
151 | } else if (isWorker) {
152 | scheduleFlush = useMessageChannel();
153 | } else if (browserWindow === undefined && typeof require === 'function') {
154 | scheduleFlush = attemptVertx();
155 | } else {
156 | scheduleFlush = useSetTimeout();
157 | }
158 |
159 | function then(onFulfillment, onRejection) {
160 | var _arguments = arguments;
161 |
162 | var parent = this;
163 |
164 | var child = new this.constructor(noop);
165 |
166 | if (child[PROMISE_ID] === undefined) {
167 | makePromise(child);
168 | }
169 |
170 | var _state = parent._state;
171 |
172 | if (_state) {
173 | (function () {
174 | var callback = _arguments[_state - 1];
175 | asap(function () {
176 | return invokeCallback(_state, child, callback, parent._result);
177 | });
178 | })();
179 | } else {
180 | subscribe(parent, child, onFulfillment, onRejection);
181 | }
182 |
183 | return child;
184 | }
185 |
186 | /**
187 | `Promise.resolve` returns a promise that will become resolved with the
188 | passed `value`. It is shorthand for the following:
189 |
190 | ```javascript
191 | let promise = new Promise(function(resolve, reject){
192 | resolve(1);
193 | });
194 |
195 | promise.then(function(value){
196 | // value === 1
197 | });
198 | ```
199 |
200 | Instead of writing the above, your code now simply becomes the following:
201 |
202 | ```javascript
203 | let promise = Promise.resolve(1);
204 |
205 | promise.then(function(value){
206 | // value === 1
207 | });
208 | ```
209 |
210 | @method resolve
211 | @static
212 | @param {Any} value value that the returned promise will be resolved with
213 | Useful for tooling.
214 | @return {Promise} a promise that will become fulfilled with the given
215 | `value`
216 | */
217 | function resolve(object) {
218 | /*jshint validthis:true */
219 | var Constructor = this;
220 |
221 | if (object && typeof object === 'object' && object.constructor === Constructor) {
222 | return object;
223 | }
224 |
225 | var promise = new Constructor(noop);
226 | _resolve(promise, object);
227 | return promise;
228 | }
229 |
230 | var PROMISE_ID = Math.random().toString(36).substring(16);
231 |
232 | function noop() {}
233 |
234 | var PENDING = void 0;
235 | var FULFILLED = 1;
236 | var REJECTED = 2;
237 |
238 | var GET_THEN_ERROR = new ErrorObject();
239 |
240 | function selfFulfillment() {
241 | return new TypeError("You cannot resolve a promise with itself");
242 | }
243 |
244 | function cannotReturnOwn() {
245 | return new TypeError('A promises callback cannot return that same promise.');
246 | }
247 |
248 | function getThen(promise) {
249 | try {
250 | return promise.then;
251 | } catch (error) {
252 | GET_THEN_ERROR.error = error;
253 | return GET_THEN_ERROR;
254 | }
255 | }
256 |
257 | function tryThen(then, value, fulfillmentHandler, rejectionHandler) {
258 | try {
259 | then.call(value, fulfillmentHandler, rejectionHandler);
260 | } catch (e) {
261 | return e;
262 | }
263 | }
264 |
265 | function handleForeignThenable(promise, thenable, then) {
266 | asap(function (promise) {
267 | var sealed = false;
268 | var error = tryThen(then, thenable, function (value) {
269 | if (sealed) {
270 | return;
271 | }
272 | sealed = true;
273 | if (thenable !== value) {
274 | _resolve(promise, value);
275 | } else {
276 | fulfill(promise, value);
277 | }
278 | }, function (reason) {
279 | if (sealed) {
280 | return;
281 | }
282 | sealed = true;
283 |
284 | _reject(promise, reason);
285 | }, 'Settle: ' + (promise._label || ' unknown promise'));
286 |
287 | if (!sealed && error) {
288 | sealed = true;
289 | _reject(promise, error);
290 | }
291 | }, promise);
292 | }
293 |
294 | function handleOwnThenable(promise, thenable) {
295 | if (thenable._state === FULFILLED) {
296 | fulfill(promise, thenable._result);
297 | } else if (thenable._state === REJECTED) {
298 | _reject(promise, thenable._result);
299 | } else {
300 | subscribe(thenable, undefined, function (value) {
301 | return _resolve(promise, value);
302 | }, function (reason) {
303 | return _reject(promise, reason);
304 | });
305 | }
306 | }
307 |
308 | function handleMaybeThenable(promise, maybeThenable, then$$) {
309 | if (maybeThenable.constructor === promise.constructor && then$$ === then && maybeThenable.constructor.resolve === resolve) {
310 | handleOwnThenable(promise, maybeThenable);
311 | } else {
312 | if (then$$ === GET_THEN_ERROR) {
313 | _reject(promise, GET_THEN_ERROR.error);
314 | GET_THEN_ERROR.error = null;
315 | } else if (then$$ === undefined) {
316 | fulfill(promise, maybeThenable);
317 | } else if (isFunction(then$$)) {
318 | handleForeignThenable(promise, maybeThenable, then$$);
319 | } else {
320 | fulfill(promise, maybeThenable);
321 | }
322 | }
323 | }
324 |
325 | function _resolve(promise, value) {
326 | if (promise === value) {
327 | _reject(promise, selfFulfillment());
328 | } else if (objectOrFunction(value)) {
329 | handleMaybeThenable(promise, value, getThen(value));
330 | } else {
331 | fulfill(promise, value);
332 | }
333 | }
334 |
335 | function publishRejection(promise) {
336 | if (promise._onerror) {
337 | promise._onerror(promise._result);
338 | }
339 |
340 | publish(promise);
341 | }
342 |
343 | function fulfill(promise, value) {
344 | if (promise._state !== PENDING) {
345 | return;
346 | }
347 |
348 | promise._result = value;
349 | promise._state = FULFILLED;
350 |
351 | if (promise._subscribers.length !== 0) {
352 | asap(publish, promise);
353 | }
354 | }
355 |
356 | function _reject(promise, reason) {
357 | if (promise._state !== PENDING) {
358 | return;
359 | }
360 | promise._state = REJECTED;
361 | promise._result = reason;
362 |
363 | asap(publishRejection, promise);
364 | }
365 |
366 | function subscribe(parent, child, onFulfillment, onRejection) {
367 | var _subscribers = parent._subscribers;
368 | var length = _subscribers.length;
369 |
370 | parent._onerror = null;
371 |
372 | _subscribers[length] = child;
373 | _subscribers[length + FULFILLED] = onFulfillment;
374 | _subscribers[length + REJECTED] = onRejection;
375 |
376 | if (length === 0 && parent._state) {
377 | asap(publish, parent);
378 | }
379 | }
380 |
381 | function publish(promise) {
382 | var subscribers = promise._subscribers;
383 | var settled = promise._state;
384 |
385 | if (subscribers.length === 0) {
386 | return;
387 | }
388 |
389 | var child = undefined,
390 | callback = undefined,
391 | detail = promise._result;
392 |
393 | for (var i = 0; i < subscribers.length; i += 3) {
394 | child = subscribers[i];
395 | callback = subscribers[i + settled];
396 |
397 | if (child) {
398 | invokeCallback(settled, child, callback, detail);
399 | } else {
400 | callback(detail);
401 | }
402 | }
403 |
404 | promise._subscribers.length = 0;
405 | }
406 |
407 | function ErrorObject() {
408 | this.error = null;
409 | }
410 |
411 | var TRY_CATCH_ERROR = new ErrorObject();
412 |
413 | function tryCatch(callback, detail) {
414 | try {
415 | return callback(detail);
416 | } catch (e) {
417 | TRY_CATCH_ERROR.error = e;
418 | return TRY_CATCH_ERROR;
419 | }
420 | }
421 |
422 | function invokeCallback(settled, promise, callback, detail) {
423 | var hasCallback = isFunction(callback),
424 | value = undefined,
425 | error = undefined,
426 | succeeded = undefined,
427 | failed = undefined;
428 |
429 | if (hasCallback) {
430 | value = tryCatch(callback, detail);
431 |
432 | if (value === TRY_CATCH_ERROR) {
433 | failed = true;
434 | error = value.error;
435 | value.error = null;
436 | } else {
437 | succeeded = true;
438 | }
439 |
440 | if (promise === value) {
441 | _reject(promise, cannotReturnOwn());
442 | return;
443 | }
444 | } else {
445 | value = detail;
446 | succeeded = true;
447 | }
448 |
449 | if (promise._state !== PENDING) {
450 | // noop
451 | } else if (hasCallback && succeeded) {
452 | _resolve(promise, value);
453 | } else if (failed) {
454 | _reject(promise, error);
455 | } else if (settled === FULFILLED) {
456 | fulfill(promise, value);
457 | } else if (settled === REJECTED) {
458 | _reject(promise, value);
459 | }
460 | }
461 |
462 | function initializePromise(promise, resolver) {
463 | try {
464 | resolver(function resolvePromise(value) {
465 | _resolve(promise, value);
466 | }, function rejectPromise(reason) {
467 | _reject(promise, reason);
468 | });
469 | } catch (e) {
470 | _reject(promise, e);
471 | }
472 | }
473 |
474 | var id = 0;
475 | function nextId() {
476 | return id++;
477 | }
478 |
479 | function makePromise(promise) {
480 | promise[PROMISE_ID] = id++;
481 | promise._state = undefined;
482 | promise._result = undefined;
483 | promise._subscribers = [];
484 | }
485 |
486 | function Enumerator(Constructor, input) {
487 | this._instanceConstructor = Constructor;
488 | this.promise = new Constructor(noop);
489 |
490 | if (!this.promise[PROMISE_ID]) {
491 | makePromise(this.promise);
492 | }
493 |
494 | if (isArray(input)) {
495 | this._input = input;
496 | this.length = input.length;
497 | this._remaining = input.length;
498 |
499 | this._result = new Array(this.length);
500 |
501 | if (this.length === 0) {
502 | fulfill(this.promise, this._result);
503 | } else {
504 | this.length = this.length || 0;
505 | this._enumerate();
506 | if (this._remaining === 0) {
507 | fulfill(this.promise, this._result);
508 | }
509 | }
510 | } else {
511 | _reject(this.promise, validationError());
512 | }
513 | }
514 |
515 | function validationError() {
516 | return new Error('Array Methods must be provided an Array');
517 | };
518 |
519 | Enumerator.prototype._enumerate = function () {
520 | var length = this.length;
521 | var _input = this._input;
522 |
523 | for (var i = 0; this._state === PENDING && i < length; i++) {
524 | this._eachEntry(_input[i], i);
525 | }
526 | };
527 |
528 | Enumerator.prototype._eachEntry = function (entry, i) {
529 | var c = this._instanceConstructor;
530 | var resolve$$ = c.resolve;
531 |
532 | if (resolve$$ === resolve) {
533 | var _then = getThen(entry);
534 |
535 | if (_then === then && entry._state !== PENDING) {
536 | this._settledAt(entry._state, i, entry._result);
537 | } else if (typeof _then !== 'function') {
538 | this._remaining--;
539 | this._result[i] = entry;
540 | } else if (c === Promise) {
541 | var promise = new c(noop);
542 | handleMaybeThenable(promise, entry, _then);
543 | this._willSettleAt(promise, i);
544 | } else {
545 | this._willSettleAt(new c(function (resolve$$) {
546 | return resolve$$(entry);
547 | }), i);
548 | }
549 | } else {
550 | this._willSettleAt(resolve$$(entry), i);
551 | }
552 | };
553 |
554 | Enumerator.prototype._settledAt = function (state, i, value) {
555 | var promise = this.promise;
556 |
557 | if (promise._state === PENDING) {
558 | this._remaining--;
559 |
560 | if (state === REJECTED) {
561 | _reject(promise, value);
562 | } else {
563 | this._result[i] = value;
564 | }
565 | }
566 |
567 | if (this._remaining === 0) {
568 | fulfill(promise, this._result);
569 | }
570 | };
571 |
572 | Enumerator.prototype._willSettleAt = function (promise, i) {
573 | var enumerator = this;
574 |
575 | subscribe(promise, undefined, function (value) {
576 | return enumerator._settledAt(FULFILLED, i, value);
577 | }, function (reason) {
578 | return enumerator._settledAt(REJECTED, i, reason);
579 | });
580 | };
581 |
582 | /**
583 | `Promise.all` accepts an array of promises, and returns a new promise which
584 | is fulfilled with an array of fulfillment values for the passed promises, or
585 | rejected with the reason of the first passed promise to be rejected. It casts all
586 | elements of the passed iterable to promises as it runs this algorithm.
587 |
588 | Example:
589 |
590 | ```javascript
591 | let promise1 = resolve(1);
592 | let promise2 = resolve(2);
593 | let promise3 = resolve(3);
594 | let promises = [ promise1, promise2, promise3 ];
595 |
596 | Promise.all(promises).then(function(array){
597 | // The array here would be [ 1, 2, 3 ];
598 | });
599 | ```
600 |
601 | If any of the `promises` given to `all` are rejected, the first promise
602 | that is rejected will be given as an argument to the returned promises's
603 | rejection handler. For example:
604 |
605 | Example:
606 |
607 | ```javascript
608 | let promise1 = resolve(1);
609 | let promise2 = reject(new Error("2"));
610 | let promise3 = reject(new Error("3"));
611 | let promises = [ promise1, promise2, promise3 ];
612 |
613 | Promise.all(promises).then(function(array){
614 | // Code here never runs because there are rejected promises!
615 | }, function(error) {
616 | // error.message === "2"
617 | });
618 | ```
619 |
620 | @method all
621 | @static
622 | @param {Array} entries array of promises
623 | @param {String} label optional string for labeling the promise.
624 | Useful for tooling.
625 | @return {Promise} promise that is fulfilled when all `promises` have been
626 | fulfilled, or rejected if any of them become rejected.
627 | @static
628 | */
629 | function all(entries) {
630 | return new Enumerator(this, entries).promise;
631 | }
632 |
633 | /**
634 | `Promise.race` returns a new promise which is settled in the same way as the
635 | first passed promise to settle.
636 |
637 | Example:
638 |
639 | ```javascript
640 | let promise1 = new Promise(function(resolve, reject){
641 | setTimeout(function(){
642 | resolve('promise 1');
643 | }, 200);
644 | });
645 |
646 | let promise2 = new Promise(function(resolve, reject){
647 | setTimeout(function(){
648 | resolve('promise 2');
649 | }, 100);
650 | });
651 |
652 | Promise.race([promise1, promise2]).then(function(result){
653 | // result === 'promise 2' because it was resolved before promise1
654 | // was resolved.
655 | });
656 | ```
657 |
658 | `Promise.race` is deterministic in that only the state of the first
659 | settled promise matters. For example, even if other promises given to the
660 | `promises` array argument are resolved, but the first settled promise has
661 | become rejected before the other promises became fulfilled, the returned
662 | promise will become rejected:
663 |
664 | ```javascript
665 | let promise1 = new Promise(function(resolve, reject){
666 | setTimeout(function(){
667 | resolve('promise 1');
668 | }, 200);
669 | });
670 |
671 | let promise2 = new Promise(function(resolve, reject){
672 | setTimeout(function(){
673 | reject(new Error('promise 2'));
674 | }, 100);
675 | });
676 |
677 | Promise.race([promise1, promise2]).then(function(result){
678 | // Code here never runs
679 | }, function(reason){
680 | // reason.message === 'promise 2' because promise 2 became rejected before
681 | // promise 1 became fulfilled
682 | });
683 | ```
684 |
685 | An example real-world use case is implementing timeouts:
686 |
687 | ```javascript
688 | Promise.race([ajax('foo.json'), timeout(5000)])
689 | ```
690 |
691 | @method race
692 | @static
693 | @param {Array} promises array of promises to observe
694 | Useful for tooling.
695 | @return {Promise} a promise which settles in the same way as the first passed
696 | promise to settle.
697 | */
698 | function race(entries) {
699 | /*jshint validthis:true */
700 | var Constructor = this;
701 |
702 | if (!isArray(entries)) {
703 | return new Constructor(function (_, reject) {
704 | return reject(new TypeError('You must pass an array to race.'));
705 | });
706 | } else {
707 | return new Constructor(function (resolve, reject) {
708 | var length = entries.length;
709 | for (var i = 0; i < length; i++) {
710 | Constructor.resolve(entries[i]).then(resolve, reject);
711 | }
712 | });
713 | }
714 | }
715 |
716 | /**
717 | `Promise.reject` returns a promise rejected with the passed `reason`.
718 | It is shorthand for the following:
719 |
720 | ```javascript
721 | let promise = new Promise(function(resolve, reject){
722 | reject(new Error('WHOOPS'));
723 | });
724 |
725 | promise.then(function(value){
726 | // Code here doesn't run because the promise is rejected!
727 | }, function(reason){
728 | // reason.message === 'WHOOPS'
729 | });
730 | ```
731 |
732 | Instead of writing the above, your code now simply becomes the following:
733 |
734 | ```javascript
735 | let promise = Promise.reject(new Error('WHOOPS'));
736 |
737 | promise.then(function(value){
738 | // Code here doesn't run because the promise is rejected!
739 | }, function(reason){
740 | // reason.message === 'WHOOPS'
741 | });
742 | ```
743 |
744 | @method reject
745 | @static
746 | @param {Any} reason value that the returned promise will be rejected with.
747 | Useful for tooling.
748 | @return {Promise} a promise rejected with the given `reason`.
749 | */
750 | function reject(reason) {
751 | /*jshint validthis:true */
752 | var Constructor = this;
753 | var promise = new Constructor(noop);
754 | _reject(promise, reason);
755 | return promise;
756 | }
757 |
758 | function needsResolver() {
759 | throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
760 | }
761 |
762 | function needsNew() {
763 | throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
764 | }
765 |
766 | /**
767 | Promise objects represent the eventual result of an asynchronous operation. The
768 | primary way of interacting with a promise is through its `then` method, which
769 | registers callbacks to receive either a promise's eventual value or the reason
770 | why the promise cannot be fulfilled.
771 |
772 | Terminology
773 | -----------
774 |
775 | - `promise` is an object or function with a `then` method whose behavior conforms to this specification.
776 | - `thenable` is an object or function that defines a `then` method.
777 | - `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
778 | - `exception` is a value that is thrown using the throw statement.
779 | - `reason` is a value that indicates why a promise was rejected.
780 | - `settled` the final resting state of a promise, fulfilled or rejected.
781 |
782 | A promise can be in one of three states: pending, fulfilled, or rejected.
783 |
784 | Promises that are fulfilled have a fulfillment value and are in the fulfilled
785 | state. Promises that are rejected have a rejection reason and are in the
786 | rejected state. A fulfillment value is never a thenable.
787 |
788 | Promises can also be said to *resolve* a value. If this value is also a
789 | promise, then the original promise's settled state will match the value's
790 | settled state. So a promise that *resolves* a promise that rejects will
791 | itself reject, and a promise that *resolves* a promise that fulfills will
792 | itself fulfill.
793 |
794 |
795 | Basic Usage:
796 | ------------
797 |
798 | ```js
799 | let promise = new Promise(function(resolve, reject) {
800 | // on success
801 | resolve(value);
802 |
803 | // on failure
804 | reject(reason);
805 | });
806 |
807 | promise.then(function(value) {
808 | // on fulfillment
809 | }, function(reason) {
810 | // on rejection
811 | });
812 | ```
813 |
814 | Advanced Usage:
815 | ---------------
816 |
817 | Promises shine when abstracting away asynchronous interactions such as
818 | `XMLHttpRequest`s.
819 |
820 | ```js
821 | function getJSON(url) {
822 | return new Promise(function(resolve, reject){
823 | let xhr = new XMLHttpRequest();
824 |
825 | xhr.open('GET', url);
826 | xhr.onreadystatechange = handler;
827 | xhr.responseType = 'json';
828 | xhr.setRequestHeader('Accept', 'application/json');
829 | xhr.send();
830 |
831 | function handler() {
832 | if (this.readyState === this.DONE) {
833 | if (this.status === 200) {
834 | resolve(this.response);
835 | } else {
836 | reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
837 | }
838 | }
839 | };
840 | });
841 | }
842 |
843 | getJSON('/posts.json').then(function(json) {
844 | // on fulfillment
845 | }, function(reason) {
846 | // on rejection
847 | });
848 | ```
849 |
850 | Unlike callbacks, promises are great composable primitives.
851 |
852 | ```js
853 | Promise.all([
854 | getJSON('/posts'),
855 | getJSON('/comments')
856 | ]).then(function(values){
857 | values[0] // => postsJSON
858 | values[1] // => commentsJSON
859 |
860 | return values;
861 | });
862 | ```
863 |
864 | @class Promise
865 | @param {function} resolver
866 | Useful for tooling.
867 | @constructor
868 | */
869 | function Promise(resolver) {
870 | this[PROMISE_ID] = nextId();
871 | this._result = this._state = undefined;
872 | this._subscribers = [];
873 |
874 | if (noop !== resolver) {
875 | typeof resolver !== 'function' && needsResolver();
876 | this instanceof Promise ? initializePromise(this, resolver) : needsNew();
877 | }
878 | }
879 |
880 | Promise.all = all;
881 | Promise.race = race;
882 | Promise.resolve = resolve;
883 | Promise.reject = reject;
884 | Promise._setScheduler = setScheduler;
885 | Promise._setAsap = setAsap;
886 | Promise._asap = asap;
887 |
888 | Promise.prototype = {
889 | constructor: Promise,
890 |
891 | /**
892 | The primary way of interacting with a promise is through its `then` method,
893 | which registers callbacks to receive either a promise's eventual value or the
894 | reason why the promise cannot be fulfilled.
895 |
896 | ```js
897 | findUser().then(function(user){
898 | // user is available
899 | }, function(reason){
900 | // user is unavailable, and you are given the reason why
901 | });
902 | ```
903 |
904 | Chaining
905 | --------
906 |
907 | The return value of `then` is itself a promise. This second, 'downstream'
908 | promise is resolved with the return value of the first promise's fulfillment
909 | or rejection handler, or rejected if the handler throws an exception.
910 |
911 | ```js
912 | findUser().then(function (user) {
913 | return user.name;
914 | }, function (reason) {
915 | return 'default name';
916 | }).then(function (userName) {
917 | // If `findUser` fulfilled, `userName` will be the user's name, otherwise it
918 | // will be `'default name'`
919 | });
920 |
921 | findUser().then(function (user) {
922 | throw new Error('Found user, but still unhappy');
923 | }, function (reason) {
924 | throw new Error('`findUser` rejected and we're unhappy');
925 | }).then(function (value) {
926 | // never reached
927 | }, function (reason) {
928 | // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
929 | // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
930 | });
931 | ```
932 | If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
933 |
934 | ```js
935 | findUser().then(function (user) {
936 | throw new PedagogicalException('Upstream error');
937 | }).then(function (value) {
938 | // never reached
939 | }).then(function (value) {
940 | // never reached
941 | }, function (reason) {
942 | // The `PedgagocialException` is propagated all the way down to here
943 | });
944 | ```
945 |
946 | Assimilation
947 | ------------
948 |
949 | Sometimes the value you want to propagate to a downstream promise can only be
950 | retrieved asynchronously. This can be achieved by returning a promise in the
951 | fulfillment or rejection handler. The downstream promise will then be pending
952 | until the returned promise is settled. This is called *assimilation*.
953 |
954 | ```js
955 | findUser().then(function (user) {
956 | return findCommentsByAuthor(user);
957 | }).then(function (comments) {
958 | // The user's comments are now available
959 | });
960 | ```
961 |
962 | If the assimliated promise rejects, then the downstream promise will also reject.
963 |
964 | ```js
965 | findUser().then(function (user) {
966 | return findCommentsByAuthor(user);
967 | }).then(function (comments) {
968 | // If `findCommentsByAuthor` fulfills, we'll have the value here
969 | }, function (reason) {
970 | // If `findCommentsByAuthor` rejects, we'll have the reason here
971 | });
972 | ```
973 |
974 | Simple Example
975 | --------------
976 |
977 | Synchronous Example
978 |
979 | ```javascript
980 | let result;
981 |
982 | try {
983 | result = findResult();
984 | // success
985 | } catch(reason) {
986 | // failure
987 | }
988 | ```
989 |
990 | Errback Example
991 |
992 | ```js
993 | findResult(function(result, err){
994 | if (err) {
995 | // failure
996 | } else {
997 | // success
998 | }
999 | });
1000 | ```
1001 |
1002 | Promise Example;
1003 |
1004 | ```javascript
1005 | findResult().then(function(result){
1006 | // success
1007 | }, function(reason){
1008 | // failure
1009 | });
1010 | ```
1011 |
1012 | Advanced Example
1013 | --------------
1014 |
1015 | Synchronous Example
1016 |
1017 | ```javascript
1018 | let author, books;
1019 |
1020 | try {
1021 | author = findAuthor();
1022 | books = findBooksByAuthor(author);
1023 | // success
1024 | } catch(reason) {
1025 | // failure
1026 | }
1027 | ```
1028 |
1029 | Errback Example
1030 |
1031 | ```js
1032 |
1033 | function foundBooks(books) {
1034 |
1035 | }
1036 |
1037 | function failure(reason) {
1038 |
1039 | }
1040 |
1041 | findAuthor(function(author, err){
1042 | if (err) {
1043 | failure(err);
1044 | // failure
1045 | } else {
1046 | try {
1047 | findBoooksByAuthor(author, function(books, err) {
1048 | if (err) {
1049 | failure(err);
1050 | } else {
1051 | try {
1052 | foundBooks(books);
1053 | } catch(reason) {
1054 | failure(reason);
1055 | }
1056 | }
1057 | });
1058 | } catch(error) {
1059 | failure(err);
1060 | }
1061 | // success
1062 | }
1063 | });
1064 | ```
1065 |
1066 | Promise Example;
1067 |
1068 | ```javascript
1069 | findAuthor().
1070 | then(findBooksByAuthor).
1071 | then(function(books){
1072 | // found books
1073 | }).catch(function(reason){
1074 | // something went wrong
1075 | });
1076 | ```
1077 |
1078 | @method then
1079 | @param {Function} onFulfilled
1080 | @param {Function} onRejected
1081 | Useful for tooling.
1082 | @return {Promise}
1083 | */
1084 | then: then,
1085 |
1086 | /**
1087 | `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
1088 | as the catch block of a try/catch statement.
1089 |
1090 | ```js
1091 | function findAuthor(){
1092 | throw new Error('couldn't find that author');
1093 | }
1094 |
1095 | // synchronous
1096 | try {
1097 | findAuthor();
1098 | } catch(reason) {
1099 | // something went wrong
1100 | }
1101 |
1102 | // async with promises
1103 | findAuthor().catch(function(reason){
1104 | // something went wrong
1105 | });
1106 | ```
1107 |
1108 | @method catch
1109 | @param {Function} onRejection
1110 | Useful for tooling.
1111 | @return {Promise}
1112 | */
1113 | 'catch': function _catch(onRejection) {
1114 | return this.then(null, onRejection);
1115 | }
1116 | };
1117 |
1118 | function polyfill() {
1119 | var local = undefined;
1120 |
1121 | if (typeof global !== 'undefined') {
1122 | local = global;
1123 | } else if (typeof self !== 'undefined') {
1124 | local = self;
1125 | } else {
1126 | try {
1127 | local = Function('return this')();
1128 | } catch (e) {
1129 | throw new Error('polyfill failed because global object is unavailable in this environment');
1130 | }
1131 | }
1132 |
1133 | var P = local.Promise;
1134 |
1135 | if (P) {
1136 | var promiseToString = null;
1137 | try {
1138 | promiseToString = Object.prototype.toString.call(P.resolve());
1139 | } catch (e) {
1140 | // silently ignored
1141 | }
1142 |
1143 | if (promiseToString === '[object Promise]' && !P.cast) {
1144 | return;
1145 | }
1146 | }
1147 |
1148 | local.Promise = Promise;
1149 | }
1150 |
1151 | // Strange compat..
1152 | Promise.polyfill = polyfill;
1153 | Promise.Promise = Promise;
1154 |
1155 | return Promise;
1156 |
1157 | })));
1158 | //# sourceMappingURL=es6-promise.map
1159 |
--------------------------------------------------------------------------------
/dist/es6-promise.auto.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * @overview es6-promise - a tiny implementation of Promises/A+.
3 | * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
4 | * @license Licensed under MIT license
5 | * See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE
6 | * @version 4.1.0+f9a5575b
7 | */
8 |
9 | (function (global, factory) {
10 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
11 | typeof define === 'function' && define.amd ? define(factory) :
12 | (global.ES6Promise = factory());
13 | }(this, (function () { 'use strict';
14 |
15 | function objectOrFunction(x) {
16 | return typeof x === 'function' || typeof x === 'object' && x !== null;
17 | }
18 |
19 | function isFunction(x) {
20 | return typeof x === 'function';
21 | }
22 |
23 | var _isArray = undefined;
24 | if (!Array.isArray) {
25 | _isArray = function (x) {
26 | return Object.prototype.toString.call(x) === '[object Array]';
27 | };
28 | } else {
29 | _isArray = Array.isArray;
30 | }
31 |
32 | var isArray = _isArray;
33 |
34 | var len = 0;
35 | var vertxNext = undefined;
36 | var customSchedulerFn = undefined;
37 |
38 | var asap = function asap(callback, arg) {
39 | queue[len] = callback;
40 | queue[len + 1] = arg;
41 | len += 2;
42 | if (len === 2) {
43 | // If len is 2, that means that we need to schedule an async flush.
44 | // If additional callbacks are queued before the queue is flushed, they
45 | // will be processed by this flush that we are scheduling.
46 | if (customSchedulerFn) {
47 | customSchedulerFn(flush);
48 | } else {
49 | scheduleFlush();
50 | }
51 | }
52 | };
53 |
54 | function setScheduler(scheduleFn) {
55 | customSchedulerFn = scheduleFn;
56 | }
57 |
58 | function setAsap(asapFn) {
59 | asap = asapFn;
60 | }
61 |
62 | var browserWindow = typeof window !== 'undefined' ? window : undefined;
63 | var browserGlobal = browserWindow || {};
64 | var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
65 | var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && ({}).toString.call(process) === '[object process]';
66 |
67 | // test for web worker but not in IE10
68 | var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined';
69 |
70 | // node
71 | function useNextTick() {
72 | // node version 0.10.x displays a deprecation warning when nextTick is used recursively
73 | // see https://github.com/cujojs/when/issues/410 for details
74 | return function () {
75 | return process.nextTick(flush);
76 | };
77 | }
78 |
79 | // vertx
80 | function useVertxTimer() {
81 | if (typeof vertxNext !== 'undefined') {
82 | return function () {
83 | vertxNext(flush);
84 | };
85 | }
86 |
87 | return useSetTimeout();
88 | }
89 |
90 | function useMutationObserver() {
91 | var iterations = 0;
92 | var observer = new BrowserMutationObserver(flush);
93 | var node = document.createTextNode('');
94 | observer.observe(node, { characterData: true });
95 |
96 | return function () {
97 | node.data = iterations = ++iterations % 2;
98 | };
99 | }
100 |
101 | // web worker
102 | function useMessageChannel() {
103 | var channel = new MessageChannel();
104 | channel.port1.onmessage = flush;
105 | return function () {
106 | return channel.port2.postMessage(0);
107 | };
108 | }
109 |
110 | function useSetTimeout() {
111 | // Store setTimeout reference so es6-promise will be unaffected by
112 | // other code modifying setTimeout (like sinon.useFakeTimers())
113 | var globalSetTimeout = setTimeout;
114 | return function () {
115 | return globalSetTimeout(flush, 1);
116 | };
117 | }
118 |
119 | var queue = new Array(1000);
120 | function flush() {
121 | for (var i = 0; i < len; i += 2) {
122 | var callback = queue[i];
123 | var arg = queue[i + 1];
124 |
125 | callback(arg);
126 |
127 | queue[i] = undefined;
128 | queue[i + 1] = undefined;
129 | }
130 |
131 | len = 0;
132 | }
133 |
134 | function attemptVertx() {
135 | try {
136 | var r = require;
137 | var vertx = r('vertx');
138 | vertxNext = vertx.runOnLoop || vertx.runOnContext;
139 | return useVertxTimer();
140 | } catch (e) {
141 | return useSetTimeout();
142 | }
143 | }
144 |
145 | var scheduleFlush = undefined;
146 | // Decide what async method to use to triggering processing of queued callbacks:
147 | if (isNode) {
148 | scheduleFlush = useNextTick();
149 | } else if (BrowserMutationObserver) {
150 | scheduleFlush = useMutationObserver();
151 | } else if (isWorker) {
152 | scheduleFlush = useMessageChannel();
153 | } else if (browserWindow === undefined && typeof require === 'function') {
154 | scheduleFlush = attemptVertx();
155 | } else {
156 | scheduleFlush = useSetTimeout();
157 | }
158 |
159 | function then(onFulfillment, onRejection) {
160 | var _arguments = arguments;
161 |
162 | var parent = this;
163 |
164 | var child = new this.constructor(noop);
165 |
166 | if (child[PROMISE_ID] === undefined) {
167 | makePromise(child);
168 | }
169 |
170 | var _state = parent._state;
171 |
172 | if (_state) {
173 | (function () {
174 | var callback = _arguments[_state - 1];
175 | asap(function () {
176 | return invokeCallback(_state, child, callback, parent._result);
177 | });
178 | })();
179 | } else {
180 | subscribe(parent, child, onFulfillment, onRejection);
181 | }
182 |
183 | return child;
184 | }
185 |
186 | /**
187 | `Promise.resolve` returns a promise that will become resolved with the
188 | passed `value`. It is shorthand for the following:
189 |
190 | ```javascript
191 | let promise = new Promise(function(resolve, reject){
192 | resolve(1);
193 | });
194 |
195 | promise.then(function(value){
196 | // value === 1
197 | });
198 | ```
199 |
200 | Instead of writing the above, your code now simply becomes the following:
201 |
202 | ```javascript
203 | let promise = Promise.resolve(1);
204 |
205 | promise.then(function(value){
206 | // value === 1
207 | });
208 | ```
209 |
210 | @method resolve
211 | @static
212 | @param {Any} value value that the returned promise will be resolved with
213 | Useful for tooling.
214 | @return {Promise} a promise that will become fulfilled with the given
215 | `value`
216 | */
217 | function resolve(object) {
218 | /*jshint validthis:true */
219 | var Constructor = this;
220 |
221 | if (object && typeof object === 'object' && object.constructor === Constructor) {
222 | return object;
223 | }
224 |
225 | var promise = new Constructor(noop);
226 | _resolve(promise, object);
227 | return promise;
228 | }
229 |
230 | var PROMISE_ID = Math.random().toString(36).substring(16);
231 |
232 | function noop() {}
233 |
234 | var PENDING = void 0;
235 | var FULFILLED = 1;
236 | var REJECTED = 2;
237 |
238 | var GET_THEN_ERROR = new ErrorObject();
239 |
240 | function selfFulfillment() {
241 | return new TypeError("You cannot resolve a promise with itself");
242 | }
243 |
244 | function cannotReturnOwn() {
245 | return new TypeError('A promises callback cannot return that same promise.');
246 | }
247 |
248 | function getThen(promise) {
249 | try {
250 | return promise.then;
251 | } catch (error) {
252 | GET_THEN_ERROR.error = error;
253 | return GET_THEN_ERROR;
254 | }
255 | }
256 |
257 | function tryThen(then, value, fulfillmentHandler, rejectionHandler) {
258 | try {
259 | then.call(value, fulfillmentHandler, rejectionHandler);
260 | } catch (e) {
261 | return e;
262 | }
263 | }
264 |
265 | function handleForeignThenable(promise, thenable, then) {
266 | asap(function (promise) {
267 | var sealed = false;
268 | var error = tryThen(then, thenable, function (value) {
269 | if (sealed) {
270 | return;
271 | }
272 | sealed = true;
273 | if (thenable !== value) {
274 | _resolve(promise, value);
275 | } else {
276 | fulfill(promise, value);
277 | }
278 | }, function (reason) {
279 | if (sealed) {
280 | return;
281 | }
282 | sealed = true;
283 |
284 | _reject(promise, reason);
285 | }, 'Settle: ' + (promise._label || ' unknown promise'));
286 |
287 | if (!sealed && error) {
288 | sealed = true;
289 | _reject(promise, error);
290 | }
291 | }, promise);
292 | }
293 |
294 | function handleOwnThenable(promise, thenable) {
295 | if (thenable._state === FULFILLED) {
296 | fulfill(promise, thenable._result);
297 | } else if (thenable._state === REJECTED) {
298 | _reject(promise, thenable._result);
299 | } else {
300 | subscribe(thenable, undefined, function (value) {
301 | return _resolve(promise, value);
302 | }, function (reason) {
303 | return _reject(promise, reason);
304 | });
305 | }
306 | }
307 |
308 | function handleMaybeThenable(promise, maybeThenable, then$$) {
309 | if (maybeThenable.constructor === promise.constructor && then$$ === then && maybeThenable.constructor.resolve === resolve) {
310 | handleOwnThenable(promise, maybeThenable);
311 | } else {
312 | if (then$$ === GET_THEN_ERROR) {
313 | _reject(promise, GET_THEN_ERROR.error);
314 | GET_THEN_ERROR.error = null;
315 | } else if (then$$ === undefined) {
316 | fulfill(promise, maybeThenable);
317 | } else if (isFunction(then$$)) {
318 | handleForeignThenable(promise, maybeThenable, then$$);
319 | } else {
320 | fulfill(promise, maybeThenable);
321 | }
322 | }
323 | }
324 |
325 | function _resolve(promise, value) {
326 | if (promise === value) {
327 | _reject(promise, selfFulfillment());
328 | } else if (objectOrFunction(value)) {
329 | handleMaybeThenable(promise, value, getThen(value));
330 | } else {
331 | fulfill(promise, value);
332 | }
333 | }
334 |
335 | function publishRejection(promise) {
336 | if (promise._onerror) {
337 | promise._onerror(promise._result);
338 | }
339 |
340 | publish(promise);
341 | }
342 |
343 | function fulfill(promise, value) {
344 | if (promise._state !== PENDING) {
345 | return;
346 | }
347 |
348 | promise._result = value;
349 | promise._state = FULFILLED;
350 |
351 | if (promise._subscribers.length !== 0) {
352 | asap(publish, promise);
353 | }
354 | }
355 |
356 | function _reject(promise, reason) {
357 | if (promise._state !== PENDING) {
358 | return;
359 | }
360 | promise._state = REJECTED;
361 | promise._result = reason;
362 |
363 | asap(publishRejection, promise);
364 | }
365 |
366 | function subscribe(parent, child, onFulfillment, onRejection) {
367 | var _subscribers = parent._subscribers;
368 | var length = _subscribers.length;
369 |
370 | parent._onerror = null;
371 |
372 | _subscribers[length] = child;
373 | _subscribers[length + FULFILLED] = onFulfillment;
374 | _subscribers[length + REJECTED] = onRejection;
375 |
376 | if (length === 0 && parent._state) {
377 | asap(publish, parent);
378 | }
379 | }
380 |
381 | function publish(promise) {
382 | var subscribers = promise._subscribers;
383 | var settled = promise._state;
384 |
385 | if (subscribers.length === 0) {
386 | return;
387 | }
388 |
389 | var child = undefined,
390 | callback = undefined,
391 | detail = promise._result;
392 |
393 | for (var i = 0; i < subscribers.length; i += 3) {
394 | child = subscribers[i];
395 | callback = subscribers[i + settled];
396 |
397 | if (child) {
398 | invokeCallback(settled, child, callback, detail);
399 | } else {
400 | callback(detail);
401 | }
402 | }
403 |
404 | promise._subscribers.length = 0;
405 | }
406 |
407 | function ErrorObject() {
408 | this.error = null;
409 | }
410 |
411 | var TRY_CATCH_ERROR = new ErrorObject();
412 |
413 | function tryCatch(callback, detail) {
414 | try {
415 | return callback(detail);
416 | } catch (e) {
417 | TRY_CATCH_ERROR.error = e;
418 | return TRY_CATCH_ERROR;
419 | }
420 | }
421 |
422 | function invokeCallback(settled, promise, callback, detail) {
423 | var hasCallback = isFunction(callback),
424 | value = undefined,
425 | error = undefined,
426 | succeeded = undefined,
427 | failed = undefined;
428 |
429 | if (hasCallback) {
430 | value = tryCatch(callback, detail);
431 |
432 | if (value === TRY_CATCH_ERROR) {
433 | failed = true;
434 | error = value.error;
435 | value.error = null;
436 | } else {
437 | succeeded = true;
438 | }
439 |
440 | if (promise === value) {
441 | _reject(promise, cannotReturnOwn());
442 | return;
443 | }
444 | } else {
445 | value = detail;
446 | succeeded = true;
447 | }
448 |
449 | if (promise._state !== PENDING) {
450 | // noop
451 | } else if (hasCallback && succeeded) {
452 | _resolve(promise, value);
453 | } else if (failed) {
454 | _reject(promise, error);
455 | } else if (settled === FULFILLED) {
456 | fulfill(promise, value);
457 | } else if (settled === REJECTED) {
458 | _reject(promise, value);
459 | }
460 | }
461 |
462 | function initializePromise(promise, resolver) {
463 | try {
464 | resolver(function resolvePromise(value) {
465 | _resolve(promise, value);
466 | }, function rejectPromise(reason) {
467 | _reject(promise, reason);
468 | });
469 | } catch (e) {
470 | _reject(promise, e);
471 | }
472 | }
473 |
474 | var id = 0;
475 | function nextId() {
476 | return id++;
477 | }
478 |
479 | function makePromise(promise) {
480 | promise[PROMISE_ID] = id++;
481 | promise._state = undefined;
482 | promise._result = undefined;
483 | promise._subscribers = [];
484 | }
485 |
486 | function Enumerator(Constructor, input) {
487 | this._instanceConstructor = Constructor;
488 | this.promise = new Constructor(noop);
489 |
490 | if (!this.promise[PROMISE_ID]) {
491 | makePromise(this.promise);
492 | }
493 |
494 | if (isArray(input)) {
495 | this._input = input;
496 | this.length = input.length;
497 | this._remaining = input.length;
498 |
499 | this._result = new Array(this.length);
500 |
501 | if (this.length === 0) {
502 | fulfill(this.promise, this._result);
503 | } else {
504 | this.length = this.length || 0;
505 | this._enumerate();
506 | if (this._remaining === 0) {
507 | fulfill(this.promise, this._result);
508 | }
509 | }
510 | } else {
511 | _reject(this.promise, validationError());
512 | }
513 | }
514 |
515 | function validationError() {
516 | return new Error('Array Methods must be provided an Array');
517 | };
518 |
519 | Enumerator.prototype._enumerate = function () {
520 | var length = this.length;
521 | var _input = this._input;
522 |
523 | for (var i = 0; this._state === PENDING && i < length; i++) {
524 | this._eachEntry(_input[i], i);
525 | }
526 | };
527 |
528 | Enumerator.prototype._eachEntry = function (entry, i) {
529 | var c = this._instanceConstructor;
530 | var resolve$$ = c.resolve;
531 |
532 | if (resolve$$ === resolve) {
533 | var _then = getThen(entry);
534 |
535 | if (_then === then && entry._state !== PENDING) {
536 | this._settledAt(entry._state, i, entry._result);
537 | } else if (typeof _then !== 'function') {
538 | this._remaining--;
539 | this._result[i] = entry;
540 | } else if (c === Promise) {
541 | var promise = new c(noop);
542 | handleMaybeThenable(promise, entry, _then);
543 | this._willSettleAt(promise, i);
544 | } else {
545 | this._willSettleAt(new c(function (resolve$$) {
546 | return resolve$$(entry);
547 | }), i);
548 | }
549 | } else {
550 | this._willSettleAt(resolve$$(entry), i);
551 | }
552 | };
553 |
554 | Enumerator.prototype._settledAt = function (state, i, value) {
555 | var promise = this.promise;
556 |
557 | if (promise._state === PENDING) {
558 | this._remaining--;
559 |
560 | if (state === REJECTED) {
561 | _reject(promise, value);
562 | } else {
563 | this._result[i] = value;
564 | }
565 | }
566 |
567 | if (this._remaining === 0) {
568 | fulfill(promise, this._result);
569 | }
570 | };
571 |
572 | Enumerator.prototype._willSettleAt = function (promise, i) {
573 | var enumerator = this;
574 |
575 | subscribe(promise, undefined, function (value) {
576 | return enumerator._settledAt(FULFILLED, i, value);
577 | }, function (reason) {
578 | return enumerator._settledAt(REJECTED, i, reason);
579 | });
580 | };
581 |
582 | /**
583 | `Promise.all` accepts an array of promises, and returns a new promise which
584 | is fulfilled with an array of fulfillment values for the passed promises, or
585 | rejected with the reason of the first passed promise to be rejected. It casts all
586 | elements of the passed iterable to promises as it runs this algorithm.
587 |
588 | Example:
589 |
590 | ```javascript
591 | let promise1 = resolve(1);
592 | let promise2 = resolve(2);
593 | let promise3 = resolve(3);
594 | let promises = [ promise1, promise2, promise3 ];
595 |
596 | Promise.all(promises).then(function(array){
597 | // The array here would be [ 1, 2, 3 ];
598 | });
599 | ```
600 |
601 | If any of the `promises` given to `all` are rejected, the first promise
602 | that is rejected will be given as an argument to the returned promises's
603 | rejection handler. For example:
604 |
605 | Example:
606 |
607 | ```javascript
608 | let promise1 = resolve(1);
609 | let promise2 = reject(new Error("2"));
610 | let promise3 = reject(new Error("3"));
611 | let promises = [ promise1, promise2, promise3 ];
612 |
613 | Promise.all(promises).then(function(array){
614 | // Code here never runs because there are rejected promises!
615 | }, function(error) {
616 | // error.message === "2"
617 | });
618 | ```
619 |
620 | @method all
621 | @static
622 | @param {Array} entries array of promises
623 | @param {String} label optional string for labeling the promise.
624 | Useful for tooling.
625 | @return {Promise} promise that is fulfilled when all `promises` have been
626 | fulfilled, or rejected if any of them become rejected.
627 | @static
628 | */
629 | function all(entries) {
630 | return new Enumerator(this, entries).promise;
631 | }
632 |
633 | /**
634 | `Promise.race` returns a new promise which is settled in the same way as the
635 | first passed promise to settle.
636 |
637 | Example:
638 |
639 | ```javascript
640 | let promise1 = new Promise(function(resolve, reject){
641 | setTimeout(function(){
642 | resolve('promise 1');
643 | }, 200);
644 | });
645 |
646 | let promise2 = new Promise(function(resolve, reject){
647 | setTimeout(function(){
648 | resolve('promise 2');
649 | }, 100);
650 | });
651 |
652 | Promise.race([promise1, promise2]).then(function(result){
653 | // result === 'promise 2' because it was resolved before promise1
654 | // was resolved.
655 | });
656 | ```
657 |
658 | `Promise.race` is deterministic in that only the state of the first
659 | settled promise matters. For example, even if other promises given to the
660 | `promises` array argument are resolved, but the first settled promise has
661 | become rejected before the other promises became fulfilled, the returned
662 | promise will become rejected:
663 |
664 | ```javascript
665 | let promise1 = new Promise(function(resolve, reject){
666 | setTimeout(function(){
667 | resolve('promise 1');
668 | }, 200);
669 | });
670 |
671 | let promise2 = new Promise(function(resolve, reject){
672 | setTimeout(function(){
673 | reject(new Error('promise 2'));
674 | }, 100);
675 | });
676 |
677 | Promise.race([promise1, promise2]).then(function(result){
678 | // Code here never runs
679 | }, function(reason){
680 | // reason.message === 'promise 2' because promise 2 became rejected before
681 | // promise 1 became fulfilled
682 | });
683 | ```
684 |
685 | An example real-world use case is implementing timeouts:
686 |
687 | ```javascript
688 | Promise.race([ajax('foo.json'), timeout(5000)])
689 | ```
690 |
691 | @method race
692 | @static
693 | @param {Array} promises array of promises to observe
694 | Useful for tooling.
695 | @return {Promise} a promise which settles in the same way as the first passed
696 | promise to settle.
697 | */
698 | function race(entries) {
699 | /*jshint validthis:true */
700 | var Constructor = this;
701 |
702 | if (!isArray(entries)) {
703 | return new Constructor(function (_, reject) {
704 | return reject(new TypeError('You must pass an array to race.'));
705 | });
706 | } else {
707 | return new Constructor(function (resolve, reject) {
708 | var length = entries.length;
709 | for (var i = 0; i < length; i++) {
710 | Constructor.resolve(entries[i]).then(resolve, reject);
711 | }
712 | });
713 | }
714 | }
715 |
716 | /**
717 | `Promise.reject` returns a promise rejected with the passed `reason`.
718 | It is shorthand for the following:
719 |
720 | ```javascript
721 | let promise = new Promise(function(resolve, reject){
722 | reject(new Error('WHOOPS'));
723 | });
724 |
725 | promise.then(function(value){
726 | // Code here doesn't run because the promise is rejected!
727 | }, function(reason){
728 | // reason.message === 'WHOOPS'
729 | });
730 | ```
731 |
732 | Instead of writing the above, your code now simply becomes the following:
733 |
734 | ```javascript
735 | let promise = Promise.reject(new Error('WHOOPS'));
736 |
737 | promise.then(function(value){
738 | // Code here doesn't run because the promise is rejected!
739 | }, function(reason){
740 | // reason.message === 'WHOOPS'
741 | });
742 | ```
743 |
744 | @method reject
745 | @static
746 | @param {Any} reason value that the returned promise will be rejected with.
747 | Useful for tooling.
748 | @return {Promise} a promise rejected with the given `reason`.
749 | */
750 | function reject(reason) {
751 | /*jshint validthis:true */
752 | var Constructor = this;
753 | var promise = new Constructor(noop);
754 | _reject(promise, reason);
755 | return promise;
756 | }
757 |
758 | function needsResolver() {
759 | throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
760 | }
761 |
762 | function needsNew() {
763 | throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
764 | }
765 |
766 | /**
767 | Promise objects represent the eventual result of an asynchronous operation. The
768 | primary way of interacting with a promise is through its `then` method, which
769 | registers callbacks to receive either a promise's eventual value or the reason
770 | why the promise cannot be fulfilled.
771 |
772 | Terminology
773 | -----------
774 |
775 | - `promise` is an object or function with a `then` method whose behavior conforms to this specification.
776 | - `thenable` is an object or function that defines a `then` method.
777 | - `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
778 | - `exception` is a value that is thrown using the throw statement.
779 | - `reason` is a value that indicates why a promise was rejected.
780 | - `settled` the final resting state of a promise, fulfilled or rejected.
781 |
782 | A promise can be in one of three states: pending, fulfilled, or rejected.
783 |
784 | Promises that are fulfilled have a fulfillment value and are in the fulfilled
785 | state. Promises that are rejected have a rejection reason and are in the
786 | rejected state. A fulfillment value is never a thenable.
787 |
788 | Promises can also be said to *resolve* a value. If this value is also a
789 | promise, then the original promise's settled state will match the value's
790 | settled state. So a promise that *resolves* a promise that rejects will
791 | itself reject, and a promise that *resolves* a promise that fulfills will
792 | itself fulfill.
793 |
794 |
795 | Basic Usage:
796 | ------------
797 |
798 | ```js
799 | let promise = new Promise(function(resolve, reject) {
800 | // on success
801 | resolve(value);
802 |
803 | // on failure
804 | reject(reason);
805 | });
806 |
807 | promise.then(function(value) {
808 | // on fulfillment
809 | }, function(reason) {
810 | // on rejection
811 | });
812 | ```
813 |
814 | Advanced Usage:
815 | ---------------
816 |
817 | Promises shine when abstracting away asynchronous interactions such as
818 | `XMLHttpRequest`s.
819 |
820 | ```js
821 | function getJSON(url) {
822 | return new Promise(function(resolve, reject){
823 | let xhr = new XMLHttpRequest();
824 |
825 | xhr.open('GET', url);
826 | xhr.onreadystatechange = handler;
827 | xhr.responseType = 'json';
828 | xhr.setRequestHeader('Accept', 'application/json');
829 | xhr.send();
830 |
831 | function handler() {
832 | if (this.readyState === this.DONE) {
833 | if (this.status === 200) {
834 | resolve(this.response);
835 | } else {
836 | reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
837 | }
838 | }
839 | };
840 | });
841 | }
842 |
843 | getJSON('/posts.json').then(function(json) {
844 | // on fulfillment
845 | }, function(reason) {
846 | // on rejection
847 | });
848 | ```
849 |
850 | Unlike callbacks, promises are great composable primitives.
851 |
852 | ```js
853 | Promise.all([
854 | getJSON('/posts'),
855 | getJSON('/comments')
856 | ]).then(function(values){
857 | values[0] // => postsJSON
858 | values[1] // => commentsJSON
859 |
860 | return values;
861 | });
862 | ```
863 |
864 | @class Promise
865 | @param {function} resolver
866 | Useful for tooling.
867 | @constructor
868 | */
869 | function Promise(resolver) {
870 | this[PROMISE_ID] = nextId();
871 | this._result = this._state = undefined;
872 | this._subscribers = [];
873 |
874 | if (noop !== resolver) {
875 | typeof resolver !== 'function' && needsResolver();
876 | this instanceof Promise ? initializePromise(this, resolver) : needsNew();
877 | }
878 | }
879 |
880 | Promise.all = all;
881 | Promise.race = race;
882 | Promise.resolve = resolve;
883 | Promise.reject = reject;
884 | Promise._setScheduler = setScheduler;
885 | Promise._setAsap = setAsap;
886 | Promise._asap = asap;
887 |
888 | Promise.prototype = {
889 | constructor: Promise,
890 |
891 | /**
892 | The primary way of interacting with a promise is through its `then` method,
893 | which registers callbacks to receive either a promise's eventual value or the
894 | reason why the promise cannot be fulfilled.
895 |
896 | ```js
897 | findUser().then(function(user){
898 | // user is available
899 | }, function(reason){
900 | // user is unavailable, and you are given the reason why
901 | });
902 | ```
903 |
904 | Chaining
905 | --------
906 |
907 | The return value of `then` is itself a promise. This second, 'downstream'
908 | promise is resolved with the return value of the first promise's fulfillment
909 | or rejection handler, or rejected if the handler throws an exception.
910 |
911 | ```js
912 | findUser().then(function (user) {
913 | return user.name;
914 | }, function (reason) {
915 | return 'default name';
916 | }).then(function (userName) {
917 | // If `findUser` fulfilled, `userName` will be the user's name, otherwise it
918 | // will be `'default name'`
919 | });
920 |
921 | findUser().then(function (user) {
922 | throw new Error('Found user, but still unhappy');
923 | }, function (reason) {
924 | throw new Error('`findUser` rejected and we're unhappy');
925 | }).then(function (value) {
926 | // never reached
927 | }, function (reason) {
928 | // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
929 | // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
930 | });
931 | ```
932 | If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
933 |
934 | ```js
935 | findUser().then(function (user) {
936 | throw new PedagogicalException('Upstream error');
937 | }).then(function (value) {
938 | // never reached
939 | }).then(function (value) {
940 | // never reached
941 | }, function (reason) {
942 | // The `PedgagocialException` is propagated all the way down to here
943 | });
944 | ```
945 |
946 | Assimilation
947 | ------------
948 |
949 | Sometimes the value you want to propagate to a downstream promise can only be
950 | retrieved asynchronously. This can be achieved by returning a promise in the
951 | fulfillment or rejection handler. The downstream promise will then be pending
952 | until the returned promise is settled. This is called *assimilation*.
953 |
954 | ```js
955 | findUser().then(function (user) {
956 | return findCommentsByAuthor(user);
957 | }).then(function (comments) {
958 | // The user's comments are now available
959 | });
960 | ```
961 |
962 | If the assimliated promise rejects, then the downstream promise will also reject.
963 |
964 | ```js
965 | findUser().then(function (user) {
966 | return findCommentsByAuthor(user);
967 | }).then(function (comments) {
968 | // If `findCommentsByAuthor` fulfills, we'll have the value here
969 | }, function (reason) {
970 | // If `findCommentsByAuthor` rejects, we'll have the reason here
971 | });
972 | ```
973 |
974 | Simple Example
975 | --------------
976 |
977 | Synchronous Example
978 |
979 | ```javascript
980 | let result;
981 |
982 | try {
983 | result = findResult();
984 | // success
985 | } catch(reason) {
986 | // failure
987 | }
988 | ```
989 |
990 | Errback Example
991 |
992 | ```js
993 | findResult(function(result, err){
994 | if (err) {
995 | // failure
996 | } else {
997 | // success
998 | }
999 | });
1000 | ```
1001 |
1002 | Promise Example;
1003 |
1004 | ```javascript
1005 | findResult().then(function(result){
1006 | // success
1007 | }, function(reason){
1008 | // failure
1009 | });
1010 | ```
1011 |
1012 | Advanced Example
1013 | --------------
1014 |
1015 | Synchronous Example
1016 |
1017 | ```javascript
1018 | let author, books;
1019 |
1020 | try {
1021 | author = findAuthor();
1022 | books = findBooksByAuthor(author);
1023 | // success
1024 | } catch(reason) {
1025 | // failure
1026 | }
1027 | ```
1028 |
1029 | Errback Example
1030 |
1031 | ```js
1032 |
1033 | function foundBooks(books) {
1034 |
1035 | }
1036 |
1037 | function failure(reason) {
1038 |
1039 | }
1040 |
1041 | findAuthor(function(author, err){
1042 | if (err) {
1043 | failure(err);
1044 | // failure
1045 | } else {
1046 | try {
1047 | findBoooksByAuthor(author, function(books, err) {
1048 | if (err) {
1049 | failure(err);
1050 | } else {
1051 | try {
1052 | foundBooks(books);
1053 | } catch(reason) {
1054 | failure(reason);
1055 | }
1056 | }
1057 | });
1058 | } catch(error) {
1059 | failure(err);
1060 | }
1061 | // success
1062 | }
1063 | });
1064 | ```
1065 |
1066 | Promise Example;
1067 |
1068 | ```javascript
1069 | findAuthor().
1070 | then(findBooksByAuthor).
1071 | then(function(books){
1072 | // found books
1073 | }).catch(function(reason){
1074 | // something went wrong
1075 | });
1076 | ```
1077 |
1078 | @method then
1079 | @param {Function} onFulfilled
1080 | @param {Function} onRejected
1081 | Useful for tooling.
1082 | @return {Promise}
1083 | */
1084 | then: then,
1085 |
1086 | /**
1087 | `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
1088 | as the catch block of a try/catch statement.
1089 |
1090 | ```js
1091 | function findAuthor(){
1092 | throw new Error('couldn't find that author');
1093 | }
1094 |
1095 | // synchronous
1096 | try {
1097 | findAuthor();
1098 | } catch(reason) {
1099 | // something went wrong
1100 | }
1101 |
1102 | // async with promises
1103 | findAuthor().catch(function(reason){
1104 | // something went wrong
1105 | });
1106 | ```
1107 |
1108 | @method catch
1109 | @param {Function} onRejection
1110 | Useful for tooling.
1111 | @return {Promise}
1112 | */
1113 | 'catch': function _catch(onRejection) {
1114 | return this.then(null, onRejection);
1115 | }
1116 | };
1117 |
1118 | function polyfill() {
1119 | var local = undefined;
1120 |
1121 | if (typeof global !== 'undefined') {
1122 | local = global;
1123 | } else if (typeof self !== 'undefined') {
1124 | local = self;
1125 | } else {
1126 | try {
1127 | local = Function('return this')();
1128 | } catch (e) {
1129 | throw new Error('polyfill failed because global object is unavailable in this environment');
1130 | }
1131 | }
1132 |
1133 | var P = local.Promise;
1134 |
1135 | if (P) {
1136 | var promiseToString = null;
1137 | try {
1138 | promiseToString = Object.prototype.toString.call(P.resolve());
1139 | } catch (e) {
1140 | // silently ignored
1141 | }
1142 |
1143 | if (promiseToString === '[object Promise]' && !P.cast) {
1144 | return;
1145 | }
1146 | }
1147 |
1148 | local.Promise = Promise;
1149 | }
1150 |
1151 | // Strange compat..
1152 | Promise.polyfill = polyfill;
1153 | Promise.Promise = Promise;
1154 |
1155 | Promise.polyfill();
1156 |
1157 | return Promise;
1158 |
1159 | })));
1160 | //# sourceMappingURL=es6-promise.auto.map
1161 |
--------------------------------------------------------------------------------
/test/extension-test.js:
--------------------------------------------------------------------------------
1 | /*global describe, specify, it, assert */
2 |
3 | if (typeof Object.getPrototypeOf !== "function") {
4 | Object.getPrototypeOf = "".__proto__ === String.prototype
5 | ? function (object) {
6 | return object.__proto__;
7 | }
8 | : function (object) {
9 | // May break if the constructor has been tampered with
10 | return object.constructor.prototype;
11 | };
12 | }
13 |
14 | function keysOf(object) {
15 | var results = [];
16 |
17 | for (var key in object) {
18 | if (object.hasOwnProperty(key)) {
19 | results.push(key);
20 | }
21 | }
22 |
23 | return results;
24 | }
25 |
26 | var g = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : this;
27 | var Promise = g.adapter.Promise;
28 | var assert = require('assert');
29 |
30 | function objectEquals(obj1, obj2) {
31 | for (var i in obj1) {
32 | if (obj1.hasOwnProperty(i)) {
33 | if (!obj2.hasOwnProperty(i)) return false;
34 | if (obj1[i] != obj2[i]) return false;
35 | }
36 | }
37 | for (var i in obj2) {
38 | if (obj2.hasOwnProperty(i)) {
39 | if (!obj1.hasOwnProperty(i)) return false;
40 | if (obj1[i] != obj2[i]) return false;
41 | }
42 | }
43 | return true;
44 | }
45 | describe('tampering', function() {
46 | var resolve = Promise.resolve;
47 |
48 | afterEach(function() {
49 | Promise.resolve = resolve;
50 | });
51 |
52 | describe('then assimilation', function() {
53 | it('tampered resolved and then', function() {
54 | var one = Promise.resolve(1);
55 | var two = Promise.resolve(2);
56 | var thenCalled = 0;
57 | var resolveCalled = 0;
58 |
59 | two.then = function() {
60 | thenCalled++;
61 | return Promise.prototype.then.apply(this, arguments);
62 | };
63 |
64 | Promise.resolve = function(x) {
65 | resolveCalled++;
66 | return new Promise(function(resolve) { resolve(x); });
67 | };
68 |
69 | return one.then(function() {
70 | return two;
71 | }).then(function(value) {
72 | assert.equal(thenCalled, 1, 'expected then to be called once');
73 | assert.equal(resolveCalled, 0, 'expected resolve to be called once');
74 | assert.equal(value, 2, 'expected fulfillment value to be 2');
75 | });
76 | });
77 |
78 | it('tampered resolved', function() {
79 | var one = Promise.resolve(1);
80 | var two = Promise.resolve(2);
81 | var thenCalled = 0;
82 | var resolveCalled = 0;
83 |
84 | Promise.resolve = function(x) {
85 | resolveCalled++;
86 | return new Promise(function(resolve) { resolve(x); });
87 | };
88 |
89 | return one.then(function() {
90 | return two;
91 | }).then(function(value) {
92 | assert.equal(resolveCalled, 0, 'expected resolve to be called once');
93 | assert.equal(value, 2, 'expected fulfillment value to be 2');
94 | });
95 | });
96 |
97 | describe('alternative constructor', function() {
98 | it('tampered resolved and then', function() {
99 | var one = Promise.resolve(1);
100 | var two = Promise.resolve(2);
101 | var thenCalled = 0;
102 | var resolveCalled = 0;
103 | var invokedAlternativeConstructor = 0;
104 |
105 | two.then = function() {
106 | thenCalled++;
107 | return Promise.prototype.then.apply(this, arguments);
108 | };
109 |
110 | function AlternativeConstructor(executor) {
111 | invokedAlternativeConstructor++;
112 | var followers = this.followers = [];
113 | executor(function(value) {
114 | followers.forEach(function(onFulfillment) {
115 | onFulfillment(value)
116 | });
117 | }, function() {
118 | throw TypeError('No Rejections supported');
119 | });
120 | }
121 |
122 | AlternativeConstructor.resolve = function(x) {
123 | resolveCalled++;
124 | return new Promise(function(resolve) { resolve(x); });
125 | };
126 |
127 | AlternativeConstructor.prototype.then = function(onFulfillment, onRejection) {
128 | this.followers.push(onFulfillment);
129 | };
130 |
131 | AlternativeConstructor.resolve = function(x) {
132 | resolveCalled++;
133 | return new Promise(function(resolve) { resolve(x); });
134 | };
135 |
136 | one.constructor = AlternativeConstructor
137 |
138 | return one.then(function() {
139 | return two;
140 | }).then(function(value) {
141 |
142 | assert.equal(invokedAlternativeConstructor, 1, 'expected AlternativeConstructor to be invoked once');
143 | assert.equal(thenCalled, 1, 'expected then to be called once');
144 | assert.equal(resolveCalled, 0, 'expected resolve to be called once');
145 | assert.equal(value, 2, 'expected fulfillment value to be 2');
146 | });
147 | });
148 | });
149 |
150 | describe('Promise.all', function() {
151 | it('tampered resolved and then', function() {
152 | var two = Promise.resolve(2);
153 | var thenCalled = 0;
154 | var resolveCalled = 0;
155 |
156 | two.then = function() {
157 | thenCalled++;
158 | return Promise.prototype.then.apply(this, arguments);
159 | };
160 |
161 | Promise.resolve = function(x) {
162 | resolveCalled++;
163 | return new Promise(function(resolve) { resolve(x); });
164 | };
165 |
166 | return Promise.all([two]).then(function(value) {
167 | assert.equal(thenCalled, 1);
168 | assert.equal(resolveCalled, 1);
169 | assert.deepEqual(value, [2]);
170 | });
171 | });
172 |
173 | it('alternative constructor and tampered then', function() {
174 | var two = Promise.resolve(2);
175 | var thenCalled = 0;
176 | var resolveCalled = 0;
177 |
178 | two.then = function() {
179 | thenCalled++;
180 | return Promise.prototype.then.apply(this, arguments);
181 | };
182 |
183 | function AlternativeConstructor(executor) {
184 | var followers = this.followers = [];
185 | executor(function(value) {
186 | followers.forEach(function(onFulfillment) {
187 | onFulfillment(value)
188 | });
189 | }, function() {
190 | throw TypeError('No Rejections supported');
191 | });
192 | }
193 |
194 | AlternativeConstructor.resolve = function(x) {
195 | resolveCalled++;
196 | return new Promise(function(resolve) { resolve(x); });
197 | };
198 |
199 | AlternativeConstructor.prototype.then = function(onFulfillment, onRejection) {
200 | this.followers.push(onFulfillment);
201 | };
202 |
203 | return Promise.all.call(AlternativeConstructor, [two]).then(function(value) {
204 | assert.equal(thenCalled, 1);
205 | assert.equal(resolveCalled, 1);
206 | assert.deepEqual(value, [2]);
207 | });
208 | });
209 | });
210 |
211 | describe('core-js species test', function() {
212 | it('foreign thenable has correct internal slots', function() {
213 | var p = Promise.resolve();
214 |
215 | function NewConstructor(it) {
216 | it(function(){}, function(){})
217 | }
218 |
219 | p.constructor = NewConstructor;
220 |
221 | var f = p.then(function(){});
222 | assert(f instanceof NewConstructor);
223 | });
224 | });
225 | describe('Promise.race', function() {
226 | it('tampered resolved and then', function() {
227 | var two = Promise.resolve(2);
228 | var thenCalled = 0;
229 | var resolveCalled = 0;
230 |
231 | two.then = function() {
232 | thenCalled++;
233 | return Promise.prototype.then.apply(this, arguments);
234 | };
235 |
236 | Promise.resolve = function(x) {
237 | resolveCalled++;
238 | return new Promise(function(resolve) { resolve(x); });
239 | };
240 |
241 | return Promise.race([two]).then(function(value) {
242 | assert.equal(thenCalled, 1);
243 | assert.equal(resolveCalled, 1);
244 | assert.deepEqual(value, 2);
245 | });
246 | });
247 |
248 | it('alternative constructor and tampered then', function() {
249 | var two = Promise.resolve(2);
250 | var thenCalled = 0;
251 | var resolveCalled = 0;
252 |
253 | two.then = function() {
254 | thenCalled++;
255 | return Promise.prototype.then.apply(this, arguments);
256 | };
257 |
258 | function AlternativeConstructor(executor) {
259 | var followers = this.followers = [];
260 | executor(function(value) {
261 | followers.forEach(function(onFulfillment) {
262 | onFulfillment(value)
263 | });
264 | }, function() {
265 | throw TypeError('No Rejections supported');
266 | });
267 | }
268 |
269 | AlternativeConstructor.resolve = function(x) {
270 | resolveCalled++;
271 | return new Promise(function(resolve) { resolve(x); });
272 | };
273 |
274 | AlternativeConstructor.prototype.then = function(onFulfillment, onRejection) {
275 | this.followers.push(onFulfillment);
276 | };
277 |
278 | return Promise.race.call(AlternativeConstructor, [two]).then(function(value) {
279 | assert.equal(thenCalled, 1);
280 | assert.equal(resolveCalled, 1);
281 | assert.deepEqual(value, 2);
282 | });
283 | });
284 | });
285 |
286 | });
287 | });
288 |
289 | describe("extensions", function() {
290 | describe("Promise constructor", function() {
291 | it('should exist and have length 1', function() {
292 | assert(Promise);
293 | assert.equal(Promise.length, 1);
294 | });
295 |
296 | it('should fulfill if `resolve` is called with a value', function(done) {
297 | var promise = new Promise(function(resolve) { resolve('value'); });
298 |
299 | promise.then(function(value) {
300 | assert.equal(value, 'value');
301 | done();
302 | });
303 | });
304 |
305 | it('should reject if `reject` is called with a reason', function(done) {
306 | var promise = new Promise(function(resolve, reject) { reject('reason'); });
307 |
308 | promise.then(function() {
309 | assert(false);
310 | done();
311 | }, function(reason) {
312 | assert.equal(reason, 'reason');
313 | done();
314 | });
315 | });
316 |
317 | it('should be a constructor', function() {
318 | var promise = new Promise(function() {});
319 |
320 | assert.equal(Object.getPrototypeOf(promise), Promise.prototype, '[[Prototype]] equals Promise.prototype');
321 | assert.equal(promise.constructor, Promise, 'constructor property of instances is set correctly');
322 | assert.equal(Promise.prototype.constructor, Promise, 'constructor property of prototype is set correctly');
323 | });
324 |
325 | it('should NOT work without `new`', function() {
326 | assert.throws(function(){
327 | Promise(function(resolve) { resolve('value'); });
328 | }, TypeError)
329 | });
330 |
331 | it('should throw a `TypeError` if not given a function', function() {
332 | assert.throws(function () {
333 | new Promise();
334 | }, TypeError);
335 |
336 | assert.throws(function () {
337 | new Promise({});
338 | }, TypeError);
339 |
340 | assert.throws(function () {
341 | new Promise('boo!');
342 | }, TypeError);
343 | });
344 |
345 | it('should reject on resolver exception', function(done) {
346 | new Promise(function() {
347 | throw 'error';
348 | }).then(null, function(e) {
349 | assert.equal(e, 'error');
350 | done();
351 | });
352 | });
353 |
354 | it('should not resolve multiple times', function(done) {
355 | var resolver, rejector, fulfilled = 0, rejected = 0;
356 | var thenable = {
357 | then: function(resolve, reject) {
358 | resolver = resolve;
359 | rejector = reject;
360 | }
361 | };
362 |
363 | var promise = new Promise(function(resolve) {
364 | resolve(1);
365 | });
366 |
367 | promise.then(function(value){
368 | return thenable;
369 | }).then(function(value){
370 | fulfilled++;
371 | }, function(reason) {
372 | rejected++;
373 | });
374 |
375 | setTimeout(function() {
376 | resolver(1);
377 | resolver(1);
378 | rejector(1);
379 | rejector(1);
380 |
381 | setTimeout(function() {
382 | assert.equal(fulfilled, 1);
383 | assert.equal(rejected, 0);
384 | done();
385 | }, 20);
386 | }, 20);
387 |
388 | });
389 |
390 | describe('assimilation', function() {
391 | it('should assimilate if `resolve` is called with a fulfilled promise', function(done) {
392 | var originalPromise = new Promise(function(resolve) { resolve('original value'); });
393 | var promise = new Promise(function(resolve) { resolve(originalPromise); });
394 |
395 | promise.then(function(value) {
396 | assert.equal(value, 'original value');
397 | done();
398 | });
399 | });
400 |
401 | it('should assimilate if `resolve` is called with a rejected promise', function(done) {
402 | var originalPromise = new Promise(function(resolve, reject) { reject('original reason'); });
403 | var promise = new Promise(function(resolve) { resolve(originalPromise); });
404 |
405 | promise.then(function() {
406 | assert(false);
407 | done();
408 | }, function(reason) {
409 | assert.equal(reason, 'original reason');
410 | done();
411 | });
412 | });
413 |
414 | it('should assimilate if `resolve` is called with a fulfilled thenable', function(done) {
415 | var originalThenable = {
416 | then: function (onFulfilled) {
417 | setTimeout(function() { onFulfilled('original value'); }, 0);
418 | }
419 | };
420 | var promise = new Promise(function(resolve) { resolve(originalThenable); });
421 |
422 | promise.then(function(value) {
423 | assert.equal(value, 'original value');
424 | done();
425 | });
426 | });
427 |
428 | it('should assimilate if `resolve` is called with a rejected thenable', function(done) {
429 | var originalThenable = {
430 | then: function (onFulfilled, onRejected) {
431 | setTimeout(function() { onRejected('original reason'); }, 0);
432 | }
433 | };
434 | var promise = new Promise(function(resolve) { resolve(originalThenable); });
435 |
436 | promise.then(function() {
437 | assert(false);
438 | done();
439 | }, function(reason) {
440 | assert.equal(reason, 'original reason');
441 | done();
442 | });
443 | });
444 |
445 |
446 | it('should assimilate two levels deep, for fulfillment of self fulfilling promises', function(done) {
447 | var originalPromise, promise;
448 | originalPromise = new Promise(function(resolve) {
449 | setTimeout(function() {
450 | resolve(originalPromise);
451 | }, 0)
452 | });
453 |
454 | promise = new Promise(function(resolve) {
455 | setTimeout(function() {
456 | resolve(originalPromise);
457 | }, 0);
458 | });
459 |
460 | promise.then(function(value) {
461 | assert(false);
462 | done();
463 | })['catch'](function(reason) {
464 | assert.equal(reason.message, "You cannot resolve a promise with itself");
465 | assert(reason instanceof TypeError);
466 | done();
467 | });
468 | });
469 |
470 | it('should assimilate two levels deep, for fulfillment', function(done) {
471 | var originalPromise = new Promise(function(resolve) { resolve('original value'); });
472 | var nextPromise = new Promise(function(resolve) { resolve(originalPromise); });
473 | var promise = new Promise(function(resolve) { resolve(nextPromise); });
474 |
475 | promise.then(function(value) {
476 | assert.equal(value, 'original value');
477 | done();
478 | });
479 | });
480 |
481 | it('should assimilate two levels deep, for rejection', function(done) {
482 | var originalPromise = new Promise(function(resolve, reject) { reject('original reason'); });
483 | var nextPromise = new Promise(function(resolve) { resolve(originalPromise); });
484 | var promise = new Promise(function(resolve) { resolve(nextPromise); });
485 |
486 | promise.then(function() {
487 | assert(false);
488 | done();
489 | }, function(reason) {
490 | assert.equal(reason, 'original reason');
491 | done();
492 | });
493 | });
494 |
495 | it('should assimilate three levels deep, mixing thenables and promises (fulfilled case)', function(done) {
496 | var originalPromise = new Promise(function(resolve) { resolve('original value'); });
497 | var intermediateThenable = {
498 | then: function (onFulfilled) {
499 | setTimeout(function() { onFulfilled(originalPromise); }, 0);
500 | }
501 | };
502 | var promise = new Promise(function(resolve) { resolve(intermediateThenable); });
503 |
504 | promise.then(function(value) {
505 | assert.equal(value, 'original value');
506 | done();
507 | });
508 | });
509 |
510 | it('should assimilate three levels deep, mixing thenables and promises (rejected case)', function(done) {
511 | var originalPromise = new Promise(function(resolve, reject) { reject('original reason'); });
512 | var intermediateThenable = {
513 | then: function (onFulfilled) {
514 | setTimeout(function() { onFulfilled(originalPromise); }, 0);
515 | }
516 | };
517 | var promise = new Promise(function(resolve) { resolve(intermediateThenable); });
518 |
519 | promise.then(function() {
520 | assert(false);
521 | done();
522 | }, function(reason) {
523 | assert.equal(reason, 'original reason');
524 | done();
525 | });
526 | });
527 | });
528 | });
529 |
530 | describe('Promise.all', function() {
531 | testAll(function(){
532 | return Promise.all.apply(Promise, arguments);
533 | });
534 | });
535 |
536 | function testAll(all) {
537 | it('should exist', function() {
538 | assert(all);
539 | });
540 |
541 | it('works with plan pojo input', function(done) {
542 | all([
543 | {}
544 | ]).then(function(result) {
545 | assert.deepEqual(result, [{}]);
546 | done();
547 | });
548 | });
549 |
550 | it('throws when not passed an array', function(done) {
551 | var nothing = assertRejection(all());
552 | var string = assertRejection(all(''));
553 | var object = assertRejection(all({}));
554 |
555 | Promise.all([
556 | nothing,
557 | string,
558 | object
559 | ]).then(function(){ done(); });
560 | });
561 |
562 | specify('fulfilled only after all of the other promises are fulfilled', function(done) {
563 | var firstResolved, secondResolved, firstResolver, secondResolver;
564 |
565 | var first = new Promise(function(resolve) {
566 | firstResolver = resolve;
567 | });
568 | first.then(function() {
569 | firstResolved = true;
570 | });
571 |
572 | var second = new Promise(function(resolve) {
573 | secondResolver = resolve;
574 | });
575 | second.then(function() {
576 | secondResolved = true;
577 | });
578 |
579 | setTimeout(function() {
580 | firstResolver(true);
581 | }, 0);
582 |
583 | setTimeout(function() {
584 | secondResolver(true);
585 | }, 0);
586 |
587 | all([first, second]).then(function() {
588 | assert(firstResolved);
589 | assert(secondResolved);
590 | done();
591 | });
592 | });
593 |
594 | specify('rejected as soon as a promise is rejected', function(done) {
595 | var firstResolver, secondResolver;
596 |
597 | var first = new Promise(function(resolve, reject) {
598 | firstResolver = { resolve: resolve, reject: reject };
599 | });
600 |
601 | var second = new Promise(function(resolve, reject) {
602 | secondResolver = { resolve: resolve, reject: reject };
603 | });
604 |
605 | setTimeout(function() {
606 | firstResolver.reject({});
607 | }, 0);
608 |
609 | var firstWasRejected, secondCompleted;
610 |
611 | first['catch'](function(){
612 | firstWasRejected = true;
613 | });
614 |
615 | second.then(function(){
616 | secondCompleted = true;
617 | }, function() {
618 | secondCompleted = true;
619 | });
620 |
621 | all([first, second]).then(function() {
622 | assert(false);
623 | }, function() {
624 | assert(firstWasRejected);
625 | assert(!secondCompleted);
626 | done();
627 | });
628 | });
629 |
630 | specify('passes the resolved values of each promise to the callback in the correct order', function(done) {
631 | var firstResolver, secondResolver, thirdResolver;
632 |
633 | var first = new Promise(function(resolve, reject) {
634 | firstResolver = { resolve: resolve, reject: reject };
635 | });
636 |
637 | var second = new Promise(function(resolve, reject) {
638 | secondResolver = { resolve: resolve, reject: reject };
639 | });
640 |
641 | var third = new Promise(function(resolve, reject) {
642 | thirdResolver = { resolve: resolve, reject: reject };
643 | });
644 |
645 | thirdResolver.resolve(3);
646 | firstResolver.resolve(1);
647 | secondResolver.resolve(2);
648 |
649 | all([first, second, third]).then(function(results) {
650 | assert(results.length === 3);
651 | assert(results[0] === 1);
652 | assert(results[1] === 2);
653 | assert(results[2] === 3);
654 | done();
655 | });
656 | });
657 |
658 | specify('resolves an empty array passed to all()', function(done) {
659 | all([]).then(function(results) {
660 | assert(results.length === 0);
661 | done();
662 | });
663 | });
664 |
665 | specify('works with null', function(done) {
666 | all([null]).then(function(results) {
667 | assert.equal(results[0], null);
668 | done();
669 | });
670 | });
671 |
672 | specify('works with a mix of promises and thenables and non-promises', function(done) {
673 | var promise = new Promise(function(resolve) { resolve(1); });
674 | var syncThenable = { then: function (onFulfilled) { onFulfilled(2); } };
675 | var asyncThenable = { then: function (onFulfilled) { setTimeout(function() { onFulfilled(3); }, 0); } };
676 | var nonPromise = 4;
677 |
678 | all([promise, syncThenable, asyncThenable, nonPromise]).then(function(results) {
679 | assert(objectEquals(results, [1, 2, 3, 4]));
680 | done();
681 | })['catch'](done);
682 | });
683 | }
684 |
685 | describe("reject", function(){
686 | specify("it should exist", function(){
687 | assert(Promise.reject);
688 | });
689 |
690 | describe('it rejects', function(){
691 | var reason = 'the reason',
692 | promise = Promise.reject(reason);
693 |
694 | promise.then(function(){
695 | assert(false, 'should not fulfill');
696 | }, function(actualReason){
697 | assert.equal(reason, actualReason);
698 | });
699 | });
700 | });
701 |
702 | function assertRejection(promise) {
703 | return promise.then(function(){
704 | assert(false, 'expected rejection, but got fulfillment');
705 | }, function(reason){
706 | assert(reason instanceof Error);
707 | });
708 | }
709 |
710 | describe('race', function() {
711 | it("should exist", function() {
712 | assert(Promise.race);
713 | });
714 |
715 | it("throws when not passed an array", function(done) {
716 | var nothing = assertRejection(Promise.race());
717 | var string = assertRejection(Promise.race(''));
718 | var object = assertRejection(Promise.race({}));
719 |
720 | Promise.all([
721 | nothing,
722 | string,
723 | object
724 | ]).then(function(){ done(); });
725 | });
726 |
727 | specify('fulfilled after one of the other promises are fulfilled', function(done) {
728 | var firstResolved, secondResolved, firstResolver, secondResolver;
729 |
730 | var first = new Promise(function(resolve) {
731 | firstResolver = resolve;
732 | });
733 | first.then(function() {
734 | firstResolved = true;
735 | });
736 |
737 | var second = new Promise(function(resolve) {
738 | secondResolver = resolve;
739 | });
740 | second.then(function() {
741 | secondResolved = true;
742 | });
743 |
744 | setTimeout(function() {
745 | firstResolver(true);
746 | }, 100);
747 |
748 | setTimeout(function() {
749 | secondResolver(true);
750 | }, 0);
751 |
752 | Promise.race([first, second]).then(function() {
753 | assert(secondResolved);
754 | assert.equal(firstResolved, undefined);
755 | done();
756 | });
757 | });
758 |
759 | specify('the race begins on nextTurn and prioritized by array entry', function(done) {
760 | var firstResolver, secondResolver, nonPromise = 5;
761 |
762 | var first = new Promise(function(resolve, reject) {
763 | resolve(true);
764 | });
765 |
766 | var second = new Promise(function(resolve, reject) {
767 | resolve(false);
768 | });
769 |
770 | Promise.race([first, second, nonPromise]).then(function(value) {
771 | assert.equal(value, true);
772 | done();
773 | });
774 | });
775 |
776 | specify('rejected as soon as a promise is rejected', function(done) {
777 | var firstResolver, secondResolver;
778 |
779 | var first = new Promise(function(resolve, reject) {
780 | firstResolver = { resolve: resolve, reject: reject };
781 | });
782 |
783 | var second = new Promise(function(resolve, reject) {
784 | secondResolver = { resolve: resolve, reject: reject };
785 | });
786 |
787 | setTimeout(function() {
788 | firstResolver.reject({});
789 | }, 0);
790 |
791 | var firstWasRejected, secondCompleted;
792 |
793 | first['catch'](function(){
794 | firstWasRejected = true;
795 | });
796 |
797 | second.then(function(){
798 | secondCompleted = true;
799 | }, function() {
800 | secondCompleted = true;
801 | });
802 |
803 | Promise.race([first, second]).then(function() {
804 | assert(false);
805 | }, function() {
806 | assert(firstWasRejected);
807 | assert(!secondCompleted);
808 | done();
809 | });
810 | });
811 |
812 | specify('resolves an empty array to forever pending Promise', function(done) {
813 | var foreverPendingPromise = Promise.race([]),
814 | wasSettled = false;
815 |
816 | foreverPendingPromise.then(function() {
817 | wasSettled = true;
818 | }, function() {
819 | wasSettled = true;
820 | });
821 |
822 | setTimeout(function() {
823 | assert(!wasSettled);
824 | done();
825 | }, 50);
826 | });
827 |
828 | specify('works with a mix of promises and thenables', function(done) {
829 | var promise = new Promise(function(resolve) { setTimeout(function() { resolve(1); }, 10); }),
830 | syncThenable = { then: function (onFulfilled) { onFulfilled(2); } };
831 |
832 | Promise.race([promise, syncThenable]).then(function(result) {
833 | assert(result, 2);
834 | done();
835 | });
836 | });
837 |
838 | specify('works with a mix of thenables and non-promises', function (done) {
839 | var asyncThenable = { then: function (onFulfilled) { setTimeout(function() { onFulfilled(3); }, 0); } },
840 | nonPromise = 4;
841 |
842 | Promise.race([asyncThenable, nonPromise]).then(function(result) {
843 | assert(result, 4);
844 | done();
845 | });
846 | });
847 | });
848 |
849 | describe("resolve", function(){
850 | specify("it should exist", function(){
851 | assert(Promise.resolve);
852 | });
853 |
854 | describe("1. If x is a promise, adopt its state ", function(){
855 | specify("1.1 If x is pending, promise must remain pending until x is fulfilled or rejected.", function(done){
856 | var expectedValue, resolver, thenable, wrapped;
857 |
858 | expectedValue = 'the value';
859 | thenable = {
860 | then: function(resolve, reject){
861 | resolver = resolve;
862 | }
863 | };
864 |
865 | wrapped = Promise.resolve(thenable);
866 |
867 | wrapped.then(function(value){
868 | assert(value === expectedValue);
869 | done();
870 | });
871 |
872 | setTimeout(function(){
873 | resolver(expectedValue);
874 | }, 10);
875 | });
876 |
877 | specify("1.2 If/when x is fulfilled, fulfill promise with the same value.", function(done){
878 | var expectedValue, thenable, wrapped;
879 |
880 | expectedValue = 'the value';
881 | thenable = {
882 | then: function(resolve, reject){
883 | resolve(expectedValue);
884 | }
885 | };
886 |
887 | wrapped = Promise.resolve(thenable);
888 |
889 | wrapped.then(function(value){
890 | assert(value === expectedValue);
891 | done();
892 | })
893 | });
894 |
895 | specify("1.3 If/when x is rejected, reject promise with the same reason.", function(done){
896 | var expectedError, thenable, wrapped;
897 |
898 | expectedError = new Error();
899 | thenable = {
900 | then: function(resolve, reject){
901 | reject(expectedError);
902 | }
903 | };
904 |
905 | wrapped = Promise.resolve(thenable);
906 |
907 | wrapped.then(null, function(error){
908 | assert(error === expectedError);
909 | done();
910 | });
911 | });
912 | });
913 |
914 | describe("2. Otherwise, if x is an object or function,", function(){
915 | specify("2.1 Let then x.then", function(done){
916 | var accessCount, resolver, wrapped, thenable;
917 |
918 | accessCount = 0;
919 | thenable = { };
920 |
921 | // we likely don't need to test this, if the browser doesn't support it
922 | if (typeof Object.defineProperty !== "function") { done(); return; }
923 |
924 | Object.defineProperty(thenable, 'then', {
925 | get: function(){
926 | accessCount++;
927 |
928 | if (accessCount > 1) {
929 | throw new Error();
930 | }
931 |
932 | return function(){ };
933 | }
934 | });
935 |
936 | assert(accessCount === 0);
937 |
938 | wrapped = Promise.resolve(thenable);
939 |
940 | assert(accessCount === 1);
941 |
942 | done();
943 | });
944 |
945 | specify("2.2 If retrieving the property x.then results in a thrown exception e, reject promise with e as the reason.", function(done){
946 | var wrapped, thenable, expectedError;
947 |
948 | expectedError = new Error();
949 | thenable = { };
950 |
951 | // we likely don't need to test this, if the browser doesn't support it
952 | if (typeof Object.defineProperty !== "function") { done(); return; }
953 |
954 | Object.defineProperty(thenable, 'then', {
955 | get: function(){
956 | throw expectedError;
957 | }
958 | });
959 |
960 | wrapped = Promise.resolve(thenable);
961 |
962 | wrapped.then(null, function(error){
963 | assert(error === expectedError, 'incorrect exception was thrown');
964 | done();
965 | });
966 | });
967 |
968 | describe('2.3. If then is a function, call it with x as this, first argument resolvePromise, and second argument rejectPromise, where', function(){
969 | specify('2.3.1 If/when resolvePromise is called with a value y, run Resolve(promise, y)', function(done){
970 | var expectedSuccess, resolver, rejector, thenable, wrapped, calledThis;
971 |
972 | thenable = {
973 | then: function(resolve, reject){
974 | calledThis = this;
975 | resolver = resolve;
976 | rejector = reject;
977 | }
978 | };
979 |
980 | expectedSuccess = 'success';
981 | wrapped = Promise.resolve(thenable);
982 |
983 | wrapped.then(function(success){
984 | assert(calledThis === thenable, 'this must be the thenable');
985 | assert(success === expectedSuccess, 'rejected promise with x');
986 | done();
987 | });
988 |
989 | setTimeout(function() {
990 | resolver(expectedSuccess);
991 | }, 20);
992 | });
993 |
994 | specify('2.3.2 If/when rejectPromise is called with a reason r, reject promise with r.', function(done){
995 | var expectedError, resolver, rejector, thenable, wrapped, calledThis;
996 |
997 | thenable = {
998 | then: function(resolve, reject){
999 | calledThis = this;
1000 | resolver = resolve;
1001 | rejector = reject;
1002 | }
1003 | };
1004 |
1005 | expectedError = new Error();
1006 |
1007 | wrapped = Promise.resolve(thenable);
1008 |
1009 | wrapped.then(null, function(error){
1010 | assert(error === expectedError, 'rejected promise with x');
1011 | done();
1012 | });
1013 |
1014 | setTimeout(function() {
1015 | rejector(expectedError);
1016 | }, 20);
1017 | });
1018 |
1019 | specify("2.3.3 If both resolvePromise and rejectPromise are called, or multiple calls to the same argument are made, the first call takes precedence, and any further calls are ignored", function(done){
1020 | var expectedError, expectedSuccess, resolver, rejector, thenable, wrapped, calledThis,
1021 | calledRejected, calledResolved;
1022 |
1023 | calledRejected = 0;
1024 | calledResolved = 0;
1025 |
1026 | thenable = {
1027 | then: function(resolve, reject){
1028 | calledThis = this;
1029 | resolver = resolve;
1030 | rejector = reject;
1031 | }
1032 | };
1033 |
1034 | expectedError = new Error();
1035 |
1036 | wrapped = Promise.resolve(thenable);
1037 |
1038 | wrapped.then(function(){
1039 | calledResolved++;
1040 | }, function(error){
1041 | calledRejected++;
1042 | assert(calledResolved === 0, 'never resolved');
1043 | assert(calledRejected === 1, 'rejected only once');
1044 | assert(error === expectedError, 'rejected promise with x');
1045 | });
1046 |
1047 | setTimeout(function() {
1048 | rejector(expectedError);
1049 | rejector(expectedError);
1050 |
1051 | rejector('foo');
1052 |
1053 | resolver('bar');
1054 | resolver('baz');
1055 | }, 20);
1056 |
1057 | setTimeout(function(){
1058 | assert(calledRejected === 1, 'only rejected once');
1059 | assert(calledResolved === 0, 'never resolved');
1060 | done();
1061 | }, 50);
1062 | });
1063 |
1064 | describe("2.3.4 If calling then throws an exception e", function(){
1065 | specify("2.3.4.1 If resolvePromise or rejectPromise have been called, ignore it.", function(done){
1066 | var expectedSuccess, resolver, rejector, thenable, wrapped, calledThis,
1067 | calledRejected, calledResolved;
1068 |
1069 | expectedSuccess = 'success';
1070 |
1071 | thenable = {
1072 | then: function(resolve, reject){
1073 | resolve(expectedSuccess);
1074 | throw expectedError;
1075 | }
1076 | };
1077 |
1078 | wrapped = Promise.resolve(thenable);
1079 |
1080 | wrapped.then(function(success){
1081 | assert(success === expectedSuccess, 'resolved not errored');
1082 | done();
1083 | });
1084 | });
1085 |
1086 | specify("2.3.4.2 Otherwise, reject promise with e as the reason.", function(done) {
1087 | var expectedError, resolver, rejector, thenable, wrapped, calledThis, callCount;
1088 |
1089 | expectedError = new Error();
1090 | callCount = 0;
1091 |
1092 | thenable = { then: function() { throw expectedError; } };
1093 |
1094 | wrapped = Promise.resolve(thenable);
1095 |
1096 | wrapped.then(null, function(error){
1097 | callCount++;
1098 | assert(expectedError === error, 'expected the correct error to be rejected');
1099 | done();
1100 | });
1101 |
1102 | assert(callCount === 0, 'expected async, was sync');
1103 | });
1104 | });
1105 | });
1106 |
1107 | specify("2.4 If then is not a function, fulfill promise with x", function(done){
1108 | var expectedError, resolver, rejector, thenable, wrapped, calledThis, callCount;
1109 |
1110 | thenable = { then: 3 };
1111 | callCount = 0;
1112 | wrapped = Promise.resolve(thenable);
1113 |
1114 | wrapped.then(function(success){
1115 | callCount++;
1116 | assert(thenable === success, 'fulfilled promise with x');
1117 | done();
1118 | });
1119 |
1120 | assert(callCount === 0, 'expected async, was sync');
1121 | });
1122 | });
1123 |
1124 | describe("3. If x is not an object or function, ", function(){
1125 | specify("fulfill promise with x.", function(done){
1126 | var thenable, callCount, wrapped;
1127 |
1128 | thenable = null;
1129 | callCount = 0;
1130 | wrapped = Promise.resolve(thenable);
1131 |
1132 | wrapped.then(function(success){
1133 | callCount++;
1134 | assert(success === thenable, 'fulfilled promise with x');
1135 | done();
1136 | }, function(a){
1137 | assert(false, 'should not also reject');
1138 | });
1139 |
1140 | assert(callCount === 0, 'expected async, was sync');
1141 | });
1142 | });
1143 | });
1144 |
1145 | if (typeof Worker !== 'undefined' && navigator.userAgent.indexOf('PhantomJS') < 1) {
1146 | describe('web worker', function () {
1147 | it('should work', function (done) {
1148 | this.timeout(2000);
1149 | var worker = new Worker('./worker.js');
1150 | worker.addEventListener('error', function(reason) {
1151 | done(new Error("Test failed:" + reason));
1152 | });
1153 | worker.addEventListener('message', function (e) {
1154 | worker.terminate();
1155 | assert.equal(e.data, 'pong');
1156 | done();
1157 | });
1158 | worker.postMessage('ping');
1159 | });
1160 | });
1161 | }
1162 | });
1163 |
1164 | // thanks to @wizardwerdna for the test case -> https://github.com/tildeio/rsvp.js/issues/66
1165 | // Only run these tests in node (phantomjs cannot handle them)
1166 | if (typeof module !== 'undefined' && module.exports) {
1167 |
1168 | describe("using reduce to sum integers using promises", function(){
1169 | it("should build the promise pipeline without error", function(){
1170 | var array, iters, pZero, i;
1171 |
1172 | array = [];
1173 | iters = 1000;
1174 |
1175 | for (i=1; i<=iters; i++) {
1176 | array.push(i);
1177 | }
1178 |
1179 | pZero = Promise.resolve(0);
1180 |
1181 | array.reduce(function(promise, nextVal) {
1182 | return promise.then(function(currentVal) {
1183 | return Promise.resolve(currentVal + nextVal);
1184 | });
1185 | }, pZero);
1186 | });
1187 |
1188 | it("should get correct answer without blowing the nextTick stack", function(done){
1189 | var pZero, array, iters, result, i;
1190 |
1191 | pZero = Promise.resolve(0);
1192 |
1193 | array = [];
1194 | iters = 1000;
1195 |
1196 | for (i=1; i<=iters; i++) {
1197 | array.push(i);
1198 | }
1199 |
1200 | result = array.reduce(function(promise, nextVal) {
1201 | return promise.then(function(currentVal) {
1202 | return Promise.resolve(currentVal + nextVal);
1203 | });
1204 | }, pZero);
1205 |
1206 | result.then(function(value){
1207 | assert.equal(value, (iters*(iters+1)/2));
1208 | done();
1209 | });
1210 | });
1211 | });
1212 | }
1213 |
1214 | // Kudos to @Octane at https://github.com/getify/native-promise-only/issues/5 for this, and @getify for pinging me.
1215 | describe("Thenables should not be able to run code during assimilation", function () {
1216 | specify("resolving to a thenable", function () {
1217 | var thenCalled = false;
1218 | var thenable = {
1219 | then: function () {
1220 | thenCalled = true;
1221 | }
1222 | };
1223 |
1224 | Promise.resolve(thenable);
1225 | assert.strictEqual(thenCalled, false);
1226 | });
1227 |
1228 | specify("resolving to an evil promise", function () {
1229 | var thenCalled = false;
1230 | var evilPromise = Promise.resolve();
1231 | evilPromise.then = function () {
1232 | thenCalled = true;
1233 | };
1234 |
1235 | Promise.resolve(evilPromise);
1236 | assert.strictEqual(thenCalled, false);
1237 | });
1238 | });
1239 |
--------------------------------------------------------------------------------