├── .eslintrc
├── .gitignore
├── .jshintrc
├── .release.json
├── .spmignore
├── .travis.yml
├── Brocfile.js
├── CHANGELOG.md
├── LICENSE
├── README.md
├── auto.js
├── config
└── versionTemplate.txt
├── es6-promise.d.ts
├── lib
├── es6-promise.auto.js
├── es6-promise.js
└── es6-promise
│ ├── -internal.js
│ ├── asap.js
│ ├── enumerator.js
│ ├── polyfill.js
│ ├── promise.js
│ ├── promise
│ ├── all.js
│ ├── race.js
│ ├── reject.js
│ └── resolve.js
│ ├── then.js
│ └── utils.js
├── package.json
├── server
├── .jshintrc
└── index.js
├── test
├── extension-test.js
├── index.html
├── index.js
├── scheduler-test.js
├── test-adapter.js
└── worker.js
├── testem.js
├── vendor
└── loader.js
└── yarn.lock
/.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 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /promises_tests
3 | /main.js
4 | /tmp
5 | /docs
6 | /dist
7 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "9"
4 | - "8"
5 | - "6"
6 | - "4"
7 |
8 | before_install:
9 | - nvm install 6
10 | - nvm use 6
11 | - export PATH=/usr/local/phantomjs-2.0.0/bin:$PATH
12 |
13 | before_script:
14 | - nvm use $TRAVIS_NODE_VERSION
15 | env:
16 | global:
17 | - EMBER_ENV=production
18 |
--------------------------------------------------------------------------------
/Brocfile.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint node:true, undef:true, unused:true */
4 | const Rollup = require('broccoli-rollup');
5 | const Babel = require('broccoli-babel-transpiler');
6 | const merge = require('broccoli-merge-trees');
7 | const uglify = require('broccoli-uglify-js');
8 | const version = require('git-repo-version');
9 | const watchify = require('broccoli-watchify');
10 | const concat = require('broccoli-concat');
11 | const fs = require('fs');
12 |
13 | const stew = require('broccoli-stew');
14 |
15 | const find = stew.find;
16 | const mv = stew.mv;
17 | const rename = stew.rename;
18 | const env = stew.env;
19 | const map = stew.map;
20 |
21 | const lib = find('lib');
22 |
23 | // test stuff
24 | const testDir = find('test');
25 | const testFiles = find('test/{index.html,worker.js}');
26 |
27 | const json3 = mv(find('node_modules/json3/lib/{json3.js}'), 'node_modules/json3/lib/', 'test/');
28 | // mocha doesn't browserify correctly
29 | const mocha = mv(find('node_modules/mocha/mocha.{js,css}'), 'node_modules/mocha/', 'test/');
30 |
31 | const testVendor = merge([ json3, mocha ]);
32 |
33 |
34 | const es5 = new Babel(lib, {
35 | plugins: [
36 | 'transform-es2015-arrow-functions',
37 | 'transform-es2015-computed-properties',
38 | 'transform-es2015-shorthand-properties',
39 | 'transform-es2015-template-literals',
40 | 'transform-es2015-parameters',
41 | 'transform-es2015-destructuring',
42 | 'transform-es2015-spread',
43 | 'transform-es2015-block-scoping',
44 | 'transform-es2015-constants',
45 | ['transform-es2015-classes', { loose: true }],
46 | 'babel6-plugin-strip-class-callcheck'
47 | ]
48 | });
49 |
50 | function rollupConfig(entry) {
51 | return new Rollup(es5, {
52 | rollup: {
53 | input: 'lib/' + entry,
54 | output: [
55 | {
56 | format: 'umd',
57 | name: 'ES6Promise',
58 | file: entry,
59 | sourcemap: 'inline'
60 | }
61 | ]
62 | }
63 | });
64 | }
65 |
66 | // build RSVP itself
67 | const es6Promise = rollupConfig('es6-promise.js')
68 | const es6PromiseAuto = rollupConfig('es6-promise.auto.js')
69 |
70 | const testBundle = watchify(merge([
71 | mv(es6Promise, 'test'),
72 | testDir
73 | ]), {
74 | browserify: { debug: true, entries: ['./test/index.js'] }
75 | });
76 |
77 | const header = stew.map(find('config/versionTemplate.txt'), content => content.replace(/VERSION_PLACEHOLDER_STRING/, version()));
78 |
79 | function concatAs(outputFile) {
80 | return merge([
81 | concat(merge([es6Promise, header]), {
82 | headerFiles: ['config/versionTemplate.txt'],
83 | inputFiles: ['es6-promise.js'],
84 | outputFile: outputFile
85 | }),
86 |
87 | concat(merge([es6PromiseAuto, header]), {
88 | headerFiles: ['config/versionTemplate.txt'],
89 | inputFiles: ['es6-promise.auto.js'],
90 | outputFile: outputFile.replace('es6-promise', 'es6-promise.auto'),
91 | }),
92 |
93 | ]);
94 | }
95 |
96 | function production() {
97 | let result;
98 | env('production', () => {
99 | result = uglify(concatAs('es6-promise.min.js'), {
100 | compress: true,
101 | mangle: true,
102 | });
103 | })
104 | return result;
105 | }
106 |
107 | function development() {
108 | return concatAs('es6-promise.js');
109 | }
110 |
111 | module.exports = merge([
112 | merge([
113 | production(),
114 | development(),
115 | ].filter(Boolean)),
116 | // test stuff
117 | testFiles,
118 | testVendor,
119 | mv(testBundle, 'test')
120 | ]);
121 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Master
2 |
3 | # 4.2.5
4 |
5 | * remove old try/catch performance hacks, modern runtimes do not require these tricks
6 |
7 | # 4.2.4
8 |
9 | * [Fixes #305] Confuse webpack
10 |
11 | # 4.2.3
12 |
13 | * Cleanup testem related build configuration
14 | * Use `prepublishOnly` instead of `prepublish` (thanks @rhysd)
15 | * Add Node.js 9, 8 to testing matrix
16 | * drop now unused s3 deployment files
17 | * internal cleanup (thanks to @bekzod, @mariusschulz)
18 | * Fixup Changelog
19 |
20 | # 4.2.2
21 |
22 | * Ensure PROMISE_ID works correctly
23 | * internal cleanup (thanks yo @mariusschulz)
24 |
25 | # 4.2.1
26 |
27 | * drop bower support
28 |
29 | # 4.2.0
30 |
31 | * drop `dist` from git repo
32 | * add `Promise.prototype.finally`
33 | * update various build related dependencies
34 | * add CDN links
35 |
36 | # 4.1.0
37 |
38 | * [BUGFIX] Fix memory leak [#269]
39 | * [BUGFIX] Auto Bundles within an AMD Environment [#263]
40 |
41 | # 4.0.5
42 |
43 | * fix require('es6-promise/auto') for Node < 4
44 |
45 | # 4.0.4
46 |
47 | * fix asap when using https://github.com/Kinvey/titanium-sdk
48 |
49 | # 4.0.3
50 |
51 | * fix Readme links
52 |
53 | # 4.0.2
54 |
55 | * fix require('es6-promise/auto');
56 |
57 | # 4.0.0
58 |
59 | * no longer polyfill automatically, if needed one can still invoke
60 | `require('es6-promise/auto')` directly.
61 |
62 | # 3.3.1
63 |
64 | * fix links in readme
65 |
66 | # 3.3.0
67 |
68 | * support polyfil on WebMAF (playstation env)
69 | * fix tampering related bug global `constructor` was referenced by mistake.
70 | * provide TS Typings
71 | * increase compatibliity with sinon.useFakeTimers();
72 | * update build tools (use rollup)
73 | * directly export promise;
74 |
75 | # 3.2.2
76 |
77 | * IE8: use isArray
78 | * update build dependencies
79 |
80 | # 3.2.1
81 |
82 | * fix race tampering issue
83 | * use eslint
84 | * fix Promise.all tampering
85 | * remove unused code
86 | * fix issues with NWJS/electron
87 |
88 | # 3.2.0
89 |
90 | * improve tamper resistence of Promise.all Promise.race and
91 | Promise.prototype.then (note, this isn't complete, but addresses an exception
92 | when used \w core-js, follow up work will address entirely)
93 | * remove spec incompatible then chaining fast-path
94 | * add eslint
95 | * update build deps
96 |
97 | # 3.1.2
98 |
99 | * fix node detection issues with NWJS/electron
100 |
101 | # 3.1.0
102 |
103 | * improve performance of Promise.all when it encounters a non-promise input object input
104 | * then/resolve tamper protection
105 | * reduce AST size of promise constructor, to facilitate more inlining
106 | * Update README.md with details about PhantomJS requirement for running tests
107 | * Mangle and compress the minified version
108 |
109 | # 3.0.2
110 |
111 | * correctly bump both bower and package.json versions
112 |
113 | # 3.0.1
114 |
115 | * no longer include dist/test in npm releases
116 |
117 | # 3.0.0
118 |
119 | * use nextTick() instead of setImmediate() to schedule microtasks with node 0.10. Later versions of
120 | nodes are not affected as they were already using nextTick(). Note that using nextTick() might
121 | trigger a depreciation warning on 0.10 as described at https://github.com/cujojs/when/issues/410.
122 | The reason why nextTick() is preferred is that is setImmediate() would schedule a macrotask
123 | instead of a microtask and might result in a different scheduling.
124 | If needed you can revert to the former behavior as follow:
125 |
126 | var Promise = require('es6-promise').Promise;
127 | Promise._setScheduler(setImmediate);
128 |
129 | # 2.3.0
130 |
131 | * #121: Ability to override the internal asap implementation
132 | * #120: Use an ascii character for an apostrophe, for source maps
133 |
134 | # 2.2.0
135 |
136 | * #116: Expose asap() and a way to override the scheduling mechanism on Promise
137 | * Lock to v0.2.3 of ember-cli
138 |
139 | # 2.1.1
140 |
141 | * Fix #100 via #105: tell browserify to ignore vertx require
142 | * Fix #101 via #102: "follow thenable state, not own state"
143 |
144 | # 2.1.0
145 |
146 | * #59: Automatic polyfill. No need to invoke `ES6Promise.polyfill()` anymore.
147 | * ... (see the commit log)
148 |
149 | # 2.0.0
150 |
151 | * re-sync with RSVP. Many large performance improvements and bugfixes.
152 |
153 | # 1.0.0
154 |
155 | * first subset of RSVP
156 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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://www.ecma-international.org/ecma-262/6.0/#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://cdn.jsdelivr.net/npm/es6-promise/dist/es6-promise.js)
10 | * [es6-promise-auto 27.78 KB (7.3 KB gzipped)](https://cdn.jsdelivr.net/npm/es6-promise/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://cdn.jsdelivr.net/npm/es6-promise/dist/es6-promise.min.js)
12 | * [es6-promise-auto-min 6.19 KB (2.4 KB gzipped)](https://cdn.jsdelivr.net/npm/es6-promise/dist/es6-promise.auto.min.js) - Minified version of `es6-promise-auto` above.
13 |
14 | ## CDN
15 |
16 | To use via a CDN include this in your html:
17 |
18 | ```html
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | ```
28 |
29 | ## Node.js
30 |
31 | To install:
32 |
33 | ```sh
34 | yarn add es6-promise
35 | ```
36 |
37 | or
38 |
39 | ```sh
40 | npm install es6-promise
41 | ```
42 |
43 | To use:
44 |
45 | ```js
46 | var Promise = require('es6-promise').Promise;
47 | ```
48 |
49 |
50 | ## Usage in IE<9
51 |
52 | `catch` and `finally` are reserved keywords in IE<9, meaning
53 | `promise.catch(func)` or `promise.finally(func)` throw a syntax error. To work
54 | around this, you can use a string to access the property as shown in the
55 | following example.
56 |
57 | However most minifiers will automatically fix this for you, making the
58 | resulting code safe for old browsers and production:
59 |
60 | ```js
61 | promise['catch'](function(err) {
62 | // ...
63 | });
64 | ```
65 |
66 | ```js
67 | promise['finally'](function() {
68 | // ...
69 | });
70 | ```
71 |
72 | ## Auto-polyfill
73 |
74 | To polyfill the global environment (either in Node or in the browser via CommonJS) use the following code snippet:
75 |
76 | ```js
77 | require('es6-promise').polyfill();
78 | ```
79 |
80 | Alternatively
81 |
82 | ```js
83 | require('es6-promise/auto');
84 | ```
85 |
86 | 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.
87 |
88 | ## Building & Testing
89 |
90 | You will need to have PhantomJS installed globally in order to run the tests.
91 |
92 | `npm install -g phantomjs`
93 |
94 | * `npm run build` to build
95 | * `npm test` to run tests
96 | * `npm start` to run a build watcher, and webserver to test
97 | * `npm run test:server` for a testem test runner and watching builder
98 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | * onSettled is invoked when/if the "promise" settles (either rejects or fulfills).
38 | * The returned promise is settled when the `Thenable` returned by `onFinally` settles;
39 | * it is rejected if `onFinally` throws or rejects; otherwise it assumes the state of the
40 | * original Promise.
41 | *
42 | * @param onFinally called when/if "promise" settles
43 |
44 | */
45 | finally (onFinally?: () => any | Thenable): Promise;
46 |
47 | /**
48 | * Make a new promise from the thenable.
49 | * A thenable is promise-like in as far as it has a "then" method.
50 | */
51 | static resolve (): Promise;
52 | static resolve (value: R | Thenable): Promise;
53 |
54 | /**
55 | * Make a promise that rejects to obj. For consistency and debugging (eg stack traces), obj should be an instanceof Error
56 | */
57 | static reject (error: any): Promise;
58 |
59 | /**
60 | * Make a promise that fulfills when every item in the array fulfills, and rejects if (and when) any item rejects.
61 | * the array passed to all can be a mixture of promise-like objects and other objects.
62 | * The fulfillment value is an array (in order) of fulfillment values. The rejection value is the first rejection value.
63 | */
64 | 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]>;
65 | 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]>;
66 | 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]>;
67 | 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]>;
68 | static all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable , T5 | Thenable, T6 | Thenable]): Promise<[T1, T2, T3, T4, T5, T6]>;
69 | static all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable , T5 | Thenable]): Promise<[T1, T2, T3, T4, T5]>;
70 | static all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable, T4 | Thenable ]): Promise<[T1, T2, T3, T4]>;
71 | static all(values: [T1 | Thenable, T2 | Thenable, T3 | Thenable]): Promise<[T1, T2, T3]>;
72 | static all(values: [T1 | Thenable, T2 | Thenable]): Promise<[T1, T2]>;
73 | static all(values: [T1 | Thenable]): Promise<[T1]>;
74 | static all(values: Array>): Promise;
75 |
76 | /**
77 | * Make a Promise that fulfills when any item fulfills, and rejects if any item rejects.
78 | */
79 | static race (promises: (R | Thenable)[]): Promise;
80 | }
81 |
82 | /**
83 | * The polyfill method will patch the global environment (in this case to the Promise name) when called.
84 | */
85 | export function polyfill (): void;
86 |
--------------------------------------------------------------------------------
/lib/es6-promise.auto.js:
--------------------------------------------------------------------------------
1 | import Promise from './es6-promise';
2 | Promise.polyfill();
3 | export default Promise;
4 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/lib/es6-promise/-internal.js:
--------------------------------------------------------------------------------
1 | import {
2 | objectOrFunction,
3 | isFunction
4 | } from './utils';
5 |
6 | import {
7 | asap
8 | } from './asap';
9 |
10 | import originalThen from './then';
11 | import originalResolve from './promise/resolve';
12 |
13 | export const PROMISE_ID = Math.random().toString(36).substring(2);
14 |
15 | function noop() {}
16 |
17 | const PENDING = void 0;
18 | const FULFILLED = 1;
19 | const REJECTED = 2;
20 |
21 | function selfFulfillment() {
22 | return new TypeError("You cannot resolve a promise with itself");
23 | }
24 |
25 | function cannotReturnOwn() {
26 | return new TypeError('A promises callback cannot return that same promise.');
27 | }
28 |
29 | function tryThen(then, value, fulfillmentHandler, rejectionHandler) {
30 | try {
31 | then.call(value, fulfillmentHandler, rejectionHandler);
32 | } catch(e) {
33 | return e;
34 | }
35 | }
36 |
37 | function handleForeignThenable(promise, thenable, then) {
38 | asap(promise => {
39 | let sealed = false;
40 | let error = tryThen(then, thenable, value => {
41 | if (sealed) { return; }
42 | sealed = true;
43 | if (thenable !== value) {
44 | resolve(promise, value);
45 | } else {
46 | fulfill(promise, value);
47 | }
48 | }, reason => {
49 | if (sealed) { return; }
50 | sealed = true;
51 |
52 | reject(promise, reason);
53 | }, 'Settle: ' + (promise._label || ' unknown promise'));
54 |
55 | if (!sealed && error) {
56 | sealed = true;
57 | reject(promise, error);
58 | }
59 | }, promise);
60 | }
61 |
62 | function handleOwnThenable(promise, thenable) {
63 | if (thenable._state === FULFILLED) {
64 | fulfill(promise, thenable._result);
65 | } else if (thenable._state === REJECTED) {
66 | reject(promise, thenable._result);
67 | } else {
68 | subscribe(thenable, undefined, value => resolve(promise, value),
69 | reason => reject(promise, reason))
70 | }
71 | }
72 |
73 | function handleMaybeThenable(promise, maybeThenable, then) {
74 | if (maybeThenable.constructor === promise.constructor &&
75 | then === originalThen &&
76 | maybeThenable.constructor.resolve === originalResolve) {
77 | handleOwnThenable(promise, maybeThenable);
78 | } else {
79 | if (then === undefined) {
80 | fulfill(promise, maybeThenable);
81 | } else if (isFunction(then)) {
82 | handleForeignThenable(promise, maybeThenable, then);
83 | } else {
84 | fulfill(promise, maybeThenable);
85 | }
86 | }
87 | }
88 |
89 | function resolve(promise, value) {
90 | if (promise === value) {
91 | reject(promise, selfFulfillment());
92 | } else if (objectOrFunction(value)) {
93 | let then;
94 | try {
95 | then = value.then;
96 | } catch (error) {
97 | reject(promise, error);
98 | return;
99 | }
100 | handleMaybeThenable(promise, value, then);
101 | } else {
102 | fulfill(promise, value);
103 | }
104 | }
105 |
106 | function publishRejection(promise) {
107 | if (promise._onerror) {
108 | promise._onerror(promise._result);
109 | }
110 |
111 | publish(promise);
112 | }
113 |
114 | function fulfill(promise, value) {
115 | if (promise._state !== PENDING) { return; }
116 |
117 | promise._result = value;
118 | promise._state = FULFILLED;
119 |
120 | if (promise._subscribers.length !== 0) {
121 | asap(publish, promise);
122 | }
123 | }
124 |
125 | function reject(promise, reason) {
126 | if (promise._state !== PENDING) { return; }
127 | promise._state = REJECTED;
128 | promise._result = reason;
129 |
130 | asap(publishRejection, promise);
131 | }
132 |
133 | function subscribe(parent, child, onFulfillment, onRejection) {
134 | let { _subscribers } = parent;
135 | let { length } = _subscribers;
136 |
137 | parent._onerror = null;
138 |
139 | _subscribers[length] = child;
140 | _subscribers[length + FULFILLED] = onFulfillment;
141 | _subscribers[length + REJECTED] = onRejection;
142 |
143 | if (length === 0 && parent._state) {
144 | asap(publish, parent);
145 | }
146 | }
147 |
148 | function publish(promise) {
149 | let subscribers = promise._subscribers;
150 | let settled = promise._state;
151 |
152 | if (subscribers.length === 0) { return; }
153 |
154 | let child, callback, detail = promise._result;
155 |
156 | for (let i = 0; i < subscribers.length; i += 3) {
157 | child = subscribers[i];
158 | callback = subscribers[i + settled];
159 |
160 | if (child) {
161 | invokeCallback(settled, child, callback, detail);
162 | } else {
163 | callback(detail);
164 | }
165 | }
166 |
167 | promise._subscribers.length = 0;
168 | }
169 |
170 | function invokeCallback(settled, promise, callback, detail) {
171 | let hasCallback = isFunction(callback),
172 | value, error, succeeded = true;
173 |
174 | if (hasCallback) {
175 | try {
176 | value = callback(detail);
177 | } catch (e) {
178 | succeeded = false;
179 | error = e;
180 | }
181 |
182 | if (promise === value) {
183 | reject(promise, cannotReturnOwn());
184 | return;
185 | }
186 | } else {
187 | value = detail;
188 | }
189 |
190 | if (promise._state !== PENDING) {
191 | // noop
192 | } else if (hasCallback && succeeded) {
193 | resolve(promise, value);
194 | } else if (succeeded === false) {
195 | reject(promise, error);
196 | } else if (settled === FULFILLED) {
197 | fulfill(promise, value);
198 | } else if (settled === REJECTED) {
199 | reject(promise, value);
200 | }
201 | }
202 |
203 | function initializePromise(promise, resolver) {
204 | try {
205 | resolver(function resolvePromise(value){
206 | resolve(promise, value);
207 | }, function rejectPromise(reason) {
208 | reject(promise, reason);
209 | });
210 | } catch(e) {
211 | reject(promise, e);
212 | }
213 | }
214 |
215 | let id = 0;
216 | function nextId() {
217 | return id++;
218 | }
219 |
220 | function makePromise(promise) {
221 | promise[PROMISE_ID] = id++;
222 | promise._state = undefined;
223 | promise._result = undefined;
224 | promise._subscribers = [];
225 | }
226 |
227 | export {
228 | nextId,
229 | makePromise,
230 | noop,
231 | resolve,
232 | reject,
233 | fulfill,
234 | subscribe,
235 | publish,
236 | publishRejection,
237 | initializePromise,
238 | invokeCallback,
239 | FULFILLED,
240 | REJECTED,
241 | PENDING,
242 | handleMaybeThenable
243 | };
244 |
--------------------------------------------------------------------------------
/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, 0);
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 vertx = Function('return this')().require('vertx');
100 | vertxNext = vertx.runOnLoop || vertx.runOnContext;
101 | return useVertxTimer();
102 | } catch(e) {
103 | return useSetTimeout();
104 | }
105 | }
106 |
107 | let scheduleFlush;
108 | // Decide what async method to use to triggering processing of queued callbacks:
109 | if (isNode) {
110 | scheduleFlush = useNextTick();
111 | } else if (BrowserMutationObserver) {
112 | scheduleFlush = useMutationObserver();
113 | } else if (isWorker) {
114 | scheduleFlush = useMessageChannel();
115 | } else if (browserWindow === undefined && typeof require === 'function') {
116 | scheduleFlush = attemptVertx();
117 | } else {
118 | scheduleFlush = useSetTimeout();
119 | }
120 |
--------------------------------------------------------------------------------
/lib/es6-promise/enumerator.js:
--------------------------------------------------------------------------------
1 | import {
2 | isArray,
3 | isMaybeThenable
4 | } from './utils';
5 | import {
6 | noop,
7 | reject,
8 | fulfill,
9 | subscribe,
10 | FULFILLED,
11 | REJECTED,
12 | PENDING,
13 | handleMaybeThenable
14 | } from './-internal';
15 |
16 | import then from './then';
17 | import Promise from './promise';
18 | import originalResolve from './promise/resolve';
19 | import originalThen from './then';
20 | import { makePromise, PROMISE_ID } from './-internal';
21 |
22 | function validationError() {
23 | return new Error('Array Methods must be provided an Array');
24 | };
25 |
26 | export default class Enumerator {
27 | constructor(Constructor, input) {
28 | this._instanceConstructor = Constructor;
29 | this.promise = new Constructor(noop);
30 |
31 | if (!this.promise[PROMISE_ID]) {
32 | makePromise(this.promise);
33 | }
34 |
35 | if (isArray(input)) {
36 | this.length = input.length;
37 | this._remaining = input.length;
38 |
39 | this._result = new Array(this.length);
40 |
41 | if (this.length === 0) {
42 | fulfill(this.promise, this._result);
43 | } else {
44 | this.length = this.length || 0;
45 | this._enumerate(input);
46 | if (this._remaining === 0) {
47 | fulfill(this.promise, this._result);
48 | }
49 | }
50 | } else {
51 | reject(this.promise, validationError());
52 | }
53 | }
54 | _enumerate(input) {
55 | for (let i = 0; this._state === PENDING && i < input.length; i++) {
56 | this._eachEntry(input[i], i);
57 | }
58 | }
59 |
60 | _eachEntry(entry, i) {
61 | let c = this._instanceConstructor;
62 | let { resolve } = c;
63 |
64 | if (resolve === originalResolve) {
65 | let then;
66 | let error;
67 | let didError = false;
68 | try {
69 | then = entry.then;
70 | } catch (e) {
71 | didError = true;
72 | error = e;
73 | }
74 |
75 | if (then === originalThen &&
76 | entry._state !== PENDING) {
77 | this._settledAt(entry._state, i, entry._result);
78 | } else if (typeof then !== 'function') {
79 | this._remaining--;
80 | this._result[i] = entry;
81 | } else if (c === Promise) {
82 | let promise = new c(noop);
83 | if (didError) {
84 | reject(promise, error);
85 | } else {
86 | handleMaybeThenable(promise, entry, then);
87 | }
88 | this._willSettleAt(promise, i);
89 | } else {
90 | this._willSettleAt(new c(resolve => resolve(entry)), i);
91 | }
92 | } else {
93 | this._willSettleAt(resolve(entry), i);
94 | }
95 | }
96 |
97 | _settledAt(state, i, value) {
98 | let { promise } = this;
99 |
100 | if (promise._state === PENDING) {
101 | this._remaining--;
102 |
103 | if (state === REJECTED) {
104 | reject(promise, value);
105 | } else {
106 | this._result[i] = value;
107 | }
108 | }
109 |
110 | if (this._remaining === 0) {
111 | fulfill(promise, this._result);
112 | }
113 | }
114 |
115 | _willSettleAt(promise, i) {
116 | let enumerator = this;
117 |
118 | subscribe(
119 | promise, undefined,
120 | value => enumerator._settledAt(FULFILLED, i, value),
121 | reason => enumerator._settledAt(REJECTED, i, reason)
122 | );
123 | }
124 | };
125 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/lib/es6-promise/promise.js:
--------------------------------------------------------------------------------
1 | import {
2 | isFunction
3 | } from './utils';
4 | import {
5 | noop,
6 | nextId,
7 | PROMISE_ID,
8 | initializePromise
9 | } from './-internal';
10 | import {
11 | asap,
12 | setAsap,
13 | setScheduler
14 | } from './asap';
15 |
16 | import all from './promise/all';
17 | import race from './promise/race';
18 | import Resolve from './promise/resolve';
19 | import Reject from './promise/reject';
20 | import then from './then';
21 |
22 | function needsResolver() {
23 | throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
24 | }
25 |
26 | function needsNew() {
27 | throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
28 | }
29 |
30 | /**
31 | Promise objects represent the eventual result of an asynchronous operation. The
32 | primary way of interacting with a promise is through its `then` method, which
33 | registers callbacks to receive either a promise's eventual value or the reason
34 | why the promise cannot be fulfilled.
35 |
36 | Terminology
37 | -----------
38 |
39 | - `promise` is an object or function with a `then` method whose behavior conforms to this specification.
40 | - `thenable` is an object or function that defines a `then` method.
41 | - `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
42 | - `exception` is a value that is thrown using the throw statement.
43 | - `reason` is a value that indicates why a promise was rejected.
44 | - `settled` the final resting state of a promise, fulfilled or rejected.
45 |
46 | A promise can be in one of three states: pending, fulfilled, or rejected.
47 |
48 | Promises that are fulfilled have a fulfillment value and are in the fulfilled
49 | state. Promises that are rejected have a rejection reason and are in the
50 | rejected state. A fulfillment value is never a thenable.
51 |
52 | Promises can also be said to *resolve* a value. If this value is also a
53 | promise, then the original promise's settled state will match the value's
54 | settled state. So a promise that *resolves* a promise that rejects will
55 | itself reject, and a promise that *resolves* a promise that fulfills will
56 | itself fulfill.
57 |
58 |
59 | Basic Usage:
60 | ------------
61 |
62 | ```js
63 | let promise = new Promise(function(resolve, reject) {
64 | // on success
65 | resolve(value);
66 |
67 | // on failure
68 | reject(reason);
69 | });
70 |
71 | promise.then(function(value) {
72 | // on fulfillment
73 | }, function(reason) {
74 | // on rejection
75 | });
76 | ```
77 |
78 | Advanced Usage:
79 | ---------------
80 |
81 | Promises shine when abstracting away asynchronous interactions such as
82 | `XMLHttpRequest`s.
83 |
84 | ```js
85 | function getJSON(url) {
86 | return new Promise(function(resolve, reject){
87 | let xhr = new XMLHttpRequest();
88 |
89 | xhr.open('GET', url);
90 | xhr.onreadystatechange = handler;
91 | xhr.responseType = 'json';
92 | xhr.setRequestHeader('Accept', 'application/json');
93 | xhr.send();
94 |
95 | function handler() {
96 | if (this.readyState === this.DONE) {
97 | if (this.status === 200) {
98 | resolve(this.response);
99 | } else {
100 | reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
101 | }
102 | }
103 | };
104 | });
105 | }
106 |
107 | getJSON('/posts.json').then(function(json) {
108 | // on fulfillment
109 | }, function(reason) {
110 | // on rejection
111 | });
112 | ```
113 |
114 | Unlike callbacks, promises are great composable primitives.
115 |
116 | ```js
117 | Promise.all([
118 | getJSON('/posts'),
119 | getJSON('/comments')
120 | ]).then(function(values){
121 | values[0] // => postsJSON
122 | values[1] // => commentsJSON
123 |
124 | return values;
125 | });
126 | ```
127 |
128 | @class Promise
129 | @param {Function} resolver
130 | Useful for tooling.
131 | @constructor
132 | */
133 |
134 | class Promise {
135 | constructor(resolver) {
136 | this[PROMISE_ID] = nextId();
137 | this._result = this._state = undefined;
138 | this._subscribers = [];
139 |
140 | if (noop !== resolver) {
141 | typeof resolver !== 'function' && needsResolver();
142 | this instanceof Promise ? initializePromise(this, resolver) : needsNew();
143 | }
144 | }
145 |
146 | /**
147 | The primary way of interacting with a promise is through its `then` method,
148 | which registers callbacks to receive either a promise's eventual value or the
149 | reason why the promise cannot be fulfilled.
150 |
151 | ```js
152 | findUser().then(function(user){
153 | // user is available
154 | }, function(reason){
155 | // user is unavailable, and you are given the reason why
156 | });
157 | ```
158 |
159 | Chaining
160 | --------
161 |
162 | The return value of `then` is itself a promise. This second, 'downstream'
163 | promise is resolved with the return value of the first promise's fulfillment
164 | or rejection handler, or rejected if the handler throws an exception.
165 |
166 | ```js
167 | findUser().then(function (user) {
168 | return user.name;
169 | }, function (reason) {
170 | return 'default name';
171 | }).then(function (userName) {
172 | // If `findUser` fulfilled, `userName` will be the user's name, otherwise it
173 | // will be `'default name'`
174 | });
175 |
176 | findUser().then(function (user) {
177 | throw new Error('Found user, but still unhappy');
178 | }, function (reason) {
179 | throw new Error('`findUser` rejected and we're unhappy');
180 | }).then(function (value) {
181 | // never reached
182 | }, function (reason) {
183 | // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
184 | // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
185 | });
186 | ```
187 | If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
188 |
189 | ```js
190 | findUser().then(function (user) {
191 | throw new PedagogicalException('Upstream error');
192 | }).then(function (value) {
193 | // never reached
194 | }).then(function (value) {
195 | // never reached
196 | }, function (reason) {
197 | // The `PedgagocialException` is propagated all the way down to here
198 | });
199 | ```
200 |
201 | Assimilation
202 | ------------
203 |
204 | Sometimes the value you want to propagate to a downstream promise can only be
205 | retrieved asynchronously. This can be achieved by returning a promise in the
206 | fulfillment or rejection handler. The downstream promise will then be pending
207 | until the returned promise is settled. This is called *assimilation*.
208 |
209 | ```js
210 | findUser().then(function (user) {
211 | return findCommentsByAuthor(user);
212 | }).then(function (comments) {
213 | // The user's comments are now available
214 | });
215 | ```
216 |
217 | If the assimliated promise rejects, then the downstream promise will also reject.
218 |
219 | ```js
220 | findUser().then(function (user) {
221 | return findCommentsByAuthor(user);
222 | }).then(function (comments) {
223 | // If `findCommentsByAuthor` fulfills, we'll have the value here
224 | }, function (reason) {
225 | // If `findCommentsByAuthor` rejects, we'll have the reason here
226 | });
227 | ```
228 |
229 | Simple Example
230 | --------------
231 |
232 | Synchronous Example
233 |
234 | ```javascript
235 | let result;
236 |
237 | try {
238 | result = findResult();
239 | // success
240 | } catch(reason) {
241 | // failure
242 | }
243 | ```
244 |
245 | Errback Example
246 |
247 | ```js
248 | findResult(function(result, err){
249 | if (err) {
250 | // failure
251 | } else {
252 | // success
253 | }
254 | });
255 | ```
256 |
257 | Promise Example;
258 |
259 | ```javascript
260 | findResult().then(function(result){
261 | // success
262 | }, function(reason){
263 | // failure
264 | });
265 | ```
266 |
267 | Advanced Example
268 | --------------
269 |
270 | Synchronous Example
271 |
272 | ```javascript
273 | let author, books;
274 |
275 | try {
276 | author = findAuthor();
277 | books = findBooksByAuthor(author);
278 | // success
279 | } catch(reason) {
280 | // failure
281 | }
282 | ```
283 |
284 | Errback Example
285 |
286 | ```js
287 |
288 | function foundBooks(books) {
289 |
290 | }
291 |
292 | function failure(reason) {
293 |
294 | }
295 |
296 | findAuthor(function(author, err){
297 | if (err) {
298 | failure(err);
299 | // failure
300 | } else {
301 | try {
302 | findBoooksByAuthor(author, function(books, err) {
303 | if (err) {
304 | failure(err);
305 | } else {
306 | try {
307 | foundBooks(books);
308 | } catch(reason) {
309 | failure(reason);
310 | }
311 | }
312 | });
313 | } catch(error) {
314 | failure(err);
315 | }
316 | // success
317 | }
318 | });
319 | ```
320 |
321 | Promise Example;
322 |
323 | ```javascript
324 | findAuthor().
325 | then(findBooksByAuthor).
326 | then(function(books){
327 | // found books
328 | }).catch(function(reason){
329 | // something went wrong
330 | });
331 | ```
332 |
333 | @method then
334 | @param {Function} onFulfilled
335 | @param {Function} onRejected
336 | Useful for tooling.
337 | @return {Promise}
338 | */
339 |
340 | /**
341 | `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
342 | as the catch block of a try/catch statement.
343 |
344 | ```js
345 | function findAuthor(){
346 | throw new Error('couldn't find that author');
347 | }
348 |
349 | // synchronous
350 | try {
351 | findAuthor();
352 | } catch(reason) {
353 | // something went wrong
354 | }
355 |
356 | // async with promises
357 | findAuthor().catch(function(reason){
358 | // something went wrong
359 | });
360 | ```
361 |
362 | @method catch
363 | @param {Function} onRejection
364 | Useful for tooling.
365 | @return {Promise}
366 | */
367 | catch(onRejection) {
368 | return this.then(null, onRejection);
369 | }
370 |
371 | /**
372 | `finally` will be invoked regardless of the promise's fate just as native
373 | try/catch/finally behaves
374 |
375 | Synchronous example:
376 |
377 | ```js
378 | findAuthor() {
379 | if (Math.random() > 0.5) {
380 | throw new Error();
381 | }
382 | return new Author();
383 | }
384 |
385 | try {
386 | return findAuthor(); // succeed or fail
387 | } catch(error) {
388 | return findOtherAuther();
389 | } finally {
390 | // always runs
391 | // doesn't affect the return value
392 | }
393 | ```
394 |
395 | Asynchronous example:
396 |
397 | ```js
398 | findAuthor().catch(function(reason){
399 | return findOtherAuther();
400 | }).finally(function(){
401 | // author was either found, or not
402 | });
403 | ```
404 |
405 | @method finally
406 | @param {Function} callback
407 | @return {Promise}
408 | */
409 | finally(callback) {
410 | let promise = this;
411 | let constructor = promise.constructor;
412 |
413 | if ( isFunction(callback) ) {
414 | return promise.then(value => constructor.resolve(callback()).then(() => value),
415 | reason => constructor.resolve(callback()).then(() => { throw reason; }));
416 | }
417 |
418 | return promise.then(callback, callback);
419 | }
420 | }
421 |
422 | Promise.prototype.then = then;
423 | export default Promise;
424 | Promise.all = all;
425 | Promise.race = race;
426 | Promise.resolve = Resolve;
427 | Promise.reject = Reject;
428 | Promise._setScheduler = setScheduler;
429 | Promise._setAsap = setAsap;
430 | Promise._asap = asap;
431 |
432 |
--------------------------------------------------------------------------------
/lib/es6-promise/promise/all.js:
--------------------------------------------------------------------------------
1 | import Enumerator from '../enumerator';
2 |
3 | /**
4 | `Promise.all` accepts an array of promises, and returns a new promise which
5 | is fulfilled with an array of fulfillment values for the passed promises, or
6 | rejected with the reason of the first passed promise to be rejected. It casts all
7 | elements of the passed iterable to promises as it runs this algorithm.
8 |
9 | Example:
10 |
11 | ```javascript
12 | let promise1 = resolve(1);
13 | let promise2 = resolve(2);
14 | let promise3 = resolve(3);
15 | let promises = [ promise1, promise2, promise3 ];
16 |
17 | Promise.all(promises).then(function(array){
18 | // The array here would be [ 1, 2, 3 ];
19 | });
20 | ```
21 |
22 | If any of the `promises` given to `all` are rejected, the first promise
23 | that is rejected will be given as an argument to the returned promises's
24 | rejection handler. For example:
25 |
26 | Example:
27 |
28 | ```javascript
29 | let promise1 = resolve(1);
30 | let promise2 = reject(new Error("2"));
31 | let promise3 = reject(new Error("3"));
32 | let promises = [ promise1, promise2, promise3 ];
33 |
34 | Promise.all(promises).then(function(array){
35 | // Code here never runs because there are rejected promises!
36 | }, function(error) {
37 | // error.message === "2"
38 | });
39 | ```
40 |
41 | @method all
42 | @static
43 | @param {Array} entries array of promises
44 | @param {String} label optional string for labeling the promise.
45 | Useful for tooling.
46 | @return {Promise} promise that is fulfilled when all `promises` have been
47 | fulfilled, or rejected if any of them become rejected.
48 | @static
49 | */
50 | export default function all(entries) {
51 | return new Enumerator(this, entries).promise;
52 | }
53 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/lib/es6-promise/utils.js:
--------------------------------------------------------------------------------
1 | export function objectOrFunction(x) {
2 | let type = typeof x;
3 | return x !== null && (type === 'object' || type === 'function');
4 | }
5 |
6 | export function isFunction(x) {
7 | return typeof x === 'function';
8 | }
9 |
10 | export function isMaybeThenable(x) {
11 | return x !== null && typeof x === 'object';
12 | }
13 |
14 | let _isArray;
15 | if (Array.isArray) {
16 | _isArray = Array.isArray;
17 | } else {
18 | _isArray = x => Object.prototype.toString.call(x) === '[object Array]';
19 | }
20 |
21 | export const isArray = _isArray;
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "es6-promise",
3 | "description": "A lightweight library that provides tools for organizing asynchronous code",
4 | "version": "4.2.8",
5 | "author": "Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)",
6 | "browser": {
7 | "vertx": false
8 | },
9 | "bugs": {
10 | "url": "https://github.com/stefanpenner/es6-promise/issues"
11 | },
12 | "dependencies": {},
13 | "devDependencies": {
14 | "babel-plugin-transform-es2015-arrow-functions": "^6.22.0",
15 | "babel-plugin-transform-es2015-block-scoping": "^6.24.1",
16 | "babel-plugin-transform-es2015-classes": "^6.24.1",
17 | "babel-plugin-transform-es2015-computed-properties": "^6.24.1",
18 | "babel-plugin-transform-es2015-constants": "^6.1.4",
19 | "babel-plugin-transform-es2015-destructuring": "^6.23.0",
20 | "babel-plugin-transform-es2015-parameters": "^6.24.1",
21 | "babel-plugin-transform-es2015-shorthand-properties": "^6.24.1",
22 | "babel-plugin-transform-es2015-spread": "^6.22.0",
23 | "babel-plugin-transform-es2015-template-literals": "^6.22.0",
24 | "babel6-plugin-strip-class-callcheck": "^6.0.0",
25 | "broccoli-babel-transpiler": "^6.0.0",
26 | "broccoli-concat": "^3.1.0",
27 | "broccoli-merge-trees": "^2.0.0",
28 | "broccoli-rollup": "^2.0.0",
29 | "broccoli-stew": "^1.5.0",
30 | "broccoli-uglify-js": "^0.2.0",
31 | "broccoli-watchify": "^1.0.1",
32 | "ember-cli": "2.18.0-beta.2",
33 | "ember-cli-dependency-checker": "^2.1.0",
34 | "git-repo-version": "1.0.1",
35 | "json3": "^3.3.2",
36 | "mocha": "^4.0.1",
37 | "promises-aplus-tests-phantom": "^2.1.0-revise"
38 | },
39 | "directories": {
40 | "lib": "lib"
41 | },
42 | "files": [
43 | "dist",
44 | "lib",
45 | "es6-promise.d.ts",
46 | "auto.js",
47 | "!dist/test"
48 | ],
49 | "homepage": "https://github.com/stefanpenner/es6-promise",
50 | "jsdelivr": "dist/es6-promise.auto.min.js",
51 | "keywords": [
52 | "futures",
53 | "polyfill",
54 | "promise",
55 | "promises"
56 | ],
57 | "license": "MIT",
58 | "main": "dist/es6-promise.js",
59 | "namespace": "es6-promise",
60 | "repository": {
61 | "type": "git",
62 | "url": "git://github.com/stefanpenner/es6-promise.git"
63 | },
64 | "scripts": {
65 | "build": "ember build --environment production",
66 | "prepublishOnly": "ember build --environment production",
67 | "start": "ember s",
68 | "test": "ember test",
69 | "test:browser": "ember test --launch PhantomJS",
70 | "test:node": "ember test --launch Mocha",
71 | "test:server": "ember test --server"
72 | },
73 | "spm": {
74 | "main": "dist/es6-promise.js"
75 | },
76 | "typings": "es6-promise.d.ts",
77 | "unpkg": "dist/es6-promise.auto.min.js"
78 | }
79 |
--------------------------------------------------------------------------------
/server/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "node": true
3 | }
4 |
--------------------------------------------------------------------------------
/server/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function(app) {
2 | app.get('/', function(req, res) {
3 | res.redirect('/test/');
4 | })
5 | };
6 |
--------------------------------------------------------------------------------
/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 | var g = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : this;
15 | var Promise = g.adapter.Promise;
16 | var assert = require('assert');
17 |
18 | describe('tampering', function() {
19 | var resolve = Promise.resolve;
20 |
21 | afterEach(function() {
22 | Promise.resolve = resolve;
23 | });
24 |
25 | describe('then assimilation', function() {
26 | it('tampered resolved and then', function() {
27 | var one = Promise.resolve(1);
28 | var two = Promise.resolve(2);
29 | var thenCalled = 0;
30 | var resolveCalled = 0;
31 |
32 | two.then = function() {
33 | thenCalled++;
34 | return Promise.prototype.then.apply(this, arguments);
35 | };
36 |
37 | Promise.resolve = function(x) {
38 | resolveCalled++;
39 | return new Promise(function(resolve) { resolve(x); });
40 | };
41 |
42 | return one.then(function() {
43 | return two;
44 | }).then(function(value) {
45 | assert.equal(thenCalled, 1, 'expected then to be called once');
46 | assert.equal(resolveCalled, 0, 'expected resolve to be called once');
47 | assert.equal(value, 2, 'expected fulfillment value to be 2');
48 | });
49 | });
50 |
51 | it('tampered resolved', function() {
52 | var one = Promise.resolve(1);
53 | var two = Promise.resolve(2);
54 | var thenCalled = 0;
55 | var resolveCalled = 0;
56 |
57 | Promise.resolve = function(x) {
58 | resolveCalled++;
59 | return new Promise(function(resolve) { resolve(x); });
60 | };
61 |
62 | return one.then(function() {
63 | return two;
64 | }).then(function(value) {
65 | assert.equal(resolveCalled, 0, 'expected resolve to be called once');
66 | assert.equal(value, 2, 'expected fulfillment value to be 2');
67 | });
68 | });
69 |
70 | describe('alternative constructor', function() {
71 | it('tampered resolved and then', function() {
72 | var one = Promise.resolve(1);
73 | var two = Promise.resolve(2);
74 | var thenCalled = 0;
75 | var resolveCalled = 0;
76 | var invokedAlternativeConstructor = 0;
77 |
78 | two.then = function() {
79 | thenCalled++;
80 | return Promise.prototype.then.apply(this, arguments);
81 | };
82 |
83 | function AlternativeConstructor(executor) {
84 | invokedAlternativeConstructor++;
85 | var followers = this.followers = [];
86 | executor(function(value) {
87 | followers.forEach(function(onFulfillment) {
88 | onFulfillment(value)
89 | });
90 | }, function() {
91 | throw TypeError('No Rejections supported');
92 | });
93 | }
94 |
95 | AlternativeConstructor.resolve = function(x) {
96 | resolveCalled++;
97 | return new Promise(function(resolve) { resolve(x); });
98 | };
99 |
100 | AlternativeConstructor.prototype.then = function(onFulfillment, onRejection) {
101 | this.followers.push(onFulfillment);
102 | };
103 |
104 | AlternativeConstructor.resolve = function(x) {
105 | resolveCalled++;
106 | return new Promise(function(resolve) { resolve(x); });
107 | };
108 |
109 | one.constructor = AlternativeConstructor
110 |
111 | return one.then(function() {
112 | return two;
113 | }).then(function(value) {
114 |
115 | assert.equal(invokedAlternativeConstructor, 1, 'expected AlternativeConstructor to be invoked once');
116 | assert.equal(thenCalled, 1, 'expected then to be called once');
117 | assert.equal(resolveCalled, 0, 'expected resolve to be called once');
118 | assert.equal(value, 2, 'expected fulfillment value to be 2');
119 | });
120 | });
121 | });
122 |
123 | describe('Promise.all', function() {
124 | it('tampered resolved and then', function() {
125 | var two = Promise.resolve(2);
126 | var thenCalled = 0;
127 | var resolveCalled = 0;
128 |
129 | two.then = function() {
130 | thenCalled++;
131 | return Promise.prototype.then.apply(this, arguments);
132 | };
133 |
134 | Promise.resolve = function(x) {
135 | resolveCalled++;
136 | return new Promise(function(resolve) { resolve(x); });
137 | };
138 |
139 | return Promise.all([two]).then(function(value) {
140 | assert.equal(thenCalled, 1);
141 | assert.equal(resolveCalled, 1);
142 | assert.deepEqual(value, [2]);
143 | });
144 | });
145 |
146 | it('alternative constructor and tampered then', function() {
147 | var two = Promise.resolve(2);
148 | var thenCalled = 0;
149 | var resolveCalled = 0;
150 |
151 | two.then = function() {
152 | thenCalled++;
153 | return Promise.prototype.then.apply(this, arguments);
154 | };
155 |
156 | function AlternativeConstructor(executor) {
157 | var followers = this.followers = [];
158 | executor(function(value) {
159 | followers.forEach(function(onFulfillment) {
160 | onFulfillment(value)
161 | });
162 | }, function() {
163 | throw TypeError('No Rejections supported');
164 | });
165 | }
166 |
167 | AlternativeConstructor.resolve = function(x) {
168 | resolveCalled++;
169 | return new Promise(function(resolve) { resolve(x); });
170 | };
171 |
172 | AlternativeConstructor.prototype.then = function(onFulfillment, onRejection) {
173 | this.followers.push(onFulfillment);
174 | };
175 |
176 | return Promise.all.call(AlternativeConstructor, [two]).then(function(value) {
177 | assert.equal(thenCalled, 1);
178 | assert.equal(resolveCalled, 1);
179 | assert.deepEqual(value, [2]);
180 | });
181 | });
182 | });
183 |
184 | describe('core-js species test', function() {
185 | it('foreign thenable has correct internal slots', function() {
186 | var p = Promise.resolve();
187 |
188 | function NewConstructor(it) {
189 | it(function(){}, function(){})
190 | }
191 |
192 | p.constructor = NewConstructor;
193 |
194 | var f = p.then(function(){});
195 | assert(f instanceof NewConstructor);
196 | });
197 | });
198 | describe('Promise.race', function() {
199 | it('tampered resolved and then', function() {
200 | var two = Promise.resolve(2);
201 | var thenCalled = 0;
202 | var resolveCalled = 0;
203 |
204 | two.then = function() {
205 | thenCalled++;
206 | return Promise.prototype.then.apply(this, arguments);
207 | };
208 |
209 | Promise.resolve = function(x) {
210 | resolveCalled++;
211 | return new Promise(function(resolve) { resolve(x); });
212 | };
213 |
214 | return Promise.race([two]).then(function(value) {
215 | assert.equal(thenCalled, 1);
216 | assert.equal(resolveCalled, 1);
217 | assert.deepEqual(value, 2);
218 | });
219 | });
220 |
221 | it('alternative constructor and tampered then', function() {
222 | var two = Promise.resolve(2);
223 | var thenCalled = 0;
224 | var resolveCalled = 0;
225 |
226 | two.then = function() {
227 | thenCalled++;
228 | return Promise.prototype.then.apply(this, arguments);
229 | };
230 |
231 | function AlternativeConstructor(executor) {
232 | var followers = this.followers = [];
233 | executor(function(value) {
234 | followers.forEach(function(onFulfillment) {
235 | onFulfillment(value)
236 | });
237 | }, function() {
238 | throw TypeError('No Rejections supported');
239 | });
240 | }
241 |
242 | AlternativeConstructor.resolve = function(x) {
243 | resolveCalled++;
244 | return new Promise(function(resolve) { resolve(x); });
245 | };
246 |
247 | AlternativeConstructor.prototype.then = function(onFulfillment, onRejection) {
248 | this.followers.push(onFulfillment);
249 | };
250 |
251 | return Promise.race.call(AlternativeConstructor, [two]).then(function(value) {
252 | assert.equal(thenCalled, 1);
253 | assert.equal(resolveCalled, 1);
254 | assert.deepEqual(value, 2);
255 | });
256 | });
257 | });
258 |
259 | });
260 | });
261 |
262 | describe("extensions", function() {
263 | describe("Promise constructor", function() {
264 | it('should exist and have length 1', function() {
265 | assert(Promise);
266 | assert.equal(Promise.length, 1);
267 | });
268 |
269 | it('should fulfill if `resolve` is called with a value', function(done) {
270 | var promise = new Promise(function(resolve) { resolve('value'); });
271 |
272 | promise.then(function(value) {
273 | assert.equal(value, 'value');
274 | done();
275 | });
276 | });
277 |
278 | it('should reject if `reject` is called with a reason', function(done) {
279 | var promise = new Promise(function(resolve, reject) { reject('reason'); });
280 |
281 | promise.then(function() {
282 | assert(false);
283 | done();
284 | }, function(reason) {
285 | assert.equal(reason, 'reason');
286 | done();
287 | });
288 | });
289 |
290 | it('should be a constructor', function() {
291 | var promise = new Promise(function() {});
292 |
293 | assert.equal(Object.getPrototypeOf(promise), Promise.prototype, '[[Prototype]] equals Promise.prototype');
294 | assert.equal(promise.constructor, Promise, 'constructor property of instances is set correctly');
295 | assert.equal(Promise.prototype.constructor, Promise, 'constructor property of prototype is set correctly');
296 | });
297 |
298 | it('should NOT work without `new`', function() {
299 | assert.throws(function(){
300 | Promise(function(resolve) { resolve('value'); });
301 | }, TypeError)
302 | });
303 |
304 | it('should throw a `TypeError` if not given a function', function() {
305 | assert.throws(function () {
306 | new Promise();
307 | }, TypeError);
308 |
309 | assert.throws(function () {
310 | new Promise({});
311 | }, TypeError);
312 |
313 | assert.throws(function () {
314 | new Promise('boo!');
315 | }, TypeError);
316 | });
317 |
318 | it('should reject on resolver exception', function(done) {
319 | new Promise(function() {
320 | throw 'error';
321 | }).then(null, function(e) {
322 | assert.equal(e, 'error');
323 | done();
324 | });
325 | });
326 |
327 | it('should not resolve multiple times', function(done) {
328 | var resolver, rejector, fulfilled = 0, rejected = 0;
329 | var thenable = {
330 | then: function(resolve, reject) {
331 | resolver = resolve;
332 | rejector = reject;
333 | }
334 | };
335 |
336 | var promise = new Promise(function(resolve) {
337 | resolve(1);
338 | });
339 |
340 | promise.then(function(value){
341 | return thenable;
342 | }).then(function(value){
343 | fulfilled++;
344 | }, function(reason) {
345 | rejected++;
346 | });
347 |
348 | setTimeout(function() {
349 | resolver(1);
350 | resolver(1);
351 | rejector(1);
352 | rejector(1);
353 |
354 | setTimeout(function() {
355 | assert.equal(fulfilled, 1);
356 | assert.equal(rejected, 0);
357 | done();
358 | }, 20);
359 | }, 20);
360 |
361 | });
362 |
363 | describe('assimilation', function() {
364 | it('should assimilate if `resolve` is called with a fulfilled promise', function(done) {
365 | var originalPromise = new Promise(function(resolve) { resolve('original value'); });
366 | var promise = new Promise(function(resolve) { resolve(originalPromise); });
367 |
368 | promise.then(function(value) {
369 | assert.equal(value, 'original value');
370 | done();
371 | });
372 | });
373 |
374 | it('should assimilate if `resolve` is called with a rejected promise', function(done) {
375 | var originalPromise = new Promise(function(resolve, reject) { reject('original reason'); });
376 | var promise = new Promise(function(resolve) { resolve(originalPromise); });
377 |
378 | promise.then(function() {
379 | assert(false);
380 | done();
381 | }, function(reason) {
382 | assert.equal(reason, 'original reason');
383 | done();
384 | });
385 | });
386 |
387 | it('should assimilate if `resolve` is called with a fulfilled thenable', function(done) {
388 | var originalThenable = {
389 | then: function (onFulfilled) {
390 | setTimeout(function() { onFulfilled('original value'); }, 0);
391 | }
392 | };
393 | var promise = new Promise(function(resolve) { resolve(originalThenable); });
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 thenable', function(done) {
402 | var originalThenable = {
403 | then: function (onFulfilled, onRejected) {
404 | setTimeout(function() { onRejected('original reason'); }, 0);
405 | }
406 | };
407 | var promise = new Promise(function(resolve) { resolve(originalThenable); });
408 |
409 | promise.then(function() {
410 | assert(false);
411 | done();
412 | }, function(reason) {
413 | assert.equal(reason, 'original reason');
414 | done();
415 | });
416 | });
417 |
418 |
419 | it('should assimilate two levels deep, for fulfillment of self fulfilling promises', function(done) {
420 | var originalPromise, promise;
421 | originalPromise = new Promise(function(resolve) {
422 | setTimeout(function() {
423 | resolve(originalPromise);
424 | }, 0)
425 | });
426 |
427 | promise = new Promise(function(resolve) {
428 | setTimeout(function() {
429 | resolve(originalPromise);
430 | }, 0);
431 | });
432 |
433 | promise.then(function(value) {
434 | assert(false);
435 | done();
436 | }).catch(function(reason) {
437 | assert.equal(reason.message, "You cannot resolve a promise with itself");
438 | assert(reason instanceof TypeError);
439 | done();
440 | });
441 | });
442 |
443 | it('should assimilate two levels deep, for fulfillment', function(done) {
444 | var originalPromise = new Promise(function(resolve) { resolve('original value'); });
445 | var nextPromise = new Promise(function(resolve) { resolve(originalPromise); });
446 | var promise = new Promise(function(resolve) { resolve(nextPromise); });
447 |
448 | promise.then(function(value) {
449 | assert.equal(value, 'original value');
450 | done();
451 | });
452 | });
453 |
454 | it('should assimilate two levels deep, for rejection', function(done) {
455 | var originalPromise = new Promise(function(resolve, reject) { reject('original reason'); });
456 | var nextPromise = new Promise(function(resolve) { resolve(originalPromise); });
457 | var promise = new Promise(function(resolve) { resolve(nextPromise); });
458 |
459 | promise.then(function() {
460 | assert(false);
461 | done();
462 | }, function(reason) {
463 | assert.equal(reason, 'original reason');
464 | done();
465 | });
466 | });
467 |
468 | it('should assimilate three levels deep, mixing thenables and promises (fulfilled case)', function(done) {
469 | var originalPromise = new Promise(function(resolve) { resolve('original value'); });
470 | var intermediateThenable = {
471 | then: function (onFulfilled) {
472 | setTimeout(function() { onFulfilled(originalPromise); }, 0);
473 | }
474 | };
475 | var promise = new Promise(function(resolve) { resolve(intermediateThenable); });
476 |
477 | promise.then(function(value) {
478 | assert.equal(value, 'original value');
479 | done();
480 | });
481 | });
482 |
483 | it('should assimilate three levels deep, mixing thenables and promises (rejected case)', function(done) {
484 | var originalPromise = new Promise(function(resolve, reject) { reject('original reason'); });
485 | var intermediateThenable = {
486 | then: function (onFulfilled) {
487 | setTimeout(function() { onFulfilled(originalPromise); }, 0);
488 | }
489 | };
490 | var promise = new Promise(function(resolve) { resolve(intermediateThenable); });
491 |
492 | promise.then(function() {
493 | assert(false);
494 | done();
495 | }, function(reason) {
496 | assert.equal(reason, 'original reason');
497 | done();
498 | });
499 | });
500 | });
501 | });
502 |
503 | describe('Promise.all', function() {
504 | testAll(function(){
505 | return Promise.all.apply(Promise, arguments);
506 | });
507 | });
508 |
509 | function testAll(all) {
510 | it('should exist', function() {
511 | assert(all);
512 | });
513 |
514 | it('works with plan pojo input', function(done) {
515 | all([
516 | {}
517 | ]).then(function(result) {
518 | assert.deepEqual(result, [{}]);
519 | done();
520 | });
521 | });
522 |
523 | it('throws when not passed an array', function(done) {
524 | var nothing = assertRejection(all());
525 | var string = assertRejection(all(''));
526 | var object = assertRejection(all({}));
527 |
528 | Promise.all([
529 | nothing,
530 | string,
531 | object
532 | ]).then(function(){ done(); });
533 | });
534 |
535 | specify('fulfilled only after all of the other promises are fulfilled', function(done) {
536 | var firstResolved, secondResolved, firstResolver, secondResolver;
537 |
538 | var first = new Promise(function(resolve) {
539 | firstResolver = resolve;
540 | });
541 | first.then(function() {
542 | firstResolved = true;
543 | });
544 |
545 | var second = new Promise(function(resolve) {
546 | secondResolver = resolve;
547 | });
548 | second.then(function() {
549 | secondResolved = true;
550 | });
551 |
552 | setTimeout(function() {
553 | firstResolver(true);
554 | }, 0);
555 |
556 | setTimeout(function() {
557 | secondResolver(true);
558 | }, 0);
559 |
560 | all([first, second]).then(function() {
561 | assert(firstResolved);
562 | assert(secondResolved);
563 | done();
564 | });
565 | });
566 |
567 | specify('rejected as soon as a promise is rejected', function(done) {
568 | var firstResolver, secondResolver;
569 |
570 | var first = new Promise(function(resolve, reject) {
571 | firstResolver = { resolve: resolve, reject: reject };
572 | });
573 |
574 | var second = new Promise(function(resolve, reject) {
575 | secondResolver = { resolve: resolve, reject: reject };
576 | });
577 |
578 | setTimeout(function() {
579 | firstResolver.reject({});
580 | }, 0);
581 |
582 | var firstWasRejected, secondCompleted;
583 |
584 | first.catch(function(){
585 | firstWasRejected = true;
586 | });
587 |
588 | second.then(function(){
589 | secondCompleted = true;
590 | }, function() {
591 | secondCompleted = true;
592 | });
593 |
594 | all([first, second]).then(function() {
595 | assert(false);
596 | }, function() {
597 | assert(firstWasRejected);
598 | assert(!secondCompleted);
599 | done();
600 | });
601 | });
602 |
603 | specify('passes the resolved values of each promise to the callback in the correct order', function(done) {
604 | var firstResolver, secondResolver, thirdResolver;
605 |
606 | var first = new Promise(function(resolve, reject) {
607 | firstResolver = { resolve: resolve, reject: reject };
608 | });
609 |
610 | var second = new Promise(function(resolve, reject) {
611 | secondResolver = { resolve: resolve, reject: reject };
612 | });
613 |
614 | var third = new Promise(function(resolve, reject) {
615 | thirdResolver = { resolve: resolve, reject: reject };
616 | });
617 |
618 | thirdResolver.resolve(3);
619 | firstResolver.resolve(1);
620 | secondResolver.resolve(2);
621 |
622 | all([first, second, third]).then(function(results) {
623 | assert(results.length === 3);
624 | assert(results[0] === 1);
625 | assert(results[1] === 2);
626 | assert(results[2] === 3);
627 | done();
628 | });
629 | });
630 |
631 | specify('resolves an empty array passed to all()', function(done) {
632 | all([]).then(function(results) {
633 | assert(results.length === 0);
634 | done();
635 | });
636 | });
637 |
638 | specify('works with null', function(done) {
639 | all([null]).then(function(results) {
640 | assert.equal(results[0], null);
641 | done();
642 | });
643 | });
644 |
645 | specify('works with a mix of promises and thenables and non-promises', function(done) {
646 | var promise = new Promise(function(resolve) { resolve(1); });
647 | var syncThenable = { then: function (onFulfilled) { onFulfilled(2); } };
648 | var asyncThenable = { then: function (onFulfilled) { setTimeout(function() { onFulfilled(3); }, 0); } };
649 | var nonPromise = 4;
650 |
651 | all([promise, syncThenable, asyncThenable, nonPromise]).then(function(results) {
652 | assert.deepEqual(results, [1, 2, 3, 4]);
653 | done();
654 | }).catch(done);
655 | });
656 | }
657 |
658 | describe("reject", function(){
659 | specify("it should exist", function(){
660 | assert(Promise.reject);
661 | });
662 |
663 | describe('it rejects', function(){
664 | var reason = 'the reason',
665 | promise = Promise.reject(reason);
666 |
667 | promise.then(function(){
668 | assert(false, 'should not fulfill');
669 | }, function(actualReason){
670 | assert.equal(reason, actualReason);
671 | });
672 | });
673 | });
674 |
675 | function assertRejection(promise) {
676 | return promise.then(function(){
677 | assert(false, 'expected rejection, but got fulfillment');
678 | }, function(reason){
679 | assert(reason instanceof Error);
680 | });
681 | }
682 |
683 | describe('race', function() {
684 | it("should exist", function() {
685 | assert(Promise.race);
686 | });
687 |
688 | it("throws when not passed an array", function(done) {
689 | var nothing = assertRejection(Promise.race());
690 | var string = assertRejection(Promise.race(''));
691 | var object = assertRejection(Promise.race({}));
692 |
693 | Promise.all([
694 | nothing,
695 | string,
696 | object
697 | ]).then(function(){ done(); });
698 | });
699 |
700 | specify('fulfilled after one of the other promises are fulfilled', function(done) {
701 | var firstResolved, secondResolved, firstResolver, secondResolver;
702 |
703 | var first = new Promise(function(resolve) {
704 | firstResolver = resolve;
705 | });
706 | first.then(function() {
707 | firstResolved = true;
708 | });
709 |
710 | var second = new Promise(function(resolve) {
711 | secondResolver = resolve;
712 | });
713 | second.then(function() {
714 | secondResolved = true;
715 | });
716 |
717 | setTimeout(function() {
718 | firstResolver(true);
719 | }, 100);
720 |
721 | setTimeout(function() {
722 | secondResolver(true);
723 | }, 0);
724 |
725 | Promise.race([first, second]).then(function() {
726 | assert(secondResolved);
727 | assert.equal(firstResolved, undefined);
728 | done();
729 | });
730 | });
731 |
732 | specify('the race begins on nextTurn and prioritized by array entry', function(done) {
733 | var firstResolver, secondResolver, nonPromise = 5;
734 |
735 | var first = new Promise(function(resolve, reject) {
736 | resolve(true);
737 | });
738 |
739 | var second = new Promise(function(resolve, reject) {
740 | resolve(false);
741 | });
742 |
743 | Promise.race([first, second, nonPromise]).then(function(value) {
744 | assert.equal(value, true);
745 | done();
746 | });
747 | });
748 |
749 | specify('rejected as soon as a promise is rejected', function(done) {
750 | var firstResolver, secondResolver;
751 |
752 | var first = new Promise(function(resolve, reject) {
753 | firstResolver = { resolve: resolve, reject: reject };
754 | });
755 |
756 | var second = new Promise(function(resolve, reject) {
757 | secondResolver = { resolve: resolve, reject: reject };
758 | });
759 |
760 | setTimeout(function() {
761 | firstResolver.reject({});
762 | }, 0);
763 |
764 | var firstWasRejected, secondCompleted;
765 |
766 | first.catch(function(){
767 | firstWasRejected = true;
768 | });
769 |
770 | second.then(function(){
771 | secondCompleted = true;
772 | }, function() {
773 | secondCompleted = true;
774 | });
775 |
776 | Promise.race([first, second]).then(function() {
777 | assert(false);
778 | }, function() {
779 | assert(firstWasRejected);
780 | assert(!secondCompleted);
781 | done();
782 | });
783 | });
784 |
785 | specify('resolves an empty array to forever pending Promise', function(done) {
786 | var foreverPendingPromise = Promise.race([]),
787 | wasSettled = false;
788 |
789 | foreverPendingPromise.then(function() {
790 | wasSettled = true;
791 | }, function() {
792 | wasSettled = true;
793 | });
794 |
795 | setTimeout(function() {
796 | assert(!wasSettled);
797 | done();
798 | }, 50);
799 | });
800 |
801 | specify('works with a mix of promises and thenables', function(done) {
802 | var promise = new Promise(function(resolve) { setTimeout(function() { resolve(1); }, 10); }),
803 | syncThenable = { then: function (onFulfilled) { onFulfilled(2); } };
804 |
805 | Promise.race([promise, syncThenable]).then(function(result) {
806 | assert(result, 2);
807 | done();
808 | });
809 | });
810 |
811 | specify('works with a mix of thenables and non-promises', function (done) {
812 | var asyncThenable = { then: function (onFulfilled) { setTimeout(function() { onFulfilled(3); }, 0); } },
813 | nonPromise = 4;
814 |
815 | Promise.race([asyncThenable, nonPromise]).then(function(result) {
816 | assert(result, 4);
817 | done();
818 | });
819 | });
820 | });
821 |
822 | describe("resolve", function(){
823 | specify("it should exist", function(){
824 | assert(Promise.resolve);
825 | });
826 |
827 | describe("1. If x is a promise, adopt its state ", function(){
828 | specify("1.1 If x is pending, promise must remain pending until x is fulfilled or rejected.", function(done){
829 | var expectedValue, resolver, thenable, wrapped;
830 |
831 | expectedValue = 'the value';
832 | thenable = {
833 | then: function(resolve, reject){
834 | resolver = resolve;
835 | }
836 | };
837 |
838 | wrapped = Promise.resolve(thenable);
839 |
840 | wrapped.then(function(value){
841 | assert(value === expectedValue);
842 | done();
843 | });
844 |
845 | setTimeout(function(){
846 | resolver(expectedValue);
847 | }, 10);
848 | });
849 |
850 | specify("1.2 If/when x is fulfilled, fulfill promise with the same value.", function(done){
851 | var expectedValue, thenable, wrapped;
852 |
853 | expectedValue = 'the value';
854 | thenable = {
855 | then: function(resolve, reject){
856 | resolve(expectedValue);
857 | }
858 | };
859 |
860 | wrapped = Promise.resolve(thenable);
861 |
862 | wrapped.then(function(value){
863 | assert(value === expectedValue);
864 | done();
865 | })
866 | });
867 |
868 | specify("1.3 If/when x is rejected, reject promise with the same reason.", function(done){
869 | var expectedError, thenable, wrapped;
870 |
871 | expectedError = new Error();
872 | thenable = {
873 | then: function(resolve, reject){
874 | reject(expectedError);
875 | }
876 | };
877 |
878 | wrapped = Promise.resolve(thenable);
879 |
880 | wrapped.then(null, function(error){
881 | assert(error === expectedError);
882 | done();
883 | });
884 | });
885 | });
886 |
887 | describe("2. Otherwise, if x is an object or function,", function(){
888 | specify("2.1 Let then x.then", function(done){
889 | var accessCount, resolver, wrapped, thenable;
890 |
891 | accessCount = 0;
892 | thenable = { };
893 |
894 | // we likely don't need to test this, if the browser doesn't support it
895 | if (typeof Object.defineProperty !== "function") { done(); return; }
896 |
897 | Object.defineProperty(thenable, 'then', {
898 | get: function(){
899 | accessCount++;
900 |
901 | if (accessCount > 1) {
902 | throw new Error();
903 | }
904 |
905 | return function(){ };
906 | }
907 | });
908 |
909 | assert(accessCount === 0);
910 |
911 | wrapped = Promise.resolve(thenable);
912 |
913 | assert(accessCount === 1);
914 |
915 | done();
916 | });
917 |
918 | specify("2.2 If retrieving the property x.then results in a thrown exception e, reject promise with e as the reason.", function(done){
919 | var wrapped, thenable, expectedError;
920 |
921 | expectedError = new Error();
922 | thenable = { };
923 |
924 | // we likely don't need to test this, if the browser doesn't support it
925 | if (typeof Object.defineProperty !== "function") { done(); return; }
926 |
927 | Object.defineProperty(thenable, 'then', {
928 | get: function(){
929 | throw expectedError;
930 | }
931 | });
932 |
933 | wrapped = Promise.resolve(thenable);
934 |
935 | wrapped.then(null, function(error){
936 | assert(error === expectedError, 'incorrect exception was thrown');
937 | done();
938 | });
939 | });
940 |
941 | describe('2.3. If then is a function, call it with x as this, first argument resolvePromise, and second argument rejectPromise, where', function(){
942 | specify('2.3.1 If/when resolvePromise is called with a value y, run Resolve(promise, y)', function(done){
943 | var expectedSuccess, resolver, rejector, thenable, wrapped, calledThis;
944 |
945 | thenable = {
946 | then: function(resolve, reject){
947 | calledThis = this;
948 | resolver = resolve;
949 | rejector = reject;
950 | }
951 | };
952 |
953 | expectedSuccess = 'success';
954 | wrapped = Promise.resolve(thenable);
955 |
956 | wrapped.then(function(success){
957 | assert(calledThis === thenable, 'this must be the thenable');
958 | assert(success === expectedSuccess, 'rejected promise with x');
959 | done();
960 | });
961 |
962 | setTimeout(function() {
963 | resolver(expectedSuccess);
964 | }, 20);
965 | });
966 |
967 | specify('2.3.2 If/when rejectPromise is called with a reason r, reject promise with r.', function(done){
968 | var expectedError, resolver, rejector, thenable, wrapped, calledThis;
969 |
970 | thenable = {
971 | then: function(resolve, reject){
972 | calledThis = this;
973 | resolver = resolve;
974 | rejector = reject;
975 | }
976 | };
977 |
978 | expectedError = new Error();
979 |
980 | wrapped = Promise.resolve(thenable);
981 |
982 | wrapped.then(null, function(error){
983 | assert(error === expectedError, 'rejected promise with x');
984 | done();
985 | });
986 |
987 | setTimeout(function() {
988 | rejector(expectedError);
989 | }, 20);
990 | });
991 |
992 | 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){
993 | var expectedError, expectedSuccess, resolver, rejector, thenable, wrapped, calledThis,
994 | calledRejected, calledResolved;
995 |
996 | calledRejected = 0;
997 | calledResolved = 0;
998 |
999 | thenable = {
1000 | then: function(resolve, reject){
1001 | calledThis = this;
1002 | resolver = resolve;
1003 | rejector = reject;
1004 | }
1005 | };
1006 |
1007 | expectedError = new Error();
1008 |
1009 | wrapped = Promise.resolve(thenable);
1010 |
1011 | wrapped.then(function(){
1012 | calledResolved++;
1013 | }, function(error){
1014 | calledRejected++;
1015 | assert(calledResolved === 0, 'never resolved');
1016 | assert(calledRejected === 1, 'rejected only once');
1017 | assert(error === expectedError, 'rejected promise with x');
1018 | });
1019 |
1020 | setTimeout(function() {
1021 | rejector(expectedError);
1022 | rejector(expectedError);
1023 |
1024 | rejector('foo');
1025 |
1026 | resolver('bar');
1027 | resolver('baz');
1028 | }, 20);
1029 |
1030 | setTimeout(function(){
1031 | assert(calledRejected === 1, 'only rejected once');
1032 | assert(calledResolved === 0, 'never resolved');
1033 | done();
1034 | }, 50);
1035 | });
1036 |
1037 | describe("2.3.4 If calling then throws an exception e", function(){
1038 | specify("2.3.4.1 If resolvePromise or rejectPromise have been called, ignore it.", function(done){
1039 | var expectedSuccess, resolver, rejector, thenable, wrapped, calledThis,
1040 | calledRejected, calledResolved;
1041 |
1042 | expectedSuccess = 'success';
1043 |
1044 | thenable = {
1045 | then: function(resolve, reject){
1046 | resolve(expectedSuccess);
1047 | throw expectedError;
1048 | }
1049 | };
1050 |
1051 | wrapped = Promise.resolve(thenable);
1052 |
1053 | wrapped.then(function(success){
1054 | assert(success === expectedSuccess, 'resolved not errored');
1055 | done();
1056 | });
1057 | });
1058 |
1059 | specify("2.3.4.2 Otherwise, reject promise with e as the reason.", function(done) {
1060 | var expectedError, resolver, rejector, thenable, wrapped, calledThis, callCount;
1061 |
1062 | expectedError = new Error();
1063 | callCount = 0;
1064 |
1065 | thenable = { then: function() { throw expectedError; } };
1066 |
1067 | wrapped = Promise.resolve(thenable);
1068 |
1069 | wrapped.then(null, function(error){
1070 | callCount++;
1071 | assert(expectedError === error, 'expected the correct error to be rejected');
1072 | done();
1073 | });
1074 |
1075 | assert(callCount === 0, 'expected async, was sync');
1076 | });
1077 | });
1078 | });
1079 |
1080 | specify("2.4 If then is not a function, fulfill promise with x", function(done){
1081 | var expectedError, resolver, rejector, thenable, wrapped, calledThis, callCount;
1082 |
1083 | thenable = { then: 3 };
1084 | callCount = 0;
1085 | wrapped = Promise.resolve(thenable);
1086 |
1087 | wrapped.then(function(success){
1088 | callCount++;
1089 | assert(thenable === success, 'fulfilled promise with x');
1090 | done();
1091 | });
1092 |
1093 | assert(callCount === 0, 'expected async, was sync');
1094 | });
1095 | });
1096 |
1097 | describe("3. If x is not an object or function, ", function(){
1098 | specify("fulfill promise with x.", function(done){
1099 | var thenable, callCount, wrapped;
1100 |
1101 | thenable = null;
1102 | callCount = 0;
1103 | wrapped = Promise.resolve(thenable);
1104 |
1105 | wrapped.then(function(success){
1106 | callCount++;
1107 | assert(success === thenable, 'fulfilled promise with x');
1108 | done();
1109 | }, function(a){
1110 | assert(false, 'should not also reject');
1111 | });
1112 |
1113 | assert(callCount === 0, 'expected async, was sync');
1114 | });
1115 | });
1116 | });
1117 |
1118 | if (typeof Worker !== 'undefined' && navigator.userAgent.indexOf('PhantomJS') < 1) {
1119 | describe('web worker', function () {
1120 | it('should work', function (done) {
1121 | this.timeout(2000);
1122 | var worker = new Worker('./worker.js');
1123 | worker.addEventListener('error', function(reason) {
1124 | done(new Error("Test failed:" + reason));
1125 | });
1126 | worker.addEventListener('message', function (e) {
1127 | worker.terminate();
1128 | assert.equal(e.data, 'pong');
1129 | done();
1130 | });
1131 | worker.postMessage('ping');
1132 | });
1133 | });
1134 | }
1135 | });
1136 |
1137 | // thanks to @wizardwerdna for the test case -> https://github.com/tildeio/rsvp.js/issues/66
1138 | // Only run these tests in node (phantomjs cannot handle them)
1139 | if (typeof module !== 'undefined' && module.exports) {
1140 |
1141 | describe("using reduce to sum integers using promises", function(){
1142 | it("should build the promise pipeline without error", function(){
1143 | var array, iters, pZero, i;
1144 |
1145 | array = [];
1146 | iters = 1000;
1147 |
1148 | for (i=1; i<=iters; i++) {
1149 | array.push(i);
1150 | }
1151 |
1152 | pZero = Promise.resolve(0);
1153 |
1154 | array.reduce(function(promise, nextVal) {
1155 | return promise.then(function(currentVal) {
1156 | return Promise.resolve(currentVal + nextVal);
1157 | });
1158 | }, pZero);
1159 | });
1160 |
1161 | it("should get correct answer without blowing the nextTick stack", function(done){
1162 | var pZero, array, iters, result, i;
1163 |
1164 | pZero = Promise.resolve(0);
1165 |
1166 | array = [];
1167 | iters = 1000;
1168 |
1169 | for (i=1; i<=iters; i++) {
1170 | array.push(i);
1171 | }
1172 |
1173 | result = array.reduce(function(promise, nextVal) {
1174 | return promise.then(function(currentVal) {
1175 | return Promise.resolve(currentVal + nextVal);
1176 | });
1177 | }, pZero);
1178 |
1179 | result.then(function(value){
1180 | assert.equal(value, (iters*(iters+1)/2));
1181 | done();
1182 | });
1183 | });
1184 | });
1185 | }
1186 |
1187 | // Kudos to @Octane at https://github.com/getify/native-promise-only/issues/5 for this, and @getify for pinging me.
1188 | describe("Thenables should not be able to run code during assimilation", function () {
1189 | specify("resolving to a thenable", function () {
1190 | var thenCalled = false;
1191 | var thenable = {
1192 | then: function () {
1193 | thenCalled = true;
1194 | }
1195 | };
1196 |
1197 | Promise.resolve(thenable);
1198 | assert.strictEqual(thenCalled, false);
1199 | });
1200 |
1201 | specify("resolving to an evil promise", function () {
1202 | var thenCalled = false;
1203 | var evilPromise = Promise.resolve();
1204 | evilPromise.then = function () {
1205 | thenCalled = true;
1206 | };
1207 |
1208 | Promise.resolve(evilPromise);
1209 | assert.strictEqual(thenCalled, false);
1210 | });
1211 | });
1212 |
1213 | describe('Promise.prototype.finally', function() {
1214 | describe("native finally behaviour", function() {
1215 | describe("no value is passed in", function() {
1216 | it("does not provide a value to the finally code", function(done) {
1217 | var fulfillmentValue = 1;
1218 | var promise = Promise.resolve(fulfillmentValue);
1219 |
1220 | promise['finally'](function() {
1221 | assert.equal(arguments.length, 0);
1222 | done();
1223 | });
1224 | });
1225 |
1226 | it("does not provide a reason to the finally code", function(done) {
1227 | var rejectionReason = new Error();
1228 | var promise = Promise.reject(rejectionReason);
1229 |
1230 | promise['finally'](function(arg) {
1231 | assert.equal(arguments.length, 0);
1232 | done();
1233 | });
1234 | });
1235 | });
1236 |
1237 | describe("non-exceptional cases do not affect the result", function(){
1238 | it("preserves the original fulfillment value even if the finally callback returns a value", function(done) {
1239 | var fulfillmentValue = 1;
1240 | var promise = Promise.resolve(fulfillmentValue);
1241 |
1242 | promise['finally'](function() {
1243 | return 2;
1244 | }).then(function(value) {
1245 | assert.equal(fulfillmentValue, value);
1246 | done();
1247 | });
1248 | });
1249 |
1250 | it("preserves the original rejection reason even if the finally callback returns a value", function(done) {
1251 | var rejectionReason = new Error();
1252 | var promise = Promise.reject(rejectionReason);
1253 |
1254 | promise['finally'](function() {
1255 | return 2;
1256 | }).then(undefined, function(reason) {
1257 | assert.equal(rejectionReason, reason);
1258 | done();
1259 | });
1260 | });
1261 |
1262 | it("preserves the original fulfillment value even if a non-callable callback is given", function(done) {
1263 | var fulfillmentValue = 1;
1264 | var promise = Promise.resolve(fulfillmentValue);
1265 |
1266 | promise['finally']().then(function(value) {
1267 | assert.equal(fulfillmentValue, value);
1268 | done();
1269 | });
1270 | });
1271 |
1272 | it("preserves the original rejection reason even if a non-callable callback is given", function(done) {
1273 | var rejectionReason = new Error();
1274 | var promise = Promise.reject(rejectionReason);
1275 |
1276 | promise['finally']().then(undefined, function(reason) {
1277 | assert.equal(rejectionReason, reason);
1278 | done();
1279 | });
1280 | });
1281 | });
1282 |
1283 | describe("exception cases do propogate the failure", function(){
1284 | describe("fulfilled promise", function(){
1285 | it("propagates changes via throw", function(done) {
1286 | var promise = Promise.resolve(1);
1287 | var expectedReason = new Error();
1288 |
1289 | promise['finally'](function() {
1290 | throw expectedReason;
1291 | }).then(undefined, function(reason) {
1292 | assert.deepEqual(expectedReason, reason);
1293 | done();
1294 | });
1295 | });
1296 |
1297 | it("propagates changes via returned rejected promise", function(done){
1298 | var promise = Promise.resolve(1);
1299 | var expectedReason = new Error();
1300 |
1301 | promise['finally'](function() {
1302 | return Promise.reject(expectedReason);
1303 | }).then(undefined, function(reason) {
1304 | assert.deepEqual(expectedReason, reason);
1305 | done();
1306 | });
1307 | });
1308 | });
1309 |
1310 | describe("rejected promise", function(){
1311 | it("propagates changes via throw", function(done) {
1312 | var promise = Promise.reject(1);
1313 | var expectedReason = new Error();
1314 |
1315 | promise['finally'](function() {
1316 | throw expectedReason;
1317 | }).then(undefined, function(reason) {
1318 | assert.deepEqual(expectedReason, reason);
1319 | done();
1320 | });
1321 | });
1322 |
1323 | it("propagates changes via returned rejected promise", function(done){
1324 | var promise = Promise.reject(1);
1325 | var expectedReason = new Error();
1326 |
1327 | promise['finally'](function() {
1328 | return Promise.reject(expectedReason);
1329 | }).then(undefined, function(reason) {
1330 | assert.deepEqual(expectedReason, reason);
1331 | done();
1332 | });
1333 | });
1334 | });
1335 | });
1336 | });
1337 |
1338 | describe("inheritance", function() {
1339 | function Subclass (resolver) {
1340 | this._promise$constructor(resolver);
1341 | }
1342 |
1343 | Subclass.prototype = Object.create(Promise.Promise.prototype);
1344 | Subclass.prototype.constructor = Subclass;
1345 | Subclass.prototype._promise$constructor = Promise.Promise;
1346 |
1347 | Subclass.resolve = Promise.Promise.resolve;
1348 | Subclass.reject = Promise.Promise.reject;
1349 | Subclass.all = Promise.Promise.all;
1350 |
1351 | it("preserves correct subclass when chained", function() {
1352 | var promise = Subclass.resolve().finally();
1353 | assert.ok(promise instanceof Subclass);
1354 | assert.equal(promise.constructor, Subclass);
1355 | });
1356 |
1357 | it("preserves correct subclass when rejected", function() {
1358 | var promise = Subclass.resolve().finally(function() {
1359 | throw new Error("OMG");
1360 | });
1361 | assert.ok(promise instanceof Subclass);
1362 | assert.equal(promise.constructor, Subclass);
1363 | });
1364 |
1365 | it("preserves correct subclass when someone returns a thenable", function() {
1366 | var promise = Subclass.resolve().finally(function() {
1367 | return Promise.Promise.resolve(1);
1368 | });
1369 | assert.ok(promise instanceof Subclass);
1370 | assert.equal(promise.constructor, Subclass);
1371 | });
1372 | });
1373 | });
1374 |
--------------------------------------------------------------------------------
/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | rsvp.js Tests
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
19 |
20 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/test/scheduler-test.js:
--------------------------------------------------------------------------------
1 | /*global describe, it, assert */
2 |
3 | var g = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : this;
4 | var Promise = g.adapter.Promise;
5 | var assert = require('assert');
6 |
7 | describe('scheduler', function() {
8 | afterEach(function() {
9 | // make sure the es6-promise scheduler is restored after each test
10 | Promise._setScheduler(void 0);
11 | });
12 |
13 | describe('Promise._setScheduler', function() {
14 | it('should allow overriding the default scheduling mechanism', function(done) {
15 | // Wrapped in a setTimeout() to make sure that the microtask queue is empty
16 | // Otherwise we would have len > 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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/testem.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | test_page: "test/index.html",
5 | parallel: 5,
6 | frameworks: "mocha",
7 | launchers: {
8 | Mocha: {
9 | "command": `./node_modules/.bin/mocha ${process.env.EMBER_CLI_TEST_OUTPUT}/test/browserify.js -R tap`,
10 | "protocol": "tap"
11 | }
12 | },
13 | launch_in_ci: [
14 | "Phantomjs",
15 | "Mocha"
16 | ],
17 | launch_in_dev: [
18 | "Phantomjs",
19 | "Mocha"
20 | ],
21 | };
22 |
--------------------------------------------------------------------------------
/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