Import Upstream version 3.7.2+dfsg1
This commit is contained in:
commit
be76ba655c
|
@ -0,0 +1,14 @@
|
|||
# This file is for unifying the coding style for different editors and IDEs
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[**.js]
|
||||
indent_style = space
|
||||
indent_size = 4
|
|
@ -0,0 +1,11 @@
|
|||
docs/Gemfile.lock
|
||||
gh-pages
|
||||
node_modules
|
||||
gh-pages
|
||||
test/browser/bundle.js
|
||||
test/browser/worker_bundle.js
|
||||
js/*
|
||||
zalgo.js
|
||||
coverage/*
|
||||
.vscode
|
||||
.idea
|
|
@ -0,0 +1,49 @@
|
|||
verbose: false
|
||||
instrumentation:
|
||||
root: .
|
||||
default-excludes: true
|
||||
excludes: []
|
||||
embed-source: false
|
||||
variable: __coverage__
|
||||
compact: true
|
||||
preserve-comments: false
|
||||
complete-copy: false
|
||||
save-baseline: false
|
||||
baseline-file: ./coverage/coverage-baseline.json
|
||||
include-all-sources: false
|
||||
reporting:
|
||||
print: summary
|
||||
reports:
|
||||
- lcov
|
||||
dir: ./coverage
|
||||
watermarks:
|
||||
statements: [50, 80]
|
||||
lines: [50, 80]
|
||||
functions: [50, 80]
|
||||
branches: [50, 80]
|
||||
report-config:
|
||||
clover: {file: clover.xml}
|
||||
cobertura: {file: cobertura-coverage.xml}
|
||||
json: {file: coverage-final.json}
|
||||
json-summary: {file: coverage-summary.json}
|
||||
lcovonly: {file: lcov.info}
|
||||
teamcity: {file: null}
|
||||
text: {file: null, maxCols: 0}
|
||||
text-summary: {file: null}
|
||||
hooks:
|
||||
hook-run-in-context: false
|
||||
post-require-hook: null
|
||||
handle-sigint: false
|
||||
check:
|
||||
global:
|
||||
statements: 0
|
||||
lines: 0
|
||||
branches: 0
|
||||
functions: 0
|
||||
excludes: []
|
||||
each:
|
||||
statements: 0
|
||||
lines: 0
|
||||
branches: 0
|
||||
functions: 0
|
||||
excludes: []
|
|
@ -0,0 +1 @@
|
|||
src/constants.js
|
|
@ -0,0 +1,161 @@
|
|||
{
|
||||
"bitwise": false,
|
||||
"camelcase": true,
|
||||
"curly": true,
|
||||
"eqeqeq": true,
|
||||
"es3": true,
|
||||
"forin": true,
|
||||
"immed": true,
|
||||
"latedef": false,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"noempty": true,
|
||||
"nonew": true,
|
||||
"plusplus": false,
|
||||
"quotmark": "double",
|
||||
"undef": true,
|
||||
"unused": true,
|
||||
"strict": false,
|
||||
"maxparams": 6,
|
||||
"maxlen": 80,
|
||||
"asi": false,
|
||||
"boss": true,
|
||||
"eqnull": true,
|
||||
"evil": true,
|
||||
"expr": false,
|
||||
"funcscope": false,
|
||||
"globalstrict": false,
|
||||
"lastsemic": false,
|
||||
"laxcomma": false,
|
||||
"laxbreak": false,
|
||||
"loopfunc": true,
|
||||
"multistr": true,
|
||||
"proto": false,
|
||||
"scripturl": true,
|
||||
"shadow": true,
|
||||
"sub": true,
|
||||
"supernew": false,
|
||||
"validthis": true,
|
||||
"browser": true,
|
||||
"jquery": true,
|
||||
"devel": true,
|
||||
"-W014": true,
|
||||
"-W116": true,
|
||||
"-W106": true,
|
||||
"-W064": true,
|
||||
"-W097": true,
|
||||
"globals": {
|
||||
"Symbol": false,
|
||||
"Map": false,
|
||||
"JSON": false,
|
||||
"Error": true,
|
||||
"args": true,
|
||||
"chrome": true,
|
||||
"INLINE_SLICE": false,
|
||||
"INLINE_SLICE_LEFT_PADDED": false,
|
||||
"BIT_FIELD_CHECK": false,
|
||||
"BIT_FIELD_READ": false,
|
||||
"USE": false,
|
||||
"global": true,
|
||||
"setImmediate": true,
|
||||
"Promise": true,
|
||||
"WebKitMutationObserver": true,
|
||||
"TypeError": true,
|
||||
"RangeError": true,
|
||||
"__DEBUG__": false,
|
||||
"__BROWSER__": false,
|
||||
"process": true,
|
||||
"self": true,
|
||||
"console": false,
|
||||
"require": false,
|
||||
"module": false,
|
||||
"define": false,
|
||||
"LATE_QUEUE_CAPACITY": false,
|
||||
"NORMAL_QUEUE_CAPACITY": false,
|
||||
"ERROR_HANDLED_KEY": false,
|
||||
"OPERATIONAL_ERROR_KEY": false,
|
||||
"DEFAULT_STATE": false,
|
||||
"STACK_ATTACHED": false,
|
||||
"ERROR_HANDLED": false,
|
||||
"GENERATED_CLASS_COUNT": false,
|
||||
"USE_BOUND": false,
|
||||
"DONT_USE_BOUND": false,
|
||||
"PROPAGATE_CANCEL": false,
|
||||
"PROPAGATE_BIND": false,
|
||||
"PROPAGATE_ALL": false,
|
||||
"CALLBACK_FULFILL_OFFSET": false,
|
||||
"CALLBACK_REJECT_OFFSET": false,
|
||||
"CALLBACK_PROMISE_OFFSET": false,
|
||||
"CALLBACK_RECEIVER_OFFSET": false,
|
||||
"CALLBACK_SIZE": false,
|
||||
"ASYNC_GUARANTEE_SHIFT": false,
|
||||
"NO_STATE": false,
|
||||
"NO_ASYNC_GUARANTEE": false,
|
||||
"RETURNED_NON_UNDEFINED": false,
|
||||
"IS_ASYNC_GUARANTEED": false,
|
||||
"IS_FOLLOWING": false,
|
||||
"IS_FULFILLED": false,
|
||||
"IS_REJECTED": false,
|
||||
"WILL_BE_CANCELLED": false,
|
||||
"IS_FINAL": false,
|
||||
"IS_BOUND": false,
|
||||
"IS_REJECTION_UNHANDLED": false,
|
||||
"IS_REJECTION_IGNORED": false,
|
||||
"IS_UNHANDLED_REJECTION_NOTIFIED": false,
|
||||
"IS_DISPOSABLE": false,
|
||||
"IS_CANCELLED": false,
|
||||
"IS_CANCELLED_OR_WILL_BE_CANCELLED": false,
|
||||
"LENGTH_MASK": false,
|
||||
"LENGTH_CLEAR_MASK": false,
|
||||
"MAX_LENGTH": false,
|
||||
"IS_REJECTED_OR_CANCELLED": false,
|
||||
"IS_REJECTED_OR_FULFILLED": false,
|
||||
"IS_REJECTED_OR_FULFILLED_OR_CANCELLED": false,
|
||||
"IS_PENDING_AND_WAITING_NEG": false,
|
||||
"IS_FATE_SEALED": false,
|
||||
"AFTER_PROMISIFIED_SUFFIX": false,
|
||||
"UNHANDLED_REJECTION_EVENT": false,
|
||||
"REJECTION_HANDLED_EVENT": false,
|
||||
"RESOLVE_UNDEFINED": false,
|
||||
"RESOLVE_ARRAY": false,
|
||||
"RESOLVE_OBJECT": false,
|
||||
"RESOLVE_FOREVER_PENDING": false,
|
||||
"RESOLVE_CALL_METHOD": false,
|
||||
"RESOLVE_MAP": false,
|
||||
"QUEUE_MAX_CAPACITY": false,
|
||||
"QUEUE_MIN_CAPACITY": false,
|
||||
"FROM_PREVIOUS_EVENT": false,
|
||||
"NO_STACK_TRACE": false,
|
||||
"ADDITIONAL_STACK_TRACE": false,
|
||||
"UNHANDLED_REJECTION_HEADER": false,
|
||||
"FINALLY_TYPE": false,
|
||||
"TAP_TYPE": false,
|
||||
"THROW": false,
|
||||
"RETURN": false,
|
||||
"MAX_PARAM_COUNT": false,
|
||||
"PARAM_COUNTS_TO_TRY": false,
|
||||
"BLUEBIRD_ERRORS": false,
|
||||
"OBJECT_PROMISIFY_DEPRECATED": false,
|
||||
"SPAWN_DEPRECATED": false,
|
||||
"LATE_CANCELLATION_OBSERVER": false,
|
||||
"TIMEOUT_ERROR": false,
|
||||
"COLLECTION_ERROR": false,
|
||||
"OBJECT_ERROR": false,
|
||||
"FUNCTION_ERROR": false,
|
||||
"CONSTRUCT_ERROR_INVOCATION": false,
|
||||
"NOT_GENERATOR_ERROR": false,
|
||||
"LONG_STACK_TRACES_ERROR": false,
|
||||
"INSPECTION_VALUE_ERROR": false,
|
||||
"INSPECTION_REASON_ERROR": false,
|
||||
"PROMISIFY_TYPE_ERROR": false,
|
||||
"CIRCULAR_RESOLUTION_ERROR": false,
|
||||
"PROPS_TYPE_ERROR": false,
|
||||
"POSITIVE_INTEGER_ERROR": false,
|
||||
"YIELDED_NON_PROMISE_ERROR": false,
|
||||
"FROM_COROUTINE_CREATED_AT": false,
|
||||
"UNBOUND_RESOLVER_INVOCATION": false,
|
||||
"PROMISIFICATION_NORMAL_METHODS_ERROR": false,
|
||||
"SUFFIX_NOT_IDENTIFIER": false,
|
||||
"NO_ASYNC_SCHEDULER": false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
language: node_js
|
||||
sudo: false
|
||||
matrix:
|
||||
include:
|
||||
- node_js: "0.10"
|
||||
- node_js: "0.12"
|
||||
- node_js: "4"
|
||||
- node_js: "5"
|
||||
- node_js: "6"
|
||||
- node_js: "7"
|
||||
- node_js: "8"
|
||||
- node_js: "10"
|
||||
fast_finish: true
|
||||
git:
|
||||
depth: 5
|
||||
env:
|
||||
- "NODE_FLAGS='--expose-gc' SCRIPT_FLAGS=''"
|
||||
before_script:
|
||||
- git submodule update --init --recursive
|
||||
script: "node $NODE_FLAGS tools/test.js $SCRIPT_FLAGS"
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
cache:
|
||||
directories:
|
||||
- "$HOME/.npm"
|
|
@ -0,0 +1 @@
|
|||
[http://bluebirdjs.com/docs/api-reference.html](http://bluebirdjs.com/docs/api-reference.html)
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
# Questions and issues
|
||||
|
||||
Please see [The Support Page](http://bluebirdjs.com/docs/support.html)
|
||||
The [github issue tracker](https://github.com/petkaantonov/bluebird/issues) is **_only_** for bug reports and feature requests.
|
||||
|
||||
# Contributing to the library
|
||||
|
||||
Contributions are welcome and appreciated. See the [Contribution Page](http://bluebirdjs.com/docs/contribute.html) on bluebirdjs.com
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2018 Petka Antonov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -0,0 +1,57 @@
|
|||
<a href="http://promisesaplus.com/">
|
||||
<img src="http://promisesaplus.com/assets/logo-small.png" alt="Promises/A+ logo"
|
||||
title="Promises/A+ 1.1 compliant" align="right" />
|
||||
</a>
|
||||
|
||||
|
||||
[![Build Status](https://travis-ci.org/petkaantonov/bluebird.svg?branch=master)](https://travis-ci.org/petkaantonov/bluebird)
|
||||
[![coverage-98%](https://img.shields.io/badge/coverage-98%25-brightgreen.svg?style=flat)](http://petkaantonov.github.io/bluebird/coverage/debug/index.html)
|
||||
|
||||
**Got a question?** Join us on [stackoverflow](http://stackoverflow.com/questions/tagged/bluebird), the [mailing list](https://groups.google.com/forum/#!forum/bluebird-js) or chat on [IRC](https://webchat.freenode.net/?channels=#promises)
|
||||
|
||||
# Introduction
|
||||
|
||||
Bluebird is a fully featured promise library with focus on innovative features and performance
|
||||
|
||||
See the [**bluebird website**](http://bluebirdjs.com/docs/getting-started.html) for further documentation, references and instructions. See the [**API reference**](http://bluebirdjs.com/docs/api-reference.html) here.
|
||||
|
||||
For bluebird 2.x documentation and files, see the [2.x tree](https://github.com/petkaantonov/bluebird/tree/2.x).
|
||||
|
||||
### Note
|
||||
|
||||
Promises in Node.js 10 are significantly faster than before. Bluebird still includes a lot of features like cancellation, iteration methods and warnings that native promises don't. If you are using Bluebird for performance rather than for those - please consider giving native promises a shot and running the benchmarks yourself.
|
||||
|
||||
# Questions and issues
|
||||
|
||||
The [github issue tracker](https://github.com/petkaantonov/bluebird/issues) is **_only_** for bug reports and feature requests. Anything else, such as questions for help in using the library, should be posted in [StackOverflow](http://stackoverflow.com/questions/tagged/bluebird) under tags `promise` and `bluebird`.
|
||||
|
||||
|
||||
|
||||
## Thanks
|
||||
|
||||
Thanks to BrowserStack for providing us with a free account which lets us support old browsers like IE8.
|
||||
|
||||
# License
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2019 Petka Antonov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
#!/usr/bin/env bash
|
||||
./build --release --no-debug
|
||||
benchmark=$1
|
||||
nodepath=${2:-node}
|
||||
shift 2;
|
||||
cwd=${PWD}
|
||||
|
||||
export NODE_ENV=production
|
||||
|
||||
trap 'cd "$cwd"' EXIT
|
||||
|
||||
if [ "$benchmark" = "doxbee" ]; then
|
||||
cd "$cwd/benchmark"
|
||||
npm install
|
||||
echo "Doxbee sequential"
|
||||
$nodepath performance.js --n 10000 --t 1 ./doxbee-sequential/*.js --harmony "$@"
|
||||
exit 0
|
||||
elif [ "$benchmark" = "doxbee-errors" ]; then
|
||||
cd "$cwd/benchmark"
|
||||
npm install
|
||||
echo "Doxbee sequential with 10% errors"
|
||||
$nodepath performance.js --n 10000 --t 1 --e 0.1 ./doxbee-sequential-errors/*.js --harmony "$@"
|
||||
exit 0
|
||||
elif [ "$benchmark" = "parallel" ]; then
|
||||
cd "$cwd/benchmark"
|
||||
npm install
|
||||
echo "Madeup parallel"
|
||||
$nodepath performance.js --n 10000 --t 1 --p 25 ./madeup-parallel/*.js --harmony "$@"
|
||||
exit 0
|
||||
elif [ "$benchmark" = "analysis" ]; then
|
||||
cd "$cwd/benchmark"
|
||||
npm install
|
||||
echo "analysis"
|
||||
$nodepath performance.js --n 10000 --t 1 ./analysis/*.js --harmony "$@"
|
||||
exit 0
|
||||
else
|
||||
echo "Invalid benchmark name $benchmark"
|
||||
exit -1
|
||||
fi
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"name": "bluebird",
|
||||
"version": "3.7.2",
|
||||
"homepage": "https://github.com/petkaantonov/bluebird",
|
||||
"authors": [
|
||||
"Petka Antonov <petka_antonov@hotmail.com>"
|
||||
],
|
||||
"description": "Bluebird is a full featured promise library with unmatched performance.",
|
||||
"main": "js/browser/bluebird.js",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"benchmark",
|
||||
"bower_components",
|
||||
"./browser",
|
||||
"node_modules",
|
||||
"test"
|
||||
],
|
||||
"keywords": [
|
||||
"promise",
|
||||
"performance",
|
||||
"promises",
|
||||
"promises-a",
|
||||
"promises-aplus",
|
||||
"async",
|
||||
"await",
|
||||
"deferred",
|
||||
"deferreds",
|
||||
"future",
|
||||
"flow control",
|
||||
"dsl",
|
||||
"fluent interface"
|
||||
]
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
[http://bluebirdjs.com/docs/changelog.html](http://bluebirdjs.com/docs/changelog.html)
|
|
@ -0,0 +1 @@
|
|||
[http://bluebirdjs.com/docs/deprecated-apis.html](http://bluebirdjs.com/docs/deprecated-apis.html)
|
|
@ -0,0 +1,12 @@
|
|||
(This issue tracker is only for bug reports or feature requests, if this is neither, please choose appropriate channel from http://bluebirdjs.com/docs/support.html)
|
||||
|
||||
Please answer the questions the best you can:
|
||||
|
||||
1) What version of bluebird is the issue happening on?
|
||||
|
||||
2) What platform and version? (For example Node.js 0.12 or Google Chrome 32)
|
||||
|
||||
3) Did this issue happen with earlier version of bluebird?
|
||||
|
||||
(Write description of your issue here, stack traces from errors and code that reproduces the issue are helpful)
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,78 @@
|
|||
{
|
||||
"name": "bluebird",
|
||||
"description": "Full featured Promises/A+ implementation with exceptionally good performance",
|
||||
"version": "3.7.2",
|
||||
"keywords": [
|
||||
"promise",
|
||||
"performance",
|
||||
"promises",
|
||||
"promises-a",
|
||||
"promises-aplus",
|
||||
"async",
|
||||
"await",
|
||||
"deferred",
|
||||
"deferreds",
|
||||
"future",
|
||||
"flow control",
|
||||
"dsl",
|
||||
"fluent interface"
|
||||
],
|
||||
"scripts": {
|
||||
"lint": "node scripts/jshint.js",
|
||||
"test": "node --expose-gc tools/test.js",
|
||||
"istanbul": "istanbul",
|
||||
"prepublish": "npm run generate-browser-core && npm run generate-browser-full",
|
||||
"generate-browser-full": "node tools/build.js --no-clean --no-debug --release --browser --minify",
|
||||
"generate-browser-core": "node tools/build.js --features=core --no-debug --release --zalgo --browser --minify && mv js/browser/bluebird.js js/browser/bluebird.core.js && mv js/browser/bluebird.min.js js/browser/bluebird.core.min.js"
|
||||
},
|
||||
"homepage": "https://github.com/petkaantonov/bluebird",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/petkaantonov/bluebird.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "http://github.com/petkaantonov/bluebird/issues"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": {
|
||||
"name": "Petka Antonov",
|
||||
"email": "petka_antonov@hotmail.com",
|
||||
"url": "http://github.com/petkaantonov/"
|
||||
},
|
||||
"devDependencies": {
|
||||
"acorn": "^6.0.2",
|
||||
"acorn-walk": "^6.1.0",
|
||||
"baconjs": "^0.7.43",
|
||||
"bluebird": "^2.9.2",
|
||||
"body-parser": "^1.10.2",
|
||||
"browserify": "^8.1.1",
|
||||
"cli-table": "~0.3.1",
|
||||
"co": "^4.2.0",
|
||||
"cross-spawn": "^0.2.3",
|
||||
"glob": "^4.3.2",
|
||||
"grunt-saucelabs": "~8.4.1",
|
||||
"highland": "^2.3.0",
|
||||
"istanbul": "^0.3.5",
|
||||
"jshint": "^2.6.0",
|
||||
"jshint-stylish": "~0.2.0",
|
||||
"kefir": "^2.4.1",
|
||||
"mkdirp": "~0.5.0",
|
||||
"mocha": "~2.1",
|
||||
"open": "~0.0.5",
|
||||
"optimist": "~0.6.1",
|
||||
"rimraf": "~2.2.6",
|
||||
"rx": "^2.3.25",
|
||||
"serve-static": "^1.7.1",
|
||||
"sinon": "~1.7.3",
|
||||
"uglify-js": "~2.4.16"
|
||||
},
|
||||
"readmeFilename": "README.md",
|
||||
"main": "./js/release/bluebird.js",
|
||||
"webpack": "./js/release/bluebird.js",
|
||||
"browser": "./js/browser/bluebird.js",
|
||||
"files": [
|
||||
"js/browser",
|
||||
"js/release",
|
||||
"LICENSE"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
"use strict";
|
||||
module.exports = function(Promise) {
|
||||
var SomePromiseArray = Promise._SomePromiseArray;
|
||||
var ASSERT = require("./assert");
|
||||
|
||||
function any(promises) {
|
||||
var ret = new SomePromiseArray(promises);
|
||||
var promise = ret.promise();
|
||||
ASSERT(promise.isPending());
|
||||
ASSERT(ret instanceof SomePromiseArray);
|
||||
ret.setHowMany(1);
|
||||
ret.setUnwrap();
|
||||
ret.init();
|
||||
return promise;
|
||||
}
|
||||
|
||||
Promise.any = function (promises) {
|
||||
return any(promises);
|
||||
};
|
||||
|
||||
Promise.prototype.any = function () {
|
||||
return any(this);
|
||||
};
|
||||
|
||||
};
|
|
@ -0,0 +1,55 @@
|
|||
"use strict";
|
||||
module.exports = (function(){
|
||||
var AssertionError = (function() {
|
||||
function AssertionError(a) {
|
||||
this.constructor$(a);
|
||||
this.message = a;
|
||||
this.name = "AssertionError";
|
||||
}
|
||||
AssertionError.prototype = new Error();
|
||||
AssertionError.prototype.constructor = AssertionError;
|
||||
AssertionError.prototype.constructor$ = Error;
|
||||
return AssertionError;
|
||||
})();
|
||||
|
||||
function getParams(args) {
|
||||
var params = [];
|
||||
for (var i = 0; i < args.length; ++i) params.push("arg" + i);
|
||||
return params;
|
||||
}
|
||||
|
||||
function nativeAssert(callName, args, expect) {
|
||||
try {
|
||||
var params = getParams(args);
|
||||
var constructorArgs = params;
|
||||
constructorArgs.push("return " +
|
||||
callName + "("+ params.join(",") + ");");
|
||||
var fn = Function.apply(null, constructorArgs);
|
||||
return fn.apply(null, args);
|
||||
} catch (e) {
|
||||
if (!(e instanceof SyntaxError)) {
|
||||
throw e;
|
||||
} else {
|
||||
return expect;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return function assert(boolExpr, message) {
|
||||
if (boolExpr === true) return;
|
||||
|
||||
if (typeof boolExpr === "string" &&
|
||||
boolExpr.charAt(0) === "%") {
|
||||
var nativeCallName = boolExpr;
|
||||
INLINE_SLICE(args, arguments, 2);
|
||||
if (nativeAssert(nativeCallName, args, message) === message) return;
|
||||
message = (nativeCallName + " !== " + message);
|
||||
}
|
||||
|
||||
var ret = new AssertionError(message);
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(ret, assert);
|
||||
}
|
||||
throw ret;
|
||||
};
|
||||
})();
|
|
@ -0,0 +1,129 @@
|
|||
"use strict";
|
||||
var firstLineError;
|
||||
try {throw new Error(); } catch (e) {firstLineError = e;}
|
||||
var ASSERT = require("./assert");
|
||||
var schedule = require("./schedule");
|
||||
var Queue = require("./queue");
|
||||
|
||||
function Async() {
|
||||
this._customScheduler = false;
|
||||
this._isTickUsed = false;
|
||||
this._lateQueue = new Queue(LATE_QUEUE_CAPACITY);
|
||||
this._normalQueue = new Queue(NORMAL_QUEUE_CAPACITY);
|
||||
this._haveDrainedQueues = false;
|
||||
var self = this;
|
||||
this.drainQueues = function () {
|
||||
self._drainQueues();
|
||||
};
|
||||
this._schedule = schedule;
|
||||
}
|
||||
|
||||
Async.prototype.setScheduler = function(fn) {
|
||||
var prev = this._schedule;
|
||||
this._schedule = fn;
|
||||
this._customScheduler = true;
|
||||
return prev;
|
||||
};
|
||||
|
||||
Async.prototype.hasCustomScheduler = function() {
|
||||
return this._customScheduler;
|
||||
};
|
||||
|
||||
Async.prototype.haveItemsQueued = function () {
|
||||
return this._isTickUsed || this._haveDrainedQueues;
|
||||
};
|
||||
|
||||
|
||||
Async.prototype.fatalError = function(e, isNode) {
|
||||
if (isNode) {
|
||||
process.stderr.write("Fatal " + (e instanceof Error ? e.stack : e) +
|
||||
"\n");
|
||||
process.exit(2);
|
||||
} else {
|
||||
this.throwLater(e);
|
||||
}
|
||||
};
|
||||
|
||||
// Must be used if fn can throw
|
||||
Async.prototype.throwLater = function(fn, arg) {
|
||||
if (arguments.length === 1) {
|
||||
arg = fn;
|
||||
fn = function () { throw arg; };
|
||||
}
|
||||
if (typeof setTimeout !== "undefined") {
|
||||
setTimeout(function() {
|
||||
fn(arg);
|
||||
}, 0);
|
||||
} else try {
|
||||
this._schedule(function() {
|
||||
fn(arg);
|
||||
});
|
||||
} catch (e) {
|
||||
throw new Error(NO_ASYNC_SCHEDULER);
|
||||
}
|
||||
};
|
||||
|
||||
//When the fn absolutely needs to be called after
|
||||
//the queue has been completely flushed
|
||||
function AsyncInvokeLater(fn, receiver, arg) {
|
||||
ASSERT(arguments.length === 3);
|
||||
this._lateQueue.push(fn, receiver, arg);
|
||||
this._queueTick();
|
||||
}
|
||||
|
||||
function AsyncInvoke(fn, receiver, arg) {
|
||||
ASSERT(arguments.length === 3);
|
||||
this._normalQueue.push(fn, receiver, arg);
|
||||
this._queueTick();
|
||||
}
|
||||
|
||||
function AsyncSettlePromises(promise) {
|
||||
this._normalQueue._pushOne(promise);
|
||||
this._queueTick();
|
||||
}
|
||||
|
||||
Async.prototype.invokeLater = AsyncInvokeLater;
|
||||
Async.prototype.invoke = AsyncInvoke;
|
||||
Async.prototype.settlePromises = AsyncSettlePromises;
|
||||
|
||||
|
||||
function _drainQueue(queue) {
|
||||
while (queue.length() > 0) {
|
||||
_drainQueueStep(queue);
|
||||
}
|
||||
}
|
||||
|
||||
// Shift the queue in a separate function to allow
|
||||
// garbage collection after each step
|
||||
function _drainQueueStep(queue) {
|
||||
var fn = queue.shift();
|
||||
if (typeof fn !== "function") {
|
||||
fn._settlePromises();
|
||||
} else {
|
||||
var receiver = queue.shift();
|
||||
var arg = queue.shift();
|
||||
fn.call(receiver, arg);
|
||||
}
|
||||
}
|
||||
|
||||
Async.prototype._drainQueues = function () {
|
||||
ASSERT(this._isTickUsed);
|
||||
_drainQueue(this._normalQueue);
|
||||
this._reset();
|
||||
this._haveDrainedQueues = true;
|
||||
_drainQueue(this._lateQueue);
|
||||
};
|
||||
|
||||
Async.prototype._queueTick = function () {
|
||||
if (!this._isTickUsed) {
|
||||
this._isTickUsed = true;
|
||||
this._schedule(this.drainQueues);
|
||||
}
|
||||
};
|
||||
|
||||
Async.prototype._reset = function () {
|
||||
this._isTickUsed = false;
|
||||
};
|
||||
|
||||
module.exports = Async;
|
||||
module.exports.firstLineError = firstLineError;
|
|
@ -0,0 +1,67 @@
|
|||
"use strict";
|
||||
module.exports = function(Promise, INTERNAL, tryConvertToPromise, debug) {
|
||||
var calledBind = false;
|
||||
var rejectThis = function(_, e) {
|
||||
this._reject(e);
|
||||
};
|
||||
|
||||
var targetRejected = function(e, context) {
|
||||
context.promiseRejectionQueued = true;
|
||||
context.bindingPromise._then(rejectThis, rejectThis, null, this, e);
|
||||
};
|
||||
|
||||
var bindingResolved = function(thisArg, context) {
|
||||
if (BIT_FIELD_CHECK(IS_PENDING_AND_WAITING_NEG, this._bitField)) {
|
||||
this._resolveCallback(context.target);
|
||||
}
|
||||
};
|
||||
|
||||
var bindingRejected = function(e, context) {
|
||||
if (!context.promiseRejectionQueued) this._reject(e);
|
||||
};
|
||||
|
||||
Promise.prototype.bind = function (thisArg) {
|
||||
if (!calledBind) {
|
||||
calledBind = true;
|
||||
Promise.prototype._propagateFrom = debug.propagateFromFunction();
|
||||
Promise.prototype._boundValue = debug.boundValueFunction();
|
||||
}
|
||||
var maybePromise = tryConvertToPromise(thisArg);
|
||||
var ret = new Promise(INTERNAL);
|
||||
ret._propagateFrom(this, PROPAGATE_CANCEL);
|
||||
var target = this._target();
|
||||
ret._setBoundTo(maybePromise);
|
||||
if (maybePromise instanceof Promise) {
|
||||
var context = {
|
||||
promiseRejectionQueued: false,
|
||||
promise: ret,
|
||||
target: target,
|
||||
bindingPromise: maybePromise
|
||||
};
|
||||
target._then(INTERNAL, targetRejected, undefined, ret, context);
|
||||
maybePromise._then(
|
||||
bindingResolved, bindingRejected, undefined, ret, context);
|
||||
ret._setOnCancel(maybePromise);
|
||||
} else {
|
||||
ret._resolveCallback(target);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
Promise.prototype._setBoundTo = function (obj) {
|
||||
if (obj !== undefined) {
|
||||
this._bitField = this._bitField | IS_BOUND;
|
||||
this._boundTo = obj;
|
||||
} else {
|
||||
this._bitField = this._bitField & (~IS_BOUND);
|
||||
}
|
||||
};
|
||||
|
||||
Promise.prototype._isBound = function () {
|
||||
return (this._bitField & IS_BOUND) === IS_BOUND;
|
||||
};
|
||||
|
||||
Promise.bind = function (thisArg, value) {
|
||||
return Promise.resolve(value).bind(thisArg);
|
||||
};
|
||||
};
|
|
@ -0,0 +1,11 @@
|
|||
"use strict";
|
||||
var old;
|
||||
if (typeof Promise !== "undefined") old = Promise;
|
||||
function noConflict() {
|
||||
try { if (Promise === bluebird) Promise = old; }
|
||||
catch (e) {}
|
||||
return bluebird;
|
||||
}
|
||||
var bluebird = require("./promise")();
|
||||
bluebird.noConflict = noConflict;
|
||||
module.exports = bluebird;
|
|
@ -0,0 +1,123 @@
|
|||
"use strict";
|
||||
var cr = Object.create;
|
||||
if (cr) {
|
||||
var callerCache = cr(null);
|
||||
var getterCache = cr(null);
|
||||
callerCache[" size"] = getterCache[" size"] = 0;
|
||||
}
|
||||
|
||||
module.exports = function(Promise) {
|
||||
var util = require("./util");
|
||||
var canEvaluate = util.canEvaluate;
|
||||
var isIdentifier = util.isIdentifier;
|
||||
|
||||
var getMethodCaller;
|
||||
var getGetter;
|
||||
if (!__BROWSER__) {
|
||||
var makeMethodCaller = function (methodName) {
|
||||
return new Function("ensureMethod", " \n\
|
||||
return function(obj) { \n\
|
||||
'use strict' \n\
|
||||
var len = this.length; \n\
|
||||
ensureMethod(obj, 'methodName'); \n\
|
||||
switch(len) { \n\
|
||||
case 1: return obj.methodName(this[0]); \n\
|
||||
case 2: return obj.methodName(this[0], this[1]); \n\
|
||||
case 3: return obj.methodName(this[0], this[1], this[2]); \n\
|
||||
case 0: return obj.methodName(); \n\
|
||||
default: \n\
|
||||
return obj.methodName.apply(obj, this); \n\
|
||||
} \n\
|
||||
}; \n\
|
||||
".replace(/methodName/g, methodName))(ensureMethod);
|
||||
};
|
||||
|
||||
var makeGetter = function (propertyName) {
|
||||
return new Function("obj", " \n\
|
||||
'use strict'; \n\
|
||||
return obj.propertyName; \n\
|
||||
".replace("propertyName", propertyName));
|
||||
};
|
||||
|
||||
var getCompiled = function(name, compiler, cache) {
|
||||
var ret = cache[name];
|
||||
if (typeof ret !== "function") {
|
||||
if (!isIdentifier(name)) {
|
||||
return null;
|
||||
}
|
||||
ret = compiler(name);
|
||||
cache[name] = ret;
|
||||
cache[" size"]++;
|
||||
if (cache[" size"] > 512) {
|
||||
var keys = Object.keys(cache);
|
||||
for (var i = 0; i < 256; ++i) delete cache[keys[i]];
|
||||
cache[" size"] = keys.length - 256;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
getMethodCaller = function(name) {
|
||||
return getCompiled(name, makeMethodCaller, callerCache);
|
||||
};
|
||||
|
||||
getGetter = function(name) {
|
||||
return getCompiled(name, makeGetter, getterCache);
|
||||
};
|
||||
}
|
||||
|
||||
function ensureMethod(obj, methodName) {
|
||||
var fn;
|
||||
if (obj != null) fn = obj[methodName];
|
||||
if (typeof fn !== "function") {
|
||||
var message = "Object " + util.classString(obj) + " has no method '" +
|
||||
util.toString(methodName) + "'";
|
||||
throw new Promise.TypeError(message);
|
||||
}
|
||||
return fn;
|
||||
}
|
||||
|
||||
function caller(obj) {
|
||||
var methodName = this.pop();
|
||||
var fn = ensureMethod(obj, methodName);
|
||||
return fn.apply(obj, this);
|
||||
}
|
||||
Promise.prototype.call = function (methodName) {
|
||||
INLINE_SLICE(args, arguments, 1);
|
||||
if (!__BROWSER__) {
|
||||
if (canEvaluate) {
|
||||
var maybeCaller = getMethodCaller(methodName);
|
||||
if (maybeCaller !== null) {
|
||||
return this._then(
|
||||
maybeCaller, undefined, undefined, args, undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
args.push(methodName);
|
||||
return this._then(caller, undefined, undefined, args, undefined);
|
||||
};
|
||||
|
||||
function namedGetter(obj) {
|
||||
return obj[this];
|
||||
}
|
||||
function indexedGetter(obj) {
|
||||
var index = +this;
|
||||
if (index < 0) index = Math.max(0, index + obj.length);
|
||||
return obj[index];
|
||||
}
|
||||
Promise.prototype.get = function (propertyName) {
|
||||
var isIndex = (typeof propertyName === "number");
|
||||
var getter;
|
||||
if (!isIndex) {
|
||||
if (canEvaluate) {
|
||||
var maybeGetter = getGetter(propertyName);
|
||||
getter = maybeGetter !== null ? maybeGetter : namedGetter;
|
||||
} else {
|
||||
getter = namedGetter;
|
||||
}
|
||||
} else {
|
||||
getter = indexedGetter;
|
||||
}
|
||||
return this._then(getter, undefined, undefined, propertyName, undefined);
|
||||
};
|
||||
};
|
|
@ -0,0 +1,136 @@
|
|||
"use strict";
|
||||
module.exports = function(Promise, PromiseArray, apiRejection, debug) {
|
||||
var ASSERT = require("./assert");
|
||||
var util = require("./util");
|
||||
var tryCatch = util.tryCatch;
|
||||
var errorObj = util.errorObj;
|
||||
var async = Promise._async;
|
||||
|
||||
Promise.prototype["break"] = Promise.prototype.cancel = function() {
|
||||
if (!debug.cancellation()) return this._warn("cancellation is disabled");
|
||||
|
||||
var promise = this;
|
||||
var child = promise;
|
||||
while (promise._isCancellable()) {
|
||||
if (!promise._cancelBy(child)) {
|
||||
if (child._isFollowing()) {
|
||||
child._followee().cancel();
|
||||
} else {
|
||||
child._cancelBranched();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
var parent = promise._cancellationParent;
|
||||
if (parent == null || !parent._isCancellable()) {
|
||||
if (promise._isFollowing()) {
|
||||
promise._followee().cancel();
|
||||
} else {
|
||||
promise._cancelBranched();
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
if (promise._isFollowing()) promise._followee().cancel();
|
||||
promise._setWillBeCancelled();
|
||||
child = promise;
|
||||
promise = parent;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Promise.prototype._branchHasCancelled = function() {
|
||||
ASSERT(typeof this._branchesRemainingToCancel === "number");
|
||||
this._branchesRemainingToCancel--;
|
||||
};
|
||||
|
||||
Promise.prototype._enoughBranchesHaveCancelled = function() {
|
||||
return this._branchesRemainingToCancel === undefined ||
|
||||
this._branchesRemainingToCancel <= 0;
|
||||
};
|
||||
|
||||
Promise.prototype._cancelBy = function(canceller) {
|
||||
if (canceller === this) {
|
||||
this._branchesRemainingToCancel = 0;
|
||||
this._invokeOnCancel();
|
||||
return true;
|
||||
} else {
|
||||
ASSERT(canceller._cancellationParent === this);
|
||||
this._branchHasCancelled();
|
||||
if (this._enoughBranchesHaveCancelled()) {
|
||||
this._invokeOnCancel();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
Promise.prototype._cancelBranched = function() {
|
||||
if (this._enoughBranchesHaveCancelled()) {
|
||||
this._cancel();
|
||||
}
|
||||
};
|
||||
|
||||
Promise.prototype._cancel = function() {
|
||||
if (!this._isCancellable()) return;
|
||||
ASSERT(!this._isFollowing());
|
||||
this._setCancelled();
|
||||
async.invoke(this._cancelPromises, this, undefined);
|
||||
};
|
||||
|
||||
Promise.prototype._cancelPromises = function() {
|
||||
if (this._length() > 0) this._settlePromises();
|
||||
};
|
||||
|
||||
Promise.prototype._unsetOnCancel = function() {
|
||||
ASSERT(this._isCancellable() || this._isCancelled());
|
||||
this._onCancelField = undefined;
|
||||
};
|
||||
|
||||
Promise.prototype._isCancellable = function() {
|
||||
return this.isPending() && !this._isCancelled();
|
||||
};
|
||||
|
||||
Promise.prototype.isCancellable = function() {
|
||||
return this.isPending() && !this.isCancelled();
|
||||
};
|
||||
|
||||
Promise.prototype._doInvokeOnCancel = function(onCancelCallback, internalOnly) {
|
||||
if (util.isArray(onCancelCallback)) {
|
||||
for (var i = 0; i < onCancelCallback.length; ++i) {
|
||||
this._doInvokeOnCancel(onCancelCallback[i], internalOnly);
|
||||
}
|
||||
} else if (onCancelCallback !== undefined) {
|
||||
if (typeof onCancelCallback === "function") {
|
||||
if (!internalOnly) {
|
||||
var e = tryCatch(onCancelCallback).call(this._boundValue());
|
||||
if (e === errorObj) {
|
||||
this._attachExtraTrace(e.e);
|
||||
async.throwLater(e.e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
onCancelCallback._resultCancelled(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Promise.prototype._invokeOnCancel = function() {
|
||||
var onCancelCallback = this._onCancel();
|
||||
// The existence of onCancel handler on a promise signals that the handler
|
||||
// has not been queued for invocation yet.
|
||||
this._unsetOnCancel();
|
||||
async.invoke(this._doInvokeOnCancel, this, onCancelCallback);
|
||||
};
|
||||
|
||||
Promise.prototype._invokeInternalOnCancel = function() {
|
||||
if (this._isCancellable()) {
|
||||
this._doInvokeOnCancel(this._onCancel(), true);
|
||||
this._unsetOnCancel();
|
||||
}
|
||||
};
|
||||
|
||||
Promise.prototype._resultCancelled = function() {
|
||||
this.cancel();
|
||||
};
|
||||
|
||||
};
|
|
@ -0,0 +1,42 @@
|
|||
"use strict";
|
||||
module.exports = function(NEXT_FILTER) {
|
||||
var util = require("./util");
|
||||
var getKeys = require("./es5").keys;
|
||||
var tryCatch = util.tryCatch;
|
||||
var errorObj = util.errorObj;
|
||||
|
||||
function catchFilter(instances, cb, promise) {
|
||||
return function(e) {
|
||||
var boundTo = promise._boundValue();
|
||||
predicateLoop: for (var i = 0; i < instances.length; ++i) {
|
||||
var item = instances[i];
|
||||
|
||||
if (item === Error ||
|
||||
(item != null && item.prototype instanceof Error)) {
|
||||
if (e instanceof item) {
|
||||
return tryCatch(cb).call(boundTo, e);
|
||||
}
|
||||
} else if (typeof item === "function") {
|
||||
var matchesPredicate = tryCatch(item).call(boundTo, e);
|
||||
if (matchesPredicate === errorObj) {
|
||||
return matchesPredicate;
|
||||
} else if (matchesPredicate) {
|
||||
return tryCatch(cb).call(boundTo, e);
|
||||
}
|
||||
} else if (util.isObject(e)) {
|
||||
var keys = getKeys(item);
|
||||
for (var j = 0; j < keys.length; ++j) {
|
||||
var key = keys[j];
|
||||
if (item[key] != e[key]) {
|
||||
continue predicateLoop;
|
||||
}
|
||||
}
|
||||
return tryCatch(cb).call(boundTo, e);
|
||||
}
|
||||
}
|
||||
return NEXT_FILTER;
|
||||
};
|
||||
}
|
||||
|
||||
return catchFilter;
|
||||
};
|
|
@ -0,0 +1,154 @@
|
|||
//This is pretty lame but what you gonna do
|
||||
|
||||
//async.js
|
||||
CONSTANT(LATE_QUEUE_CAPACITY, 16);
|
||||
CONSTANT(NORMAL_QUEUE_CAPACITY, 16);
|
||||
|
||||
//errors.js
|
||||
CONSTANT(ERROR_HANDLED_KEY, "__promiseHandled__");
|
||||
CONSTANT(OPERATIONAL_ERROR_KEY, "isOperational");
|
||||
CONSTANT(DEFAULT_STATE, 0);
|
||||
CONSTANT(STACK_ATTACHED, 1);
|
||||
CONSTANT(ERROR_HANDLED, 2);
|
||||
|
||||
//join.js
|
||||
CONSTANT(GENERATED_CLASS_COUNT, 8);
|
||||
|
||||
//promise.js
|
||||
CONSTANT(USE_BOUND, true);
|
||||
CONSTANT(DONT_USE_BOUND, false);
|
||||
|
||||
CONSTANT(PROPAGATE_CANCEL, 1);
|
||||
CONSTANT(PROPAGATE_BIND, 2);
|
||||
CONSTANT(PROPAGATE_ALL, PROPAGATE_CANCEL | PROPAGATE_BIND);
|
||||
|
||||
CONSTANT(CALLBACK_FULFILL_OFFSET, 0);
|
||||
CONSTANT(CALLBACK_REJECT_OFFSET, 1);
|
||||
CONSTANT(CALLBACK_PROMISE_OFFSET, 2);
|
||||
CONSTANT(CALLBACK_RECEIVER_OFFSET, 3);
|
||||
CONSTANT(CALLBACK_SIZE, 4);
|
||||
//Layout for ._bitField
|
||||
//[RR]XO GWFN CTBH IUDE LLLL LLLL LLLL LLLL
|
||||
//[RR] = [Reserved] (Both bits are either on or off to represent
|
||||
// 1 bit due to 31-bit integers in 32-bit v8)
|
||||
//R = [Reserved]
|
||||
//X = noAsyncGuarantee
|
||||
//O = returnedNonUndefined
|
||||
//G = isAsyncGuaranteed
|
||||
//W = isFollowing (The promise that is being followed is not stored explicitly)
|
||||
//F = isFulfilled
|
||||
//N = isRejected
|
||||
//C = willBeCancelled
|
||||
//T = isFinal (used for .done() implementation)
|
||||
//B = isBound
|
||||
//I = isRejectionIgnored
|
||||
//H = isRejectionUnhandled
|
||||
//U = isUnhanldedRejectionNotified
|
||||
//D = isDisposable
|
||||
//E = isCancelled
|
||||
//L = Length, 16 bit unsigned
|
||||
CONSTANT(ASYNC_GUARANTEE_SHIFT, 2)
|
||||
CONSTANT(NO_STATE, 0x0|0);
|
||||
CONSTANT(NO_ASYNC_GUARANTEE, 0x20000000|0);
|
||||
CONSTANT(RETURNED_NON_UNDEFINED, 0x10000000|0);
|
||||
CONSTANT(IS_ASYNC_GUARANTEED, 0x8000000|0);
|
||||
CONSTANT(IS_FOLLOWING, 0x4000000|0);
|
||||
CONSTANT(IS_FULFILLED, 0x2000000|0);
|
||||
CONSTANT(IS_REJECTED, 0x1000000|0);
|
||||
CONSTANT(WILL_BE_CANCELLED, 0x800000|0);
|
||||
CONSTANT(IS_FINAL, 0x400000|0);
|
||||
CONSTANT(IS_BOUND, 0x200000|0);
|
||||
CONSTANT(IS_REJECTION_UNHANDLED, 0x100000|0);
|
||||
CONSTANT(IS_REJECTION_IGNORED, 0x80000|0);
|
||||
CONSTANT(IS_UNHANDLED_REJECTION_NOTIFIED, 0x40000|0);
|
||||
CONSTANT(IS_DISPOSABLE, 0x20000|0);
|
||||
CONSTANT(IS_CANCELLED, 0x10000|0);
|
||||
CONSTANT(IS_CANCELLED_OR_WILL_BE_CANCELLED, IS_CANCELLED | WILL_BE_CANCELLED)
|
||||
CONSTANT(LENGTH_MASK, 0xFFFF|0);
|
||||
CONSTANT(LENGTH_CLEAR_MASK, ~LENGTH_MASK);
|
||||
CONSTANT(MAX_LENGTH, LENGTH_MASK);
|
||||
CONSTANT(IS_REJECTED_OR_CANCELLED, IS_REJECTED | IS_CANCELLED);
|
||||
CONSTANT(IS_REJECTED_OR_FULFILLED, IS_REJECTED | IS_FULFILLED);
|
||||
CONSTANT(IS_REJECTED_OR_FULFILLED_OR_CANCELLED, IS_REJECTED | IS_FULFILLED| IS_CANCELLED);
|
||||
CONSTANT(IS_PENDING_AND_WAITING_NEG, IS_REJECTED_OR_FULFILLED_OR_CANCELLED);
|
||||
|
||||
CONSTANT(IS_FATE_SEALED, IS_REJECTED | IS_FULFILLED | IS_FOLLOWING | IS_CANCELLED);
|
||||
|
||||
CONSTANT(AFTER_PROMISIFIED_SUFFIX, "Async");
|
||||
CONSTANT(UNHANDLED_REJECTION_EVENT, "unhandledRejection");
|
||||
CONSTANT(REJECTION_HANDLED_EVENT, "rejectionHandled");
|
||||
|
||||
//promise_array.js
|
||||
//MUST BE NEGATIVE NUMBERS
|
||||
CONSTANT(RESOLVE_UNDEFINED, -1);
|
||||
CONSTANT(RESOLVE_ARRAY, -2);
|
||||
CONSTANT(RESOLVE_OBJECT, -3);
|
||||
CONSTANT(RESOLVE_FOREVER_PENDING, -4);
|
||||
CONSTANT(RESOLVE_CALL_METHOD, -5);
|
||||
CONSTANT(RESOLVE_MAP, -6);
|
||||
|
||||
//queue.js
|
||||
CONSTANT(QUEUE_MAX_CAPACITY, (1 << 30) | 0);
|
||||
CONSTANT(QUEUE_MIN_CAPACITY, 16);
|
||||
|
||||
//captured_trace.js
|
||||
CONSTANT(FROM_PREVIOUS_EVENT, "From previous event:");
|
||||
CONSTANT(NO_STACK_TRACE, " (No stack trace)");
|
||||
CONSTANT(ADDITIONAL_STACK_TRACE, "^--- With additional stack trace: ");
|
||||
CONSTANT(UNHANDLED_REJECTION_HEADER, "Unhandled rejection ");
|
||||
|
||||
//finally.js
|
||||
CONSTANT(FINALLY_TYPE, 0);
|
||||
CONSTANT(TAP_TYPE, 1);
|
||||
|
||||
//direct_resolve.js
|
||||
CONSTANT(THROW, 1);
|
||||
CONSTANT(RETURN, 2);
|
||||
|
||||
//promisify.js
|
||||
CONSTANT(MAX_PARAM_COUNT, 1023);
|
||||
CONSTANT(PARAM_COUNTS_TO_TRY, 3);
|
||||
|
||||
//error.js
|
||||
CONSTANT(BLUEBIRD_ERRORS, "__BluebirdErrorTypes__");
|
||||
|
||||
//deprecated
|
||||
CONSTANT(OBJECT_PROMISIFY_DEPRECATED, "Promise.promisify for promisifying entire objects is deprecated. Use Promise.promisifyAll instead.\n\n\
|
||||
See http://goo.gl/MqrFmX");
|
||||
CONSTANT(SPAWN_DEPRECATED, "Promise.spawn is deprecated. Use Promise.coroutine instead.");
|
||||
|
||||
//errors
|
||||
CONSTANT(LATE_CANCELLATION_OBSERVER, "late cancellation observer");
|
||||
CONSTANT(TIMEOUT_ERROR, "operation timed out");
|
||||
CONSTANT(COLLECTION_ERROR, "expecting an array or an iterable object but got ");
|
||||
CONSTANT(OBJECT_ERROR, "expecting an object but got ");
|
||||
CONSTANT(FUNCTION_ERROR, "expecting a function but got ");
|
||||
CONSTANT(CONSTRUCT_ERROR_INVOCATION, "the promise constructor cannot be invoked directly\n\n\
|
||||
See http://goo.gl/MqrFmX\n");
|
||||
CONSTANT(NOT_GENERATOR_ERROR, "generatorFunction must be a function\n\n\
|
||||
See http://goo.gl/MqrFmX\n");
|
||||
CONSTANT(LONG_STACK_TRACES_ERROR, "cannot enable long stack traces after promises have been created\n\n\
|
||||
See http://goo.gl/MqrFmX\n");
|
||||
CONSTANT(INSPECTION_VALUE_ERROR, "cannot get fulfillment value of a non-fulfilled promise\n\n\
|
||||
See http://goo.gl/MqrFmX\n");
|
||||
CONSTANT(INSPECTION_REASON_ERROR, "cannot get rejection reason of a non-rejected promise\n\n\
|
||||
See http://goo.gl/MqrFmX\n");
|
||||
CONSTANT(PROMISIFY_TYPE_ERROR, "the target of promisifyAll must be an object or a function\n\n\
|
||||
See http://goo.gl/MqrFmX\n");
|
||||
CONSTANT(CIRCULAR_RESOLUTION_ERROR, "circular promise resolution chain\n\n\
|
||||
See http://goo.gl/MqrFmX\n");
|
||||
CONSTANT(PROPS_TYPE_ERROR, "cannot await properties of a non-object\n\n\
|
||||
See http://goo.gl/MqrFmX\n");
|
||||
CONSTANT(POSITIVE_INTEGER_ERROR, "expecting a positive integer\n\n\
|
||||
See http://goo.gl/MqrFmX\n");
|
||||
CONSTANT(YIELDED_NON_PROMISE_ERROR, "A value %s was yielded that could not be treated as a promise\n\n\
|
||||
See http://goo.gl/MqrFmX\n\n");
|
||||
CONSTANT(FROM_COROUTINE_CREATED_AT, "From coroutine:\n");
|
||||
CONSTANT(UNBOUND_RESOLVER_INVOCATION, "Illegal invocation, resolver resolve/reject must be called within a resolver context. Consider using the promise constructor instead.\n\n\
|
||||
See http://goo.gl/MqrFmX\n");
|
||||
CONSTANT(PROMISIFICATION_NORMAL_METHODS_ERROR, "Cannot promisify an API that has normal methods with '%s'-suffix\n\n\
|
||||
See http://goo.gl/MqrFmX\n");
|
||||
CONSTANT(SUFFIX_NOT_IDENTIFIER, "suffix must be a valid identifier\n\n\
|
||||
See http://goo.gl/MqrFmX\n");
|
||||
CONSTANT(NO_ASYNC_SCHEDULER, "No async scheduler available\n\n\
|
||||
See http://goo.gl/MqrFmX\n");
|
|
@ -0,0 +1,69 @@
|
|||
"use strict";
|
||||
module.exports = function(Promise) {
|
||||
var longStackTraces = false;
|
||||
var contextStack = [];
|
||||
|
||||
Promise.prototype._promiseCreated = function() {};
|
||||
Promise.prototype._pushContext = function() {};
|
||||
Promise.prototype._popContext = function() {return null;};
|
||||
Promise._peekContext = Promise.prototype._peekContext = function() {};
|
||||
|
||||
function Context() {
|
||||
this._trace = new Context.CapturedTrace(peekContext());
|
||||
}
|
||||
Context.prototype._pushContext = function () {
|
||||
if (this._trace !== undefined) {
|
||||
this._trace._promiseCreated = null;
|
||||
contextStack.push(this._trace);
|
||||
}
|
||||
};
|
||||
|
||||
Context.prototype._popContext = function () {
|
||||
if (this._trace !== undefined) {
|
||||
var trace = contextStack.pop();
|
||||
var ret = trace._promiseCreated;
|
||||
trace._promiseCreated = null;
|
||||
return ret;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
function createContext() {
|
||||
if (longStackTraces) return new Context();
|
||||
}
|
||||
|
||||
function peekContext() {
|
||||
var lastIndex = contextStack.length - 1;
|
||||
if (lastIndex >= 0) {
|
||||
return contextStack[lastIndex];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
Context.CapturedTrace = null;
|
||||
Context.create = createContext;
|
||||
Context.deactivateLongStackTraces = function() {};
|
||||
Context.activateLongStackTraces = function() {
|
||||
var Promise_pushContext = Promise.prototype._pushContext;
|
||||
var Promise_popContext = Promise.prototype._popContext;
|
||||
var Promise_PeekContext = Promise._peekContext;
|
||||
var Promise_peekContext = Promise.prototype._peekContext;
|
||||
var Promise_promiseCreated = Promise.prototype._promiseCreated;
|
||||
Context.deactivateLongStackTraces = function() {
|
||||
Promise.prototype._pushContext = Promise_pushContext;
|
||||
Promise.prototype._popContext = Promise_popContext;
|
||||
Promise._peekContext = Promise_PeekContext;
|
||||
Promise.prototype._peekContext = Promise_peekContext;
|
||||
Promise.prototype._promiseCreated = Promise_promiseCreated;
|
||||
longStackTraces = false;
|
||||
};
|
||||
longStackTraces = true;
|
||||
Promise.prototype._pushContext = Context.prototype._pushContext;
|
||||
Promise.prototype._popContext = Context.prototype._popContext;
|
||||
Promise._peekContext = Promise.prototype._peekContext = peekContext;
|
||||
Promise.prototype._promiseCreated = function() {
|
||||
var ctx = this._peekContext();
|
||||
if (ctx && ctx._promiseCreated == null) ctx._promiseCreated = this;
|
||||
};
|
||||
};
|
||||
return Context;
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,46 @@
|
|||
"use strict";
|
||||
module.exports = function(Promise) {
|
||||
function returner() {
|
||||
return this.value;
|
||||
}
|
||||
function thrower() {
|
||||
throw this.reason;
|
||||
}
|
||||
|
||||
Promise.prototype["return"] =
|
||||
Promise.prototype.thenReturn = function (value) {
|
||||
if (value instanceof Promise) value.suppressUnhandledRejections();
|
||||
return this._then(
|
||||
returner, undefined, undefined, {value: value}, undefined);
|
||||
};
|
||||
|
||||
Promise.prototype["throw"] =
|
||||
Promise.prototype.thenThrow = function (reason) {
|
||||
return this._then(
|
||||
thrower, undefined, undefined, {reason: reason}, undefined);
|
||||
};
|
||||
|
||||
Promise.prototype.catchThrow = function (reason) {
|
||||
if (arguments.length <= 1) {
|
||||
return this._then(
|
||||
undefined, thrower, undefined, {reason: reason}, undefined);
|
||||
} else {
|
||||
var _reason = arguments[1];
|
||||
var handler = function() {throw _reason;};
|
||||
return this.caught(reason, handler);
|
||||
}
|
||||
};
|
||||
|
||||
Promise.prototype.catchReturn = function (value) {
|
||||
if (arguments.length <= 1) {
|
||||
if (value instanceof Promise) value.suppressUnhandledRejections();
|
||||
return this._then(
|
||||
undefined, returner, undefined, {value: value}, undefined);
|
||||
} else {
|
||||
var _value = arguments[1];
|
||||
if (_value instanceof Promise) _value.suppressUnhandledRejections();
|
||||
var handler = function() {return _value;};
|
||||
return this.caught(value, handler);
|
||||
}
|
||||
};
|
||||
};
|
|
@ -0,0 +1,30 @@
|
|||
"use strict";
|
||||
module.exports = function(Promise, INTERNAL) {
|
||||
var PromiseReduce = Promise.reduce;
|
||||
var PromiseAll = Promise.all;
|
||||
|
||||
function promiseAllThis() {
|
||||
return PromiseAll(this);
|
||||
}
|
||||
|
||||
function PromiseMapSeries(promises, fn) {
|
||||
return PromiseReduce(promises, fn, INTERNAL, INTERNAL);
|
||||
}
|
||||
|
||||
Promise.prototype.each = function (fn) {
|
||||
return PromiseReduce(this, fn, INTERNAL, 0)
|
||||
._then(promiseAllThis, undefined, undefined, this, undefined);
|
||||
};
|
||||
|
||||
Promise.prototype.mapSeries = function (fn) {
|
||||
return PromiseReduce(this, fn, INTERNAL, INTERNAL);
|
||||
};
|
||||
|
||||
Promise.each = function (promises, fn) {
|
||||
return PromiseReduce(promises, fn, INTERNAL, 0)
|
||||
._then(promiseAllThis, undefined, undefined, promises, undefined);
|
||||
};
|
||||
|
||||
Promise.mapSeries = PromiseMapSeries;
|
||||
};
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
"use strict";
|
||||
var es5 = require("./es5");
|
||||
var Objectfreeze = es5.freeze;
|
||||
var util = require("./util");
|
||||
var inherits = util.inherits;
|
||||
var notEnumerableProp = util.notEnumerableProp;
|
||||
|
||||
function subError(nameProperty, defaultMessage) {
|
||||
function SubError(message) {
|
||||
if (!(this instanceof SubError)) return new SubError(message);
|
||||
notEnumerableProp(this, "message",
|
||||
typeof message === "string" ? message : defaultMessage);
|
||||
notEnumerableProp(this, "name", nameProperty);
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
} else {
|
||||
Error.call(this);
|
||||
}
|
||||
}
|
||||
inherits(SubError, Error);
|
||||
return SubError;
|
||||
}
|
||||
|
||||
var _TypeError, _RangeError;
|
||||
var Warning = subError("Warning", "warning");
|
||||
var CancellationError = subError("CancellationError", "cancellation error");
|
||||
var TimeoutError = subError("TimeoutError", "timeout error");
|
||||
var AggregateError = subError("AggregateError", "aggregate error");
|
||||
try {
|
||||
_TypeError = TypeError;
|
||||
_RangeError = RangeError;
|
||||
} catch(e) {
|
||||
_TypeError = subError("TypeError", "type error");
|
||||
_RangeError = subError("RangeError", "range error");
|
||||
}
|
||||
|
||||
var methods = ("join pop push shift unshift slice filter forEach some " +
|
||||
"every map indexOf lastIndexOf reduce reduceRight sort reverse").split(" ");
|
||||
|
||||
for (var i = 0; i < methods.length; ++i) {
|
||||
if (typeof Array.prototype[methods[i]] === "function") {
|
||||
AggregateError.prototype[methods[i]] = Array.prototype[methods[i]];
|
||||
}
|
||||
}
|
||||
|
||||
es5.defineProperty(AggregateError.prototype, "length", {
|
||||
value: 0,
|
||||
configurable: false,
|
||||
writable: true,
|
||||
enumerable: true
|
||||
});
|
||||
AggregateError.prototype[OPERATIONAL_ERROR_KEY] = true;
|
||||
var level = 0;
|
||||
AggregateError.prototype.toString = function() {
|
||||
var indent = Array(level * 4 + 1).join(" ");
|
||||
var ret = "\n" + indent + "AggregateError of:" + "\n";
|
||||
level++;
|
||||
indent = Array(level * 4 + 1).join(" ");
|
||||
for (var i = 0; i < this.length; ++i) {
|
||||
var str = this[i] === this ? "[Circular AggregateError]" : this[i] + "";
|
||||
var lines = str.split("\n");
|
||||
for (var j = 0; j < lines.length; ++j) {
|
||||
lines[j] = indent + lines[j];
|
||||
}
|
||||
str = lines.join("\n");
|
||||
ret += str + "\n";
|
||||
}
|
||||
level--;
|
||||
return ret;
|
||||
};
|
||||
|
||||
function OperationalError(message) {
|
||||
if (!(this instanceof OperationalError))
|
||||
return new OperationalError(message);
|
||||
notEnumerableProp(this, "name", "OperationalError");
|
||||
notEnumerableProp(this, "message", message);
|
||||
this.cause = message;
|
||||
this[OPERATIONAL_ERROR_KEY] = true;
|
||||
|
||||
if (message instanceof Error) {
|
||||
notEnumerableProp(this, "message", message.message);
|
||||
notEnumerableProp(this, "stack", message.stack);
|
||||
} else if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
}
|
||||
|
||||
}
|
||||
inherits(OperationalError, Error);
|
||||
|
||||
//Ensure all copies of the library throw the same error types
|
||||
var errorTypes = Error[BLUEBIRD_ERRORS];
|
||||
if (!errorTypes) {
|
||||
errorTypes = Objectfreeze({
|
||||
CancellationError: CancellationError,
|
||||
TimeoutError: TimeoutError,
|
||||
OperationalError: OperationalError,
|
||||
RejectionError: OperationalError,
|
||||
AggregateError: AggregateError
|
||||
});
|
||||
es5.defineProperty(Error, BLUEBIRD_ERRORS, {
|
||||
value: errorTypes,
|
||||
writable: false,
|
||||
enumerable: false,
|
||||
configurable: false
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Error: Error,
|
||||
TypeError: _TypeError,
|
||||
RangeError: _RangeError,
|
||||
CancellationError: errorTypes.CancellationError,
|
||||
OperationalError: errorTypes.OperationalError,
|
||||
TimeoutError: errorTypes.TimeoutError,
|
||||
AggregateError: errorTypes.AggregateError,
|
||||
Warning: Warning
|
||||
};
|
|
@ -0,0 +1,80 @@
|
|||
var isES5 = (function(){
|
||||
"use strict";
|
||||
return this === undefined;
|
||||
})();
|
||||
|
||||
if (isES5) {
|
||||
module.exports = {
|
||||
freeze: Object.freeze,
|
||||
defineProperty: Object.defineProperty,
|
||||
getDescriptor: Object.getOwnPropertyDescriptor,
|
||||
keys: Object.keys,
|
||||
names: Object.getOwnPropertyNames,
|
||||
getPrototypeOf: Object.getPrototypeOf,
|
||||
isArray: Array.isArray,
|
||||
isES5: isES5,
|
||||
propertyIsWritable: function(obj, prop) {
|
||||
var descriptor = Object.getOwnPropertyDescriptor(obj, prop);
|
||||
return !!(!descriptor || descriptor.writable || descriptor.set);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
var has = {}.hasOwnProperty;
|
||||
var str = {}.toString;
|
||||
var proto = {}.constructor.prototype;
|
||||
|
||||
var ObjectKeys = function (o) {
|
||||
var ret = [];
|
||||
for (var key in o) {
|
||||
if (has.call(o, key)) {
|
||||
ret.push(key);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
var ObjectGetDescriptor = function(o, key) {
|
||||
return {value: o[key]};
|
||||
};
|
||||
|
||||
var ObjectDefineProperty = function (o, key, desc) {
|
||||
o[key] = desc.value;
|
||||
return o;
|
||||
};
|
||||
|
||||
var ObjectFreeze = function (obj) {
|
||||
return obj;
|
||||
};
|
||||
|
||||
var ObjectGetPrototypeOf = function (obj) {
|
||||
try {
|
||||
return Object(obj).constructor.prototype;
|
||||
}
|
||||
catch (e) {
|
||||
return proto;
|
||||
}
|
||||
};
|
||||
|
||||
var ArrayIsArray = function (obj) {
|
||||
try {
|
||||
return str.call(obj) === "[object Array]";
|
||||
}
|
||||
catch(e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
isArray: ArrayIsArray,
|
||||
keys: ObjectKeys,
|
||||
names: ObjectKeys,
|
||||
defineProperty: ObjectDefineProperty,
|
||||
getDescriptor: ObjectGetDescriptor,
|
||||
freeze: ObjectFreeze,
|
||||
getPrototypeOf: ObjectGetPrototypeOf,
|
||||
isES5: isES5,
|
||||
propertyIsWritable: function() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
"use strict";
|
||||
module.exports = function(Promise, INTERNAL) {
|
||||
var PromiseMap = Promise.map;
|
||||
|
||||
Promise.prototype.filter = function (fn, options) {
|
||||
return PromiseMap(this, fn, options, INTERNAL);
|
||||
};
|
||||
|
||||
Promise.filter = function (promises, fn, options) {
|
||||
return PromiseMap(promises, fn, options, INTERNAL);
|
||||
};
|
||||
};
|
|
@ -0,0 +1,146 @@
|
|||
"use strict";
|
||||
module.exports = function(Promise, tryConvertToPromise, NEXT_FILTER) {
|
||||
var util = require("./util");
|
||||
var CancellationError = Promise.CancellationError;
|
||||
var errorObj = util.errorObj;
|
||||
var catchFilter = require("./catch_filter")(NEXT_FILTER);
|
||||
|
||||
function PassThroughHandlerContext(promise, type, handler) {
|
||||
this.promise = promise;
|
||||
this.type = type;
|
||||
this.handler = handler;
|
||||
this.called = false;
|
||||
this.cancelPromise = null;
|
||||
}
|
||||
|
||||
PassThroughHandlerContext.prototype.isFinallyHandler = function() {
|
||||
return this.type === FINALLY_TYPE;
|
||||
};
|
||||
|
||||
function FinallyHandlerCancelReaction(finallyHandler) {
|
||||
this.finallyHandler = finallyHandler;
|
||||
}
|
||||
|
||||
FinallyHandlerCancelReaction.prototype._resultCancelled = function() {
|
||||
checkCancel(this.finallyHandler);
|
||||
};
|
||||
|
||||
function checkCancel(ctx, reason) {
|
||||
if (ctx.cancelPromise != null) {
|
||||
if (arguments.length > 1) {
|
||||
ctx.cancelPromise._reject(reason);
|
||||
} else {
|
||||
ctx.cancelPromise._cancel();
|
||||
}
|
||||
ctx.cancelPromise = null;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function succeed() {
|
||||
return finallyHandler.call(this, this.promise._target()._settledValue());
|
||||
}
|
||||
function fail(reason) {
|
||||
if (checkCancel(this, reason)) return;
|
||||
errorObj.e = reason;
|
||||
return errorObj;
|
||||
}
|
||||
function finallyHandler(reasonOrValue) {
|
||||
var promise = this.promise;
|
||||
var handler = this.handler;
|
||||
|
||||
if (!this.called) {
|
||||
this.called = true;
|
||||
var ret = this.isFinallyHandler()
|
||||
? handler.call(promise._boundValue())
|
||||
: handler.call(promise._boundValue(), reasonOrValue);
|
||||
if (ret === NEXT_FILTER) {
|
||||
return ret;
|
||||
} else if (ret !== undefined) {
|
||||
promise._setReturnedNonUndefined();
|
||||
var maybePromise = tryConvertToPromise(ret, promise);
|
||||
if (maybePromise instanceof Promise) {
|
||||
if (this.cancelPromise != null) {
|
||||
if (maybePromise._isCancelled()) {
|
||||
var reason =
|
||||
new CancellationError(LATE_CANCELLATION_OBSERVER);
|
||||
promise._attachExtraTrace(reason);
|
||||
errorObj.e = reason;
|
||||
return errorObj;
|
||||
} else if (maybePromise.isPending()) {
|
||||
maybePromise._attachCancellationCallback(
|
||||
new FinallyHandlerCancelReaction(this));
|
||||
}
|
||||
}
|
||||
return maybePromise._then(
|
||||
succeed, fail, undefined, this, undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (promise.isRejected()) {
|
||||
checkCancel(this);
|
||||
errorObj.e = reasonOrValue;
|
||||
return errorObj;
|
||||
} else {
|
||||
checkCancel(this);
|
||||
return reasonOrValue;
|
||||
}
|
||||
}
|
||||
|
||||
Promise.prototype._passThrough = function(handler, type, success, fail) {
|
||||
if (typeof handler !== "function") return this.then();
|
||||
return this._then(success,
|
||||
fail,
|
||||
undefined,
|
||||
new PassThroughHandlerContext(this, type, handler),
|
||||
undefined);
|
||||
};
|
||||
|
||||
Promise.prototype.lastly =
|
||||
Promise.prototype["finally"] = function (handler) {
|
||||
return this._passThrough(handler,
|
||||
FINALLY_TYPE,
|
||||
finallyHandler,
|
||||
finallyHandler);
|
||||
};
|
||||
|
||||
|
||||
Promise.prototype.tap = function (handler) {
|
||||
return this._passThrough(handler, TAP_TYPE, finallyHandler);
|
||||
};
|
||||
|
||||
Promise.prototype.tapCatch = function (handlerOrPredicate) {
|
||||
var len = arguments.length;
|
||||
if(len === 1) {
|
||||
return this._passThrough(handlerOrPredicate,
|
||||
TAP_TYPE,
|
||||
undefined,
|
||||
finallyHandler);
|
||||
} else {
|
||||
var catchInstances = new Array(len - 1),
|
||||
j = 0, i;
|
||||
for (i = 0; i < len - 1; ++i) {
|
||||
var item = arguments[i];
|
||||
if (util.isObject(item)) {
|
||||
catchInstances[j++] = item;
|
||||
} else {
|
||||
return Promise.reject(new TypeError(
|
||||
"tapCatch statement predicate: "
|
||||
+ OBJECT_ERROR + util.classString(item)
|
||||
));
|
||||
}
|
||||
}
|
||||
catchInstances.length = j;
|
||||
var handler = arguments[i];
|
||||
return this._passThrough(catchFilter(catchInstances, handler, this),
|
||||
TAP_TYPE,
|
||||
undefined,
|
||||
finallyHandler);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return PassThroughHandlerContext;
|
||||
};
|
|
@ -0,0 +1,230 @@
|
|||
"use strict";
|
||||
module.exports = function(Promise,
|
||||
apiRejection,
|
||||
INTERNAL,
|
||||
tryConvertToPromise,
|
||||
Proxyable,
|
||||
debug) {
|
||||
var errors = require("./errors");
|
||||
var TypeError = errors.TypeError;
|
||||
var ASSERT = require("./assert");
|
||||
var util = require("./util");
|
||||
var errorObj = util.errorObj;
|
||||
var tryCatch = util.tryCatch;
|
||||
var yieldHandlers = [];
|
||||
|
||||
function promiseFromYieldHandler(value, yieldHandlers, traceParent) {
|
||||
for (var i = 0; i < yieldHandlers.length; ++i) {
|
||||
traceParent._pushContext();
|
||||
var result = tryCatch(yieldHandlers[i])(value);
|
||||
traceParent._popContext();
|
||||
if (result === errorObj) {
|
||||
traceParent._pushContext();
|
||||
var ret = Promise.reject(errorObj.e);
|
||||
traceParent._popContext();
|
||||
return ret;
|
||||
}
|
||||
var maybePromise = tryConvertToPromise(result, traceParent);
|
||||
if (maybePromise instanceof Promise) return maybePromise;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function PromiseSpawn(generatorFunction, receiver, yieldHandler, stack) {
|
||||
if (debug.cancellation()) {
|
||||
var internal = new Promise(INTERNAL);
|
||||
var _finallyPromise = this._finallyPromise = new Promise(INTERNAL);
|
||||
this._promise = internal.lastly(function() {
|
||||
return _finallyPromise;
|
||||
});
|
||||
internal._captureStackTrace();
|
||||
internal._setOnCancel(this);
|
||||
} else {
|
||||
var promise = this._promise = new Promise(INTERNAL);
|
||||
promise._captureStackTrace();
|
||||
}
|
||||
this._stack = stack;
|
||||
this._generatorFunction = generatorFunction;
|
||||
this._receiver = receiver;
|
||||
this._generator = undefined;
|
||||
this._yieldHandlers = typeof yieldHandler === "function"
|
||||
? [yieldHandler].concat(yieldHandlers)
|
||||
: yieldHandlers;
|
||||
this._yieldedPromise = null;
|
||||
this._cancellationPhase = false;
|
||||
}
|
||||
util.inherits(PromiseSpawn, Proxyable);
|
||||
|
||||
PromiseSpawn.prototype._isResolved = function() {
|
||||
return this._promise === null;
|
||||
};
|
||||
|
||||
PromiseSpawn.prototype._cleanup = function() {
|
||||
this._promise = this._generator = null;
|
||||
if (debug.cancellation() && this._finallyPromise !== null) {
|
||||
this._finallyPromise._fulfill();
|
||||
this._finallyPromise = null;
|
||||
}
|
||||
};
|
||||
|
||||
PromiseSpawn.prototype._promiseCancelled = function() {
|
||||
if (this._isResolved()) return;
|
||||
var implementsReturn = typeof this._generator["return"] !== "undefined";
|
||||
|
||||
var result;
|
||||
if (!implementsReturn) {
|
||||
var reason = new Promise.CancellationError(
|
||||
"generator .return() sentinel");
|
||||
Promise.coroutine.returnSentinel = reason;
|
||||
this._promise._attachExtraTrace(reason);
|
||||
this._promise._pushContext();
|
||||
result = tryCatch(this._generator["throw"]).call(this._generator,
|
||||
reason);
|
||||
this._promise._popContext();
|
||||
} else {
|
||||
this._promise._pushContext();
|
||||
result = tryCatch(this._generator["return"]).call(this._generator,
|
||||
undefined);
|
||||
this._promise._popContext();
|
||||
}
|
||||
this._cancellationPhase = true;
|
||||
this._yieldedPromise = null;
|
||||
this._continue(result);
|
||||
};
|
||||
|
||||
PromiseSpawn.prototype._promiseFulfilled = function(value) {
|
||||
this._yieldedPromise = null;
|
||||
this._promise._pushContext();
|
||||
var result = tryCatch(this._generator.next).call(this._generator, value);
|
||||
this._promise._popContext();
|
||||
this._continue(result);
|
||||
};
|
||||
|
||||
PromiseSpawn.prototype._promiseRejected = function(reason) {
|
||||
this._yieldedPromise = null;
|
||||
this._promise._attachExtraTrace(reason);
|
||||
this._promise._pushContext();
|
||||
var result = tryCatch(this._generator["throw"])
|
||||
.call(this._generator, reason);
|
||||
this._promise._popContext();
|
||||
this._continue(result);
|
||||
};
|
||||
|
||||
PromiseSpawn.prototype._resultCancelled = function() {
|
||||
if (this._yieldedPromise instanceof Promise) {
|
||||
var promise = this._yieldedPromise;
|
||||
this._yieldedPromise = null;
|
||||
promise.cancel();
|
||||
}
|
||||
};
|
||||
|
||||
PromiseSpawn.prototype.promise = function () {
|
||||
return this._promise;
|
||||
};
|
||||
|
||||
PromiseSpawn.prototype._run = function () {
|
||||
this._generator = this._generatorFunction.call(this._receiver);
|
||||
this._receiver =
|
||||
this._generatorFunction = undefined;
|
||||
this._promiseFulfilled(undefined);
|
||||
};
|
||||
|
||||
PromiseSpawn.prototype._continue = function (result) {
|
||||
ASSERT(this._yieldedPromise == null);
|
||||
var promise = this._promise;
|
||||
if (result === errorObj) {
|
||||
this._cleanup();
|
||||
if (this._cancellationPhase) {
|
||||
return promise.cancel();
|
||||
} else {
|
||||
return promise._rejectCallback(result.e, false);
|
||||
}
|
||||
}
|
||||
|
||||
var value = result.value;
|
||||
if (result.done === true) {
|
||||
this._cleanup();
|
||||
if (this._cancellationPhase) {
|
||||
return promise.cancel();
|
||||
} else {
|
||||
return promise._resolveCallback(value);
|
||||
}
|
||||
} else {
|
||||
var maybePromise = tryConvertToPromise(value, this._promise);
|
||||
if (!(maybePromise instanceof Promise)) {
|
||||
maybePromise =
|
||||
promiseFromYieldHandler(maybePromise,
|
||||
this._yieldHandlers,
|
||||
this._promise);
|
||||
ASSERT(maybePromise === null || maybePromise instanceof Promise);
|
||||
if (maybePromise === null) {
|
||||
this._promiseRejected(
|
||||
new TypeError(
|
||||
YIELDED_NON_PROMISE_ERROR.replace("%s", String(value)) +
|
||||
FROM_COROUTINE_CREATED_AT +
|
||||
this._stack.split("\n").slice(1, -7).join("\n")
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
maybePromise = maybePromise._target();
|
||||
var bitField = maybePromise._bitField;
|
||||
USE(bitField);
|
||||
if (BIT_FIELD_CHECK(IS_PENDING_AND_WAITING_NEG)) {
|
||||
this._yieldedPromise = maybePromise;
|
||||
maybePromise._proxy(this, null);
|
||||
} else if (BIT_FIELD_CHECK(IS_FULFILLED)) {
|
||||
Promise._async.invoke(
|
||||
this._promiseFulfilled, this, maybePromise._value()
|
||||
);
|
||||
} else if (BIT_FIELD_CHECK(IS_REJECTED)) {
|
||||
Promise._async.invoke(
|
||||
this._promiseRejected, this, maybePromise._reason()
|
||||
);
|
||||
} else {
|
||||
this._promiseCancelled();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Promise.coroutine = function (generatorFunction, options) {
|
||||
//Throw synchronously because Promise.coroutine is semantically
|
||||
//something you call at "compile time" to annotate static functions
|
||||
if (typeof generatorFunction !== "function") {
|
||||
throw new TypeError(NOT_GENERATOR_ERROR);
|
||||
}
|
||||
var yieldHandler = Object(options).yieldHandler;
|
||||
var PromiseSpawn$ = PromiseSpawn;
|
||||
var stack = new Error().stack;
|
||||
return function () {
|
||||
var generator = generatorFunction.apply(this, arguments);
|
||||
var spawn = new PromiseSpawn$(undefined, undefined, yieldHandler,
|
||||
stack);
|
||||
var ret = spawn.promise();
|
||||
spawn._generator = generator;
|
||||
spawn._promiseFulfilled(undefined);
|
||||
return ret;
|
||||
};
|
||||
};
|
||||
|
||||
Promise.coroutine.addYieldHandler = function(fn) {
|
||||
if (typeof fn !== "function") {
|
||||
throw new TypeError(FUNCTION_ERROR + util.classString(fn));
|
||||
}
|
||||
yieldHandlers.push(fn);
|
||||
};
|
||||
|
||||
Promise.spawn = function (generatorFunction) {
|
||||
debug.deprecated("Promise.spawn()", "Promise.coroutine()");
|
||||
//Return rejected promise because Promise.spawn is semantically
|
||||
//something that will be called at runtime with possibly dynamic values
|
||||
if (typeof generatorFunction !== "function") {
|
||||
return apiRejection(NOT_GENERATOR_ERROR);
|
||||
}
|
||||
var spawn = new PromiseSpawn(generatorFunction, this);
|
||||
var ret = spawn.promise();
|
||||
spawn._run(Promise.spawn);
|
||||
return ret;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,165 @@
|
|||
"use strict";
|
||||
module.exports =
|
||||
function(Promise, PromiseArray, tryConvertToPromise, INTERNAL, async) {
|
||||
var util = require("./util");
|
||||
var canEvaluate = util.canEvaluate;
|
||||
var tryCatch = util.tryCatch;
|
||||
var errorObj = util.errorObj;
|
||||
var reject;
|
||||
|
||||
if (!__BROWSER__) {
|
||||
if (canEvaluate) {
|
||||
var thenCallback = function(i) {
|
||||
return new Function("value", "holder", " \n\
|
||||
'use strict'; \n\
|
||||
holder.pIndex = value; \n\
|
||||
holder.checkFulfillment(this); \n\
|
||||
".replace(/Index/g, i));
|
||||
};
|
||||
|
||||
var promiseSetter = function(i) {
|
||||
return new Function("promise", "holder", " \n\
|
||||
'use strict'; \n\
|
||||
holder.pIndex = promise; \n\
|
||||
".replace(/Index/g, i));
|
||||
};
|
||||
|
||||
var generateHolderClass = function(total) {
|
||||
var props = new Array(total);
|
||||
for (var i = 0; i < props.length; ++i) {
|
||||
props[i] = "this.p" + (i+1);
|
||||
}
|
||||
var assignment = props.join(" = ") + " = null;";
|
||||
var cancellationCode= "var promise;\n" + props.map(function(prop) {
|
||||
return " \n\
|
||||
promise = " + prop + "; \n\
|
||||
if (promise instanceof Promise) { \n\
|
||||
promise.cancel(); \n\
|
||||
} \n\
|
||||
";
|
||||
}).join("\n");
|
||||
var passedArguments = props.join(", ");
|
||||
var name = "Holder$" + total;
|
||||
|
||||
|
||||
var code = "return function(tryCatch, errorObj, Promise, async) { \n\
|
||||
'use strict'; \n\
|
||||
function [TheName](fn) { \n\
|
||||
[TheProperties] \n\
|
||||
this.fn = fn; \n\
|
||||
this.asyncNeeded = true; \n\
|
||||
this.now = 0; \n\
|
||||
} \n\
|
||||
\n\
|
||||
[TheName].prototype._callFunction = function(promise) { \n\
|
||||
promise._pushContext(); \n\
|
||||
var ret = tryCatch(this.fn)([ThePassedArguments]); \n\
|
||||
promise._popContext(); \n\
|
||||
if (ret === errorObj) { \n\
|
||||
promise._rejectCallback(ret.e, false); \n\
|
||||
} else { \n\
|
||||
promise._resolveCallback(ret); \n\
|
||||
} \n\
|
||||
}; \n\
|
||||
\n\
|
||||
[TheName].prototype.checkFulfillment = function(promise) { \n\
|
||||
var now = ++this.now; \n\
|
||||
if (now === [TheTotal]) { \n\
|
||||
if (this.asyncNeeded) { \n\
|
||||
async.invoke(this._callFunction, this, promise); \n\
|
||||
} else { \n\
|
||||
this._callFunction(promise); \n\
|
||||
} \n\
|
||||
\n\
|
||||
} \n\
|
||||
}; \n\
|
||||
\n\
|
||||
[TheName].prototype._resultCancelled = function() { \n\
|
||||
[CancellationCode] \n\
|
||||
}; \n\
|
||||
\n\
|
||||
return [TheName]; \n\
|
||||
}(tryCatch, errorObj, Promise, async); \n\
|
||||
";
|
||||
|
||||
code = code.replace(/\[TheName\]/g, name)
|
||||
.replace(/\[TheTotal\]/g, total)
|
||||
.replace(/\[ThePassedArguments\]/g, passedArguments)
|
||||
.replace(/\[TheProperties\]/g, assignment)
|
||||
.replace(/\[CancellationCode\]/g, cancellationCode);
|
||||
|
||||
return new Function("tryCatch", "errorObj", "Promise", "async", code)
|
||||
(tryCatch, errorObj, Promise, async);
|
||||
};
|
||||
|
||||
var holderClasses = [];
|
||||
var thenCallbacks = [];
|
||||
var promiseSetters = [];
|
||||
|
||||
for (var i = 0; i < GENERATED_CLASS_COUNT; ++i) {
|
||||
holderClasses.push(generateHolderClass(i + 1));
|
||||
thenCallbacks.push(thenCallback(i + 1));
|
||||
promiseSetters.push(promiseSetter(i + 1));
|
||||
}
|
||||
|
||||
reject = function (reason) {
|
||||
this._reject(reason);
|
||||
};
|
||||
}}
|
||||
|
||||
Promise.join = function () {
|
||||
var last = arguments.length - 1;
|
||||
var fn;
|
||||
if (last > 0 && typeof arguments[last] === "function") {
|
||||
fn = arguments[last];
|
||||
if (!__BROWSER__) {
|
||||
if (last <= GENERATED_CLASS_COUNT && canEvaluate) {
|
||||
var ret = new Promise(INTERNAL);
|
||||
ret._captureStackTrace();
|
||||
var HolderClass = holderClasses[last - 1];
|
||||
var holder = new HolderClass(fn);
|
||||
var callbacks = thenCallbacks;
|
||||
|
||||
for (var i = 0; i < last; ++i) {
|
||||
var maybePromise = tryConvertToPromise(arguments[i], ret);
|
||||
if (maybePromise instanceof Promise) {
|
||||
maybePromise = maybePromise._target();
|
||||
var bitField = maybePromise._bitField;
|
||||
USE(bitField);
|
||||
if (BIT_FIELD_CHECK(IS_PENDING_AND_WAITING_NEG)) {
|
||||
maybePromise._then(callbacks[i], reject,
|
||||
undefined, ret, holder);
|
||||
promiseSetters[i](maybePromise, holder);
|
||||
holder.asyncNeeded = false;
|
||||
} else if (BIT_FIELD_CHECK(IS_FULFILLED)) {
|
||||
callbacks[i].call(ret,
|
||||
maybePromise._value(), holder);
|
||||
} else if (BIT_FIELD_CHECK(IS_REJECTED)) {
|
||||
ret._reject(maybePromise._reason());
|
||||
} else {
|
||||
ret._cancel();
|
||||
}
|
||||
} else {
|
||||
callbacks[i].call(ret, maybePromise, holder);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ret._isFateSealed()) {
|
||||
if (holder.asyncNeeded) {
|
||||
var context = Promise._getContext();
|
||||
holder.fn = util.contextBind(context, holder.fn);
|
||||
}
|
||||
ret._setAsyncGuaranteed();
|
||||
ret._setOnCancel(holder);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
INLINE_SLICE(args, arguments);
|
||||
if (fn) args.pop();
|
||||
var ret = new PromiseArray(args).promise();
|
||||
return fn !== undefined ? ret.spread(fn) : ret;
|
||||
};
|
||||
|
||||
};
|
|
@ -0,0 +1,192 @@
|
|||
"use strict";
|
||||
module.exports = function(Promise,
|
||||
PromiseArray,
|
||||
apiRejection,
|
||||
tryConvertToPromise,
|
||||
INTERNAL,
|
||||
debug) {
|
||||
var ASSERT = require("./assert");
|
||||
var util = require("./util");
|
||||
var tryCatch = util.tryCatch;
|
||||
var errorObj = util.errorObj;
|
||||
var async = Promise._async;
|
||||
|
||||
function MappingPromiseArray(promises, fn, limit, _filter) {
|
||||
this.constructor$(promises);
|
||||
this._promise._captureStackTrace();
|
||||
var context = Promise._getContext();
|
||||
this._callback = util.contextBind(context, fn);
|
||||
this._preservedValues = _filter === INTERNAL
|
||||
? new Array(this.length())
|
||||
: null;
|
||||
this._limit = limit;
|
||||
this._inFlight = 0;
|
||||
this._queue = [];
|
||||
async.invoke(this._asyncInit, this, undefined);
|
||||
if (util.isArray(promises)) {
|
||||
for (var i = 0; i < promises.length; ++i) {
|
||||
var maybePromise = promises[i];
|
||||
if (maybePromise instanceof Promise) {
|
||||
maybePromise.suppressUnhandledRejections();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
util.inherits(MappingPromiseArray, PromiseArray);
|
||||
|
||||
MappingPromiseArray.prototype._asyncInit = function() {
|
||||
this._init$(undefined, RESOLVE_ARRAY);
|
||||
};
|
||||
|
||||
// The following hack is required because the super constructor
|
||||
// might call promiseFulfilled before this.callback = fn is set
|
||||
//
|
||||
// The super constructor call must always be first so that fields
|
||||
// are initialized in the same order so that the sub-class instances
|
||||
// will share same memory layout as the super class instances
|
||||
|
||||
// Override
|
||||
MappingPromiseArray.prototype._init = function () {};
|
||||
|
||||
// Override
|
||||
MappingPromiseArray.prototype._promiseFulfilled = function (value, index) {
|
||||
ASSERT(!this._isResolved());
|
||||
var values = this._values;
|
||||
var length = this.length();
|
||||
var preservedValues = this._preservedValues;
|
||||
var limit = this._limit;
|
||||
|
||||
// Callback has been called for this index if it's negative
|
||||
if (index < 0) {
|
||||
// Restore the actual index value
|
||||
index = (index * -1) - 1;
|
||||
values[index] = value;
|
||||
if (limit >= 1) {
|
||||
this._inFlight--;
|
||||
this._drainQueue();
|
||||
if (this._isResolved()) return true;
|
||||
}
|
||||
} else {
|
||||
if (limit >= 1 && this._inFlight >= limit) {
|
||||
values[index] = value;
|
||||
this._queue.push(index);
|
||||
return false;
|
||||
}
|
||||
if (preservedValues !== null) preservedValues[index] = value;
|
||||
|
||||
var promise = this._promise;
|
||||
var callback = this._callback;
|
||||
var receiver = promise._boundValue();
|
||||
promise._pushContext();
|
||||
var ret = tryCatch(callback).call(receiver, value, index, length);
|
||||
var promiseCreated = promise._popContext();
|
||||
debug.checkForgottenReturns(
|
||||
ret,
|
||||
promiseCreated,
|
||||
preservedValues !== null ? "Promise.filter" : "Promise.map",
|
||||
promise
|
||||
);
|
||||
if (ret === errorObj) {
|
||||
this._reject(ret.e);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the mapper function returned a promise we simply reuse
|
||||
// The MappingPromiseArray as a PromiseArray for round 2.
|
||||
// To mark an index as "round 2" its inverted by adding +1 and
|
||||
// multiplying by -1
|
||||
var maybePromise = tryConvertToPromise(ret, this._promise);
|
||||
if (maybePromise instanceof Promise) {
|
||||
maybePromise = maybePromise._target();
|
||||
var bitField = maybePromise._bitField;
|
||||
USE(bitField);
|
||||
if (BIT_FIELD_CHECK(IS_PENDING_AND_WAITING_NEG)) {
|
||||
if (limit >= 1) this._inFlight++;
|
||||
values[index] = maybePromise;
|
||||
maybePromise._proxy(this, (index + 1) * -1);
|
||||
return false;
|
||||
} else if (BIT_FIELD_CHECK(IS_FULFILLED)) {
|
||||
ret = maybePromise._value();
|
||||
} else if (BIT_FIELD_CHECK(IS_REJECTED)) {
|
||||
this._reject(maybePromise._reason());
|
||||
return true;
|
||||
} else {
|
||||
this._cancel();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
values[index] = ret;
|
||||
}
|
||||
var totalResolved = ++this._totalResolved;
|
||||
if (totalResolved >= length) {
|
||||
if (preservedValues !== null) {
|
||||
this._filter(values, preservedValues);
|
||||
} else {
|
||||
this._resolve(values);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
MappingPromiseArray.prototype._drainQueue = function () {
|
||||
var queue = this._queue;
|
||||
var limit = this._limit;
|
||||
var values = this._values;
|
||||
while (queue.length > 0 && this._inFlight < limit) {
|
||||
if (this._isResolved()) return;
|
||||
var index = queue.pop();
|
||||
this._promiseFulfilled(values[index], index);
|
||||
}
|
||||
};
|
||||
|
||||
MappingPromiseArray.prototype._filter = function (booleans, values) {
|
||||
var len = values.length;
|
||||
var ret = new Array(len);
|
||||
var j = 0;
|
||||
for (var i = 0; i < len; ++i) {
|
||||
if (booleans[i]) ret[j++] = values[i];
|
||||
}
|
||||
ret.length = j;
|
||||
this._resolve(ret);
|
||||
};
|
||||
|
||||
MappingPromiseArray.prototype.preservedValues = function () {
|
||||
return this._preservedValues;
|
||||
};
|
||||
|
||||
function map(promises, fn, options, _filter) {
|
||||
if (typeof fn !== "function") {
|
||||
return apiRejection(FUNCTION_ERROR + util.classString(fn));
|
||||
}
|
||||
|
||||
var limit = 0;
|
||||
if (options !== undefined) {
|
||||
if (typeof options === "object" && options !== null) {
|
||||
if (typeof options.concurrency !== "number") {
|
||||
return Promise.reject(
|
||||
new TypeError("'concurrency' must be a number but it is " +
|
||||
util.classString(options.concurrency)));
|
||||
}
|
||||
limit = options.concurrency;
|
||||
} else {
|
||||
return Promise.reject(new TypeError(
|
||||
"options argument must be an object but it is " +
|
||||
util.classString(options)));
|
||||
}
|
||||
}
|
||||
limit = typeof limit === "number" &&
|
||||
isFinite(limit) && limit >= 1 ? limit : 0;
|
||||
return new MappingPromiseArray(promises, fn, limit, _filter).promise();
|
||||
}
|
||||
|
||||
Promise.prototype.map = function (fn, options) {
|
||||
return map(this, fn, options, null);
|
||||
};
|
||||
|
||||
Promise.map = function (promises, fn, options, _filter) {
|
||||
return map(promises, fn, options, _filter);
|
||||
};
|
||||
|
||||
|
||||
};
|
|
@ -0,0 +1,57 @@
|
|||
"use strict";
|
||||
module.exports =
|
||||
function(Promise, INTERNAL, tryConvertToPromise, apiRejection, debug) {
|
||||
var util = require("./util");
|
||||
var ASSERT = require("./assert");
|
||||
var tryCatch = util.tryCatch;
|
||||
|
||||
Promise.method = function (fn) {
|
||||
if (typeof fn !== "function") {
|
||||
throw new Promise.TypeError(FUNCTION_ERROR + util.classString(fn));
|
||||
}
|
||||
return function () {
|
||||
var ret = new Promise(INTERNAL);
|
||||
ret._captureStackTrace();
|
||||
ret._pushContext();
|
||||
var value = tryCatch(fn).apply(this, arguments);
|
||||
var promiseCreated = ret._popContext();
|
||||
debug.checkForgottenReturns(
|
||||
value, promiseCreated, "Promise.method", ret);
|
||||
ret._resolveFromSyncValue(value);
|
||||
return ret;
|
||||
};
|
||||
};
|
||||
|
||||
Promise.attempt = Promise["try"] = function (fn) {
|
||||
if (typeof fn !== "function") {
|
||||
return apiRejection(FUNCTION_ERROR + util.classString(fn));
|
||||
}
|
||||
var ret = new Promise(INTERNAL);
|
||||
ret._captureStackTrace();
|
||||
ret._pushContext();
|
||||
var value;
|
||||
if (arguments.length > 1) {
|
||||
debug.deprecated("calling Promise.try with more than 1 argument");
|
||||
var arg = arguments[1];
|
||||
var ctx = arguments[2];
|
||||
value = util.isArray(arg) ? tryCatch(fn).apply(ctx, arg)
|
||||
: tryCatch(fn).call(ctx, arg);
|
||||
} else {
|
||||
value = tryCatch(fn)();
|
||||
}
|
||||
var promiseCreated = ret._popContext();
|
||||
debug.checkForgottenReturns(
|
||||
value, promiseCreated, "Promise.try", ret);
|
||||
ret._resolveFromSyncValue(value);
|
||||
return ret;
|
||||
};
|
||||
|
||||
Promise.prototype._resolveFromSyncValue = function (value) {
|
||||
ASSERT(!this._isFollowing());
|
||||
if (value === util.errorObj) {
|
||||
this._rejectCallback(value.e, false);
|
||||
} else {
|
||||
this._resolveCallback(value, true);
|
||||
}
|
||||
};
|
||||
};
|
|
@ -0,0 +1,51 @@
|
|||
"use strict";
|
||||
var util = require("./util");
|
||||
var maybeWrapAsError = util.maybeWrapAsError;
|
||||
var errors = require("./errors");
|
||||
var OperationalError = errors.OperationalError;
|
||||
var es5 = require("./es5");
|
||||
|
||||
function isUntypedError(obj) {
|
||||
return obj instanceof Error &&
|
||||
es5.getPrototypeOf(obj) === Error.prototype;
|
||||
}
|
||||
|
||||
var rErrorKey = /^(?:name|message|stack|cause)$/;
|
||||
function wrapAsOperationalError(obj) {
|
||||
var ret;
|
||||
if (isUntypedError(obj)) {
|
||||
ret = new OperationalError(obj);
|
||||
ret.name = obj.name;
|
||||
ret.message = obj.message;
|
||||
ret.stack = obj.stack;
|
||||
var keys = es5.keys(obj);
|
||||
for (var i = 0; i < keys.length; ++i) {
|
||||
var key = keys[i];
|
||||
if (!rErrorKey.test(key)) {
|
||||
ret[key] = obj[key];
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
util.markAsOriginatingFromRejection(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
function nodebackForPromise(promise, multiArgs) {
|
||||
return function(err, value) {
|
||||
if (promise === null) return;
|
||||
if (err) {
|
||||
var wrapped = wrapAsOperationalError(maybeWrapAsError(err));
|
||||
promise._attachExtraTrace(wrapped);
|
||||
promise._reject(wrapped);
|
||||
} else if (!multiArgs) {
|
||||
promise._fulfill(value);
|
||||
} else {
|
||||
INLINE_SLICE(args, arguments, 1);
|
||||
promise._fulfill(args);
|
||||
}
|
||||
promise = null;
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = nodebackForPromise;
|
|
@ -0,0 +1,62 @@
|
|||
"use strict";
|
||||
module.exports = function(Promise) {
|
||||
var util = require("./util");
|
||||
var async = Promise._async;
|
||||
var ASSERT = require("./assert");
|
||||
var tryCatch = util.tryCatch;
|
||||
var errorObj = util.errorObj;
|
||||
|
||||
function spreadAdapter(val, nodeback) {
|
||||
var promise = this;
|
||||
if (!util.isArray(val)) return successAdapter.call(promise, val, nodeback);
|
||||
var ret =
|
||||
tryCatch(nodeback).apply(promise._boundValue(), [null].concat(val));
|
||||
if (ret === errorObj) {
|
||||
async.throwLater(ret.e);
|
||||
}
|
||||
}
|
||||
|
||||
function successAdapter(val, nodeback) {
|
||||
var promise = this;
|
||||
var receiver = promise._boundValue();
|
||||
ASSERT(typeof nodeback == "function");
|
||||
var ret = val === undefined
|
||||
? tryCatch(nodeback).call(receiver, null)
|
||||
: tryCatch(nodeback).call(receiver, null, val);
|
||||
if (ret === errorObj) {
|
||||
async.throwLater(ret.e);
|
||||
}
|
||||
}
|
||||
function errorAdapter(reason, nodeback) {
|
||||
var promise = this;
|
||||
if (!reason) {
|
||||
var newReason = new Error(reason + "");
|
||||
newReason.cause = reason;
|
||||
reason = newReason;
|
||||
ASSERT(!!reason);
|
||||
}
|
||||
ASSERT(typeof nodeback == "function");
|
||||
var ret = tryCatch(nodeback).call(promise._boundValue(), reason);
|
||||
if (ret === errorObj) {
|
||||
async.throwLater(ret.e);
|
||||
}
|
||||
}
|
||||
|
||||
Promise.prototype.asCallback = Promise.prototype.nodeify = function (nodeback,
|
||||
options) {
|
||||
if (typeof nodeback == "function") {
|
||||
var adapter = successAdapter;
|
||||
if (options !== undefined && Object(options).spread) {
|
||||
adapter = spreadAdapter;
|
||||
}
|
||||
this._then(
|
||||
adapter,
|
||||
errorAdapter,
|
||||
undefined,
|
||||
this,
|
||||
nodeback
|
||||
);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,827 @@
|
|||
"use strict";
|
||||
module.exports = function() {
|
||||
var makeSelfResolutionError = function () {
|
||||
return new TypeError(CIRCULAR_RESOLUTION_ERROR);
|
||||
};
|
||||
var reflectHandler = function() {
|
||||
return new Promise.PromiseInspection(this._target());
|
||||
};
|
||||
var apiRejection = function(msg) {
|
||||
return Promise.reject(new TypeError(msg));
|
||||
};
|
||||
function Proxyable() {}
|
||||
var UNDEFINED_BINDING = {};
|
||||
var ASSERT = require("./assert");
|
||||
var util = require("./util");
|
||||
util.setReflectHandler(reflectHandler);
|
||||
|
||||
var getDomain = function() {
|
||||
var domain = process.domain;
|
||||
if (domain === undefined) {
|
||||
return null;
|
||||
}
|
||||
return domain;
|
||||
};
|
||||
var getContextDefault = function() {
|
||||
return null;
|
||||
};
|
||||
var getContextDomain = function() {
|
||||
return {
|
||||
domain: getDomain(),
|
||||
async: null
|
||||
};
|
||||
};
|
||||
var AsyncResource = util.isNode && util.nodeSupportsAsyncResource ?
|
||||
require("async_hooks").AsyncResource : null;
|
||||
var getContextAsyncHooks = function() {
|
||||
return {
|
||||
domain: getDomain(),
|
||||
async: new AsyncResource("Bluebird::Promise")
|
||||
};
|
||||
};
|
||||
var getContext = util.isNode ? getContextDomain : getContextDefault;
|
||||
util.notEnumerableProp(Promise, "_getContext", getContext);
|
||||
var enableAsyncHooks = function() {
|
||||
getContext = getContextAsyncHooks;
|
||||
util.notEnumerableProp(Promise, "_getContext", getContextAsyncHooks);
|
||||
};
|
||||
var disableAsyncHooks = function() {
|
||||
getContext = getContextDomain;
|
||||
util.notEnumerableProp(Promise, "_getContext", getContextDomain);
|
||||
};
|
||||
|
||||
var es5 = require("./es5");
|
||||
var Async = require("./async");
|
||||
var async = new Async();
|
||||
es5.defineProperty(Promise, "_async", {value: async});
|
||||
var errors = require("./errors");
|
||||
var TypeError = Promise.TypeError = errors.TypeError;
|
||||
Promise.RangeError = errors.RangeError;
|
||||
var CancellationError = Promise.CancellationError = errors.CancellationError;
|
||||
Promise.TimeoutError = errors.TimeoutError;
|
||||
Promise.OperationalError = errors.OperationalError;
|
||||
Promise.RejectionError = errors.OperationalError;
|
||||
Promise.AggregateError = errors.AggregateError;
|
||||
var INTERNAL = function(){};
|
||||
var APPLY = {};
|
||||
var NEXT_FILTER = {};
|
||||
var tryConvertToPromise = require("./thenables")(Promise, INTERNAL);
|
||||
var PromiseArray =
|
||||
require("./promise_array")(Promise, INTERNAL,
|
||||
tryConvertToPromise, apiRejection, Proxyable);
|
||||
var Context = require("./context")(Promise);
|
||||
/*jshint unused:false*/
|
||||
var createContext = Context.create;
|
||||
|
||||
var debug = require("./debuggability")(Promise, Context,
|
||||
enableAsyncHooks, disableAsyncHooks);
|
||||
var CapturedTrace = debug.CapturedTrace;
|
||||
var PassThroughHandlerContext =
|
||||
require("./finally")(Promise, tryConvertToPromise, NEXT_FILTER);
|
||||
var catchFilter = require("./catch_filter")(NEXT_FILTER);
|
||||
var nodebackForPromise = require("./nodeback");
|
||||
var errorObj = util.errorObj;
|
||||
var tryCatch = util.tryCatch;
|
||||
function check(self, executor) {
|
||||
if (self == null || self.constructor !== Promise) {
|
||||
throw new TypeError(CONSTRUCT_ERROR_INVOCATION);
|
||||
}
|
||||
if (typeof executor !== "function") {
|
||||
throw new TypeError(FUNCTION_ERROR + util.classString(executor));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function Promise(executor) {
|
||||
if (executor !== INTERNAL) {
|
||||
check(this, executor);
|
||||
}
|
||||
this._bitField = NO_STATE;
|
||||
this._fulfillmentHandler0 = undefined;
|
||||
this._rejectionHandler0 = undefined;
|
||||
this._promise0 = undefined;
|
||||
this._receiver0 = undefined;
|
||||
this._resolveFromExecutor(executor);
|
||||
this._promiseCreated();
|
||||
this._fireEvent("promiseCreated", this);
|
||||
}
|
||||
|
||||
Promise.prototype.toString = function () {
|
||||
return "[object Promise]";
|
||||
};
|
||||
|
||||
Promise.prototype.caught = Promise.prototype["catch"] = function (fn) {
|
||||
var len = arguments.length;
|
||||
if (len > 1) {
|
||||
var catchInstances = new Array(len - 1),
|
||||
j = 0, i;
|
||||
for (i = 0; i < len - 1; ++i) {
|
||||
var item = arguments[i];
|
||||
if (util.isObject(item)) {
|
||||
catchInstances[j++] = item;
|
||||
} else {
|
||||
return apiRejection("Catch statement predicate: " +
|
||||
OBJECT_ERROR + util.classString(item));
|
||||
}
|
||||
}
|
||||
catchInstances.length = j;
|
||||
fn = arguments[i];
|
||||
|
||||
if (typeof fn !== "function") {
|
||||
throw new TypeError("The last argument to .catch() " +
|
||||
"must be a function, got " + util.toString(fn));
|
||||
}
|
||||
return this.then(undefined, catchFilter(catchInstances, fn, this));
|
||||
}
|
||||
return this.then(undefined, fn);
|
||||
};
|
||||
|
||||
Promise.prototype.reflect = function () {
|
||||
return this._then(reflectHandler,
|
||||
reflectHandler, undefined, this, undefined);
|
||||
};
|
||||
|
||||
Promise.prototype.then = function (didFulfill, didReject) {
|
||||
if (debug.warnings() && arguments.length > 0 &&
|
||||
typeof didFulfill !== "function" &&
|
||||
typeof didReject !== "function") {
|
||||
var msg = ".then() only accepts functions but was passed: " +
|
||||
util.classString(didFulfill);
|
||||
if (arguments.length > 1) {
|
||||
msg += ", " + util.classString(didReject);
|
||||
}
|
||||
this._warn(msg);
|
||||
}
|
||||
return this._then(didFulfill, didReject, undefined, undefined, undefined);
|
||||
};
|
||||
|
||||
Promise.prototype.done = function (didFulfill, didReject) {
|
||||
var promise =
|
||||
this._then(didFulfill, didReject, undefined, undefined, undefined);
|
||||
promise._setIsFinal();
|
||||
};
|
||||
|
||||
Promise.prototype.spread = function (fn) {
|
||||
if (typeof fn !== "function") {
|
||||
return apiRejection(FUNCTION_ERROR + util.classString(fn));
|
||||
}
|
||||
return this.all()._then(fn, undefined, undefined, APPLY, undefined);
|
||||
};
|
||||
|
||||
Promise.prototype.toJSON = function () {
|
||||
var ret = {
|
||||
isFulfilled: false,
|
||||
isRejected: false,
|
||||
fulfillmentValue: undefined,
|
||||
rejectionReason: undefined
|
||||
};
|
||||
if (this.isFulfilled()) {
|
||||
ret.fulfillmentValue = this.value();
|
||||
ret.isFulfilled = true;
|
||||
} else if (this.isRejected()) {
|
||||
ret.rejectionReason = this.reason();
|
||||
ret.isRejected = true;
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
Promise.prototype.all = function () {
|
||||
if (arguments.length > 0) {
|
||||
this._warn(".all() was passed arguments but it does not take any");
|
||||
}
|
||||
return new PromiseArray(this).promise();
|
||||
};
|
||||
|
||||
Promise.prototype.error = function (fn) {
|
||||
return this.caught(util.originatesFromRejection, fn);
|
||||
};
|
||||
|
||||
Promise.getNewLibraryCopy = module.exports;
|
||||
|
||||
Promise.is = function (val) {
|
||||
return val instanceof Promise;
|
||||
};
|
||||
|
||||
Promise.fromNode = Promise.fromCallback = function(fn) {
|
||||
var ret = new Promise(INTERNAL);
|
||||
ret._captureStackTrace();
|
||||
var multiArgs = arguments.length > 1 ? !!Object(arguments[1]).multiArgs
|
||||
: false;
|
||||
var result = tryCatch(fn)(nodebackForPromise(ret, multiArgs));
|
||||
if (result === errorObj) {
|
||||
ret._rejectCallback(result.e, true);
|
||||
}
|
||||
if (!ret._isFateSealed()) ret._setAsyncGuaranteed();
|
||||
return ret;
|
||||
};
|
||||
|
||||
Promise.all = function (promises) {
|
||||
return new PromiseArray(promises).promise();
|
||||
};
|
||||
|
||||
Promise.cast = function (obj) {
|
||||
var ret = tryConvertToPromise(obj);
|
||||
if (!(ret instanceof Promise)) {
|
||||
ret = new Promise(INTERNAL);
|
||||
ret._captureStackTrace();
|
||||
ret._setFulfilled();
|
||||
ret._rejectionHandler0 = obj;
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
Promise.resolve = Promise.fulfilled = Promise.cast;
|
||||
|
||||
Promise.reject = Promise.rejected = function (reason) {
|
||||
var ret = new Promise(INTERNAL);
|
||||
ret._captureStackTrace();
|
||||
ret._rejectCallback(reason, true);
|
||||
return ret;
|
||||
};
|
||||
|
||||
Promise.setScheduler = function(fn) {
|
||||
if (typeof fn !== "function") {
|
||||
throw new TypeError(FUNCTION_ERROR + util.classString(fn));
|
||||
}
|
||||
return async.setScheduler(fn);
|
||||
};
|
||||
|
||||
Promise.prototype._then = function (
|
||||
didFulfill,
|
||||
didReject,
|
||||
_, // For fast-cast compatibility between bluebird versions
|
||||
receiver,
|
||||
internalData
|
||||
) {
|
||||
ASSERT(arguments.length === 5);
|
||||
var haveInternalData = internalData !== undefined;
|
||||
var promise = haveInternalData ? internalData : new Promise(INTERNAL);
|
||||
var target = this._target();
|
||||
var bitField = target._bitField;
|
||||
|
||||
if (!haveInternalData) {
|
||||
promise._propagateFrom(this, PROPAGATE_ALL);
|
||||
promise._captureStackTrace();
|
||||
if (receiver === undefined &&
|
||||
BIT_FIELD_CHECK(IS_BOUND, this._bitField)) {
|
||||
if (!BIT_FIELD_CHECK(IS_PENDING_AND_WAITING_NEG)) {
|
||||
receiver = this._boundValue();
|
||||
} else {
|
||||
receiver = target === this ? undefined : this._boundTo;
|
||||
}
|
||||
}
|
||||
this._fireEvent("promiseChained", this, promise);
|
||||
}
|
||||
|
||||
var context = getContext();
|
||||
if (!BIT_FIELD_CHECK(IS_PENDING_AND_WAITING_NEG)) {
|
||||
var handler, value, settler = target._settlePromiseCtx;
|
||||
if (BIT_FIELD_CHECK(IS_FULFILLED)) {
|
||||
value = target._rejectionHandler0;
|
||||
handler = didFulfill;
|
||||
} else if (BIT_FIELD_CHECK(IS_REJECTED)) {
|
||||
value = target._fulfillmentHandler0;
|
||||
handler = didReject;
|
||||
target._unsetRejectionIsUnhandled();
|
||||
} else {
|
||||
settler = target._settlePromiseLateCancellationObserver;
|
||||
value = new CancellationError(LATE_CANCELLATION_OBSERVER);
|
||||
target._attachExtraTrace(value);
|
||||
handler = didReject;
|
||||
}
|
||||
|
||||
async.invoke(settler, target, {
|
||||
handler: util.contextBind(context, handler),
|
||||
promise: promise,
|
||||
receiver: receiver,
|
||||
value: value
|
||||
});
|
||||
} else {
|
||||
target._addCallbacks(didFulfill, didReject, promise,
|
||||
receiver, context);
|
||||
}
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
Promise.prototype._length = function () {
|
||||
ASSERT(arguments.length === 0);
|
||||
return this._bitField & LENGTH_MASK;
|
||||
};
|
||||
|
||||
Promise.prototype._isFateSealed = function () {
|
||||
return (this._bitField & IS_FATE_SEALED) !== 0;
|
||||
};
|
||||
|
||||
Promise.prototype._isFollowing = function () {
|
||||
return (this._bitField & IS_FOLLOWING) === IS_FOLLOWING;
|
||||
};
|
||||
|
||||
Promise.prototype._setLength = function (len) {
|
||||
this._bitField = (this._bitField & LENGTH_CLEAR_MASK) |
|
||||
(len & LENGTH_MASK);
|
||||
};
|
||||
|
||||
Promise.prototype._setFulfilled = function () {
|
||||
this._bitField = this._bitField | IS_FULFILLED;
|
||||
this._fireEvent("promiseFulfilled", this);
|
||||
};
|
||||
|
||||
Promise.prototype._setRejected = function () {
|
||||
this._bitField = this._bitField | IS_REJECTED;
|
||||
this._fireEvent("promiseRejected", this);
|
||||
};
|
||||
|
||||
Promise.prototype._setFollowing = function () {
|
||||
this._bitField = this._bitField | IS_FOLLOWING;
|
||||
this._fireEvent("promiseResolved", this);
|
||||
};
|
||||
|
||||
Promise.prototype._setIsFinal = function () {
|
||||
this._bitField = this._bitField | IS_FINAL;
|
||||
};
|
||||
|
||||
Promise.prototype._isFinal = function () {
|
||||
return (this._bitField & IS_FINAL) > 0;
|
||||
};
|
||||
|
||||
Promise.prototype._unsetCancelled = function() {
|
||||
this._bitField = this._bitField & (~IS_CANCELLED);
|
||||
};
|
||||
|
||||
Promise.prototype._setCancelled = function() {
|
||||
this._bitField = this._bitField | IS_CANCELLED;
|
||||
this._fireEvent("promiseCancelled", this);
|
||||
};
|
||||
|
||||
Promise.prototype._setWillBeCancelled = function() {
|
||||
this._bitField = this._bitField | WILL_BE_CANCELLED;
|
||||
};
|
||||
|
||||
Promise.prototype._setAsyncGuaranteed = function() {
|
||||
if (async.hasCustomScheduler()) return;
|
||||
var bitField = this._bitField;
|
||||
this._bitField = bitField |
|
||||
(((bitField & NO_ASYNC_GUARANTEE) >> ASYNC_GUARANTEE_SHIFT) ^
|
||||
IS_ASYNC_GUARANTEED);
|
||||
};
|
||||
|
||||
Promise.prototype._setNoAsyncGuarantee = function() {
|
||||
this._bitField = (this._bitField | NO_ASYNC_GUARANTEE) &
|
||||
(~IS_ASYNC_GUARANTEED);
|
||||
};
|
||||
|
||||
Promise.prototype._receiverAt = function (index) {
|
||||
ASSERT(!this._isFollowing());
|
||||
var ret = index === 0 ? this._receiver0 : this[
|
||||
index * CALLBACK_SIZE - CALLBACK_SIZE + CALLBACK_RECEIVER_OFFSET];
|
||||
//Only use the bound value when not calling internal methods
|
||||
if (ret === UNDEFINED_BINDING) {
|
||||
return undefined;
|
||||
} else if (ret === undefined && this._isBound()) {
|
||||
return this._boundValue();
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
Promise.prototype._promiseAt = function (index) {
|
||||
ASSERT(index > 0);
|
||||
ASSERT(!this._isFollowing());
|
||||
return this[
|
||||
index * CALLBACK_SIZE - CALLBACK_SIZE + CALLBACK_PROMISE_OFFSET];
|
||||
};
|
||||
|
||||
Promise.prototype._fulfillmentHandlerAt = function (index) {
|
||||
ASSERT(!this._isFollowing());
|
||||
ASSERT(index > 0);
|
||||
return this[
|
||||
index * CALLBACK_SIZE - CALLBACK_SIZE + CALLBACK_FULFILL_OFFSET];
|
||||
};
|
||||
|
||||
Promise.prototype._rejectionHandlerAt = function (index) {
|
||||
ASSERT(!this._isFollowing());
|
||||
ASSERT(index > 0);
|
||||
return this[
|
||||
index * CALLBACK_SIZE - CALLBACK_SIZE + CALLBACK_REJECT_OFFSET];
|
||||
};
|
||||
|
||||
Promise.prototype._boundValue = function() {};
|
||||
|
||||
Promise.prototype._migrateCallback0 = function (follower) {
|
||||
var bitField = follower._bitField;
|
||||
var fulfill = follower._fulfillmentHandler0;
|
||||
var reject = follower._rejectionHandler0;
|
||||
var promise = follower._promise0;
|
||||
var receiver = follower._receiverAt(0);
|
||||
if (receiver === undefined) receiver = UNDEFINED_BINDING;
|
||||
this._addCallbacks(fulfill, reject, promise, receiver, null);
|
||||
};
|
||||
|
||||
Promise.prototype._migrateCallbackAt = function (follower, index) {
|
||||
ASSERT(index > 0);
|
||||
var fulfill = follower._fulfillmentHandlerAt(index);
|
||||
var reject = follower._rejectionHandlerAt(index);
|
||||
var promise = follower._promiseAt(index);
|
||||
var receiver = follower._receiverAt(index);
|
||||
if (receiver === undefined) receiver = UNDEFINED_BINDING;
|
||||
this._addCallbacks(fulfill, reject, promise, receiver, null);
|
||||
};
|
||||
|
||||
Promise.prototype._addCallbacks = function (
|
||||
fulfill,
|
||||
reject,
|
||||
promise,
|
||||
receiver,
|
||||
context
|
||||
) {
|
||||
ASSERT(typeof context === "object");
|
||||
ASSERT(!this._isFateSealed());
|
||||
ASSERT(!this._isFollowing());
|
||||
var index = this._length();
|
||||
|
||||
if (index >= MAX_LENGTH - CALLBACK_SIZE) {
|
||||
index = 0;
|
||||
this._setLength(0);
|
||||
}
|
||||
|
||||
if (index === 0) {
|
||||
ASSERT(this._promise0 === undefined);
|
||||
ASSERT(this._receiver0 === undefined);
|
||||
ASSERT(this._fulfillmentHandler0 === undefined);
|
||||
ASSERT(this._rejectionHandler0 === undefined);
|
||||
|
||||
this._promise0 = promise;
|
||||
this._receiver0 = receiver;
|
||||
if (typeof fulfill === "function") {
|
||||
this._fulfillmentHandler0 = util.contextBind(context, fulfill);
|
||||
}
|
||||
if (typeof reject === "function") {
|
||||
this._rejectionHandler0 = util.contextBind(context, reject);
|
||||
}
|
||||
} else {
|
||||
ASSERT(this[base + CALLBACK_PROMISE_OFFSET] === undefined);
|
||||
ASSERT(this[base + CALLBACK_RECEIVER_OFFSET] === undefined);
|
||||
ASSERT(this[base + CALLBACK_FULFILL_OFFSET] === undefined);
|
||||
ASSERT(this[base + CALLBACK_REJECT_OFFSET] === undefined);
|
||||
var base = index * CALLBACK_SIZE - CALLBACK_SIZE;
|
||||
this[base + CALLBACK_PROMISE_OFFSET] = promise;
|
||||
this[base + CALLBACK_RECEIVER_OFFSET] = receiver;
|
||||
if (typeof fulfill === "function") {
|
||||
this[base + CALLBACK_FULFILL_OFFSET] =
|
||||
util.contextBind(context, fulfill);
|
||||
}
|
||||
if (typeof reject === "function") {
|
||||
this[base + CALLBACK_REJECT_OFFSET] =
|
||||
util.contextBind(context, reject);
|
||||
}
|
||||
}
|
||||
this._setLength(index + 1);
|
||||
return index;
|
||||
};
|
||||
|
||||
Promise.prototype._proxy = function (proxyable, arg) {
|
||||
ASSERT(proxyable instanceof Proxyable);
|
||||
ASSERT(!(arg instanceof Promise));
|
||||
ASSERT(!this._isFollowing());
|
||||
ASSERT(arguments.length === 2);
|
||||
ASSERT(!this._isFateSealed());
|
||||
this._addCallbacks(undefined, undefined, arg, proxyable, null);
|
||||
};
|
||||
|
||||
Promise.prototype._resolveCallback = function(value, shouldBind) {
|
||||
if (BIT_FIELD_CHECK(IS_FATE_SEALED, this._bitField)) return;
|
||||
if (value === this)
|
||||
return this._rejectCallback(makeSelfResolutionError(), false);
|
||||
var maybePromise = tryConvertToPromise(value, this);
|
||||
if (!(maybePromise instanceof Promise)) return this._fulfill(value);
|
||||
|
||||
if (shouldBind) this._propagateFrom(maybePromise, PROPAGATE_BIND);
|
||||
|
||||
|
||||
var promise = maybePromise._target();
|
||||
|
||||
if (promise === this) {
|
||||
this._reject(makeSelfResolutionError());
|
||||
return;
|
||||
}
|
||||
|
||||
var bitField = promise._bitField;
|
||||
if (BIT_FIELD_CHECK(IS_PENDING_AND_WAITING_NEG)) {
|
||||
var len = this._length();
|
||||
if (len > 0) promise._migrateCallback0(this);
|
||||
for (var i = 1; i < len; ++i) {
|
||||
promise._migrateCallbackAt(this, i);
|
||||
}
|
||||
this._setFollowing();
|
||||
this._setLength(0);
|
||||
this._setFollowee(maybePromise);
|
||||
} else if (BIT_FIELD_CHECK(IS_FULFILLED)) {
|
||||
this._fulfill(promise._value());
|
||||
} else if (BIT_FIELD_CHECK(IS_REJECTED)) {
|
||||
this._reject(promise._reason());
|
||||
} else {
|
||||
var reason = new CancellationError(LATE_CANCELLATION_OBSERVER);
|
||||
promise._attachExtraTrace(reason);
|
||||
this._reject(reason);
|
||||
}
|
||||
};
|
||||
|
||||
Promise.prototype._rejectCallback =
|
||||
function(reason, synchronous, ignoreNonErrorWarnings) {
|
||||
var trace = util.ensureErrorObject(reason);
|
||||
var hasStack = trace === reason;
|
||||
if (!hasStack && !ignoreNonErrorWarnings && debug.warnings()) {
|
||||
var message = "a promise was rejected with a non-error: " +
|
||||
util.classString(reason);
|
||||
this._warn(message, true);
|
||||
}
|
||||
this._attachExtraTrace(trace, synchronous ? hasStack : false);
|
||||
this._reject(reason);
|
||||
};
|
||||
|
||||
Promise.prototype._resolveFromExecutor = function (executor) {
|
||||
if (executor === INTERNAL) return;
|
||||
ASSERT(typeof executor === "function");
|
||||
var promise = this;
|
||||
this._captureStackTrace();
|
||||
this._pushContext();
|
||||
var synchronous = true;
|
||||
var r = this._execute(executor, function(value) {
|
||||
promise._resolveCallback(value);
|
||||
}, function (reason) {
|
||||
promise._rejectCallback(reason, synchronous);
|
||||
});
|
||||
synchronous = false;
|
||||
this._popContext();
|
||||
|
||||
if (r !== undefined) {
|
||||
promise._rejectCallback(r, true);
|
||||
}
|
||||
};
|
||||
|
||||
Promise.prototype._settlePromiseFromHandler = function (
|
||||
handler, receiver, value, promise
|
||||
) {
|
||||
var bitField = promise._bitField;
|
||||
if (BIT_FIELD_CHECK(IS_CANCELLED)) return;
|
||||
promise._pushContext();
|
||||
var x;
|
||||
if (receiver === APPLY) {
|
||||
if (!value || typeof value.length !== "number") {
|
||||
x = errorObj;
|
||||
x.e = new TypeError("cannot .spread() a non-array: " +
|
||||
util.classString(value));
|
||||
} else {
|
||||
x = tryCatch(handler).apply(this._boundValue(), value);
|
||||
}
|
||||
} else {
|
||||
x = tryCatch(handler).call(receiver, value);
|
||||
}
|
||||
var promiseCreated = promise._popContext();
|
||||
bitField = promise._bitField;
|
||||
if (BIT_FIELD_CHECK(IS_CANCELLED)) return;
|
||||
|
||||
ASSERT(!promise._isFateSealed());
|
||||
|
||||
if (x === NEXT_FILTER) {
|
||||
promise._reject(value);
|
||||
} else if (x === errorObj) {
|
||||
promise._rejectCallback(x.e, false);
|
||||
} else {
|
||||
debug.checkForgottenReturns(x, promiseCreated, "", promise, this);
|
||||
promise._resolveCallback(x);
|
||||
}
|
||||
};
|
||||
|
||||
Promise.prototype._target = function() {
|
||||
var ret = this;
|
||||
while (ret._isFollowing()) ret = ret._followee();
|
||||
return ret;
|
||||
};
|
||||
|
||||
Promise.prototype._followee = function() {
|
||||
ASSERT(this._isFollowing());
|
||||
ASSERT(this._rejectionHandler0 instanceof Promise);
|
||||
return this._rejectionHandler0;
|
||||
};
|
||||
|
||||
Promise.prototype._setFollowee = function(promise) {
|
||||
ASSERT(this._isFollowing());
|
||||
ASSERT(!(this._rejectionHandler0 instanceof Promise));
|
||||
this._rejectionHandler0 = promise;
|
||||
};
|
||||
|
||||
Promise.prototype._settlePromise = function(promise, handler, receiver, value) {
|
||||
ASSERT(!this._isFollowing());
|
||||
var isPromise = promise instanceof Promise;
|
||||
var bitField = this._bitField;
|
||||
var asyncGuaranteed = BIT_FIELD_CHECK(IS_ASYNC_GUARANTEED);
|
||||
if (BIT_FIELD_CHECK(IS_CANCELLED)) {
|
||||
if (isPromise) promise._invokeInternalOnCancel();
|
||||
|
||||
if (receiver instanceof PassThroughHandlerContext &&
|
||||
receiver.isFinallyHandler()) {
|
||||
receiver.cancelPromise = promise;
|
||||
if (tryCatch(handler).call(receiver, value) === errorObj) {
|
||||
promise._reject(errorObj.e);
|
||||
}
|
||||
} else if (handler === reflectHandler) {
|
||||
promise._fulfill(reflectHandler.call(receiver));
|
||||
} else if (receiver instanceof Proxyable) {
|
||||
receiver._promiseCancelled(promise);
|
||||
} else if (isPromise || promise instanceof PromiseArray) {
|
||||
promise._cancel();
|
||||
} else {
|
||||
receiver.cancel();
|
||||
}
|
||||
} else if (typeof handler === "function") {
|
||||
//if promise is not instanceof Promise
|
||||
//it is internally smuggled data
|
||||
if (!isPromise) {
|
||||
handler.call(receiver, value, promise);
|
||||
} else {
|
||||
if (asyncGuaranteed) promise._setAsyncGuaranteed();
|
||||
this._settlePromiseFromHandler(handler, receiver, value, promise);
|
||||
}
|
||||
} else if (receiver instanceof Proxyable) {
|
||||
if (!receiver._isResolved()) {
|
||||
if (BIT_FIELD_CHECK(IS_FULFILLED)) {
|
||||
receiver._promiseFulfilled(value, promise);
|
||||
} else {
|
||||
receiver._promiseRejected(value, promise);
|
||||
}
|
||||
}
|
||||
} else if (isPromise) {
|
||||
if (asyncGuaranteed) promise._setAsyncGuaranteed();
|
||||
if (BIT_FIELD_CHECK(IS_FULFILLED)) {
|
||||
promise._fulfill(value);
|
||||
} else {
|
||||
promise._reject(value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Promise.prototype._settlePromiseLateCancellationObserver = function(ctx) {
|
||||
var handler = ctx.handler;
|
||||
var promise = ctx.promise;
|
||||
var receiver = ctx.receiver;
|
||||
var value = ctx.value;
|
||||
if (typeof handler === "function") {
|
||||
if (!(promise instanceof Promise)) {
|
||||
handler.call(receiver, value, promise);
|
||||
} else {
|
||||
this._settlePromiseFromHandler(handler, receiver, value, promise);
|
||||
}
|
||||
} else if (promise instanceof Promise) {
|
||||
promise._reject(value);
|
||||
}
|
||||
};
|
||||
|
||||
Promise.prototype._settlePromiseCtx = function(ctx) {
|
||||
this._settlePromise(ctx.promise, ctx.handler, ctx.receiver, ctx.value);
|
||||
};
|
||||
|
||||
Promise.prototype._settlePromise0 = function(handler, value, bitField) {
|
||||
var promise = this._promise0;
|
||||
var receiver = this._receiverAt(0);
|
||||
this._promise0 = undefined;
|
||||
this._receiver0 = undefined;
|
||||
this._settlePromise(promise, handler, receiver, value);
|
||||
};
|
||||
|
||||
Promise.prototype._clearCallbackDataAtIndex = function(index) {
|
||||
ASSERT(!this._isFollowing());
|
||||
ASSERT(index > 0);
|
||||
var base = index * CALLBACK_SIZE - CALLBACK_SIZE;
|
||||
this[base + CALLBACK_PROMISE_OFFSET] =
|
||||
this[base + CALLBACK_RECEIVER_OFFSET] =
|
||||
this[base + CALLBACK_FULFILL_OFFSET] =
|
||||
this[base + CALLBACK_REJECT_OFFSET] = undefined;
|
||||
};
|
||||
|
||||
Promise.prototype._fulfill = function (value) {
|
||||
var bitField = this._bitField;
|
||||
if (BIT_FIELD_READ(IS_FATE_SEALED)) return;
|
||||
if (value === this) {
|
||||
var err = makeSelfResolutionError();
|
||||
this._attachExtraTrace(err);
|
||||
return this._reject(err);
|
||||
}
|
||||
this._setFulfilled();
|
||||
this._rejectionHandler0 = value;
|
||||
|
||||
if (BIT_FIELD_READ(LENGTH_MASK) > 0) {
|
||||
if (BIT_FIELD_CHECK(IS_ASYNC_GUARANTEED)) {
|
||||
this._settlePromises();
|
||||
} else {
|
||||
async.settlePromises(this);
|
||||
}
|
||||
this._dereferenceTrace();
|
||||
}
|
||||
};
|
||||
|
||||
Promise.prototype._reject = function (reason) {
|
||||
var bitField = this._bitField;
|
||||
if (BIT_FIELD_READ(IS_FATE_SEALED)) return;
|
||||
this._setRejected();
|
||||
this._fulfillmentHandler0 = reason;
|
||||
|
||||
if (this._isFinal()) {
|
||||
ASSERT(this._length() === 0);
|
||||
return async.fatalError(reason, util.isNode);
|
||||
}
|
||||
|
||||
if (BIT_FIELD_READ(LENGTH_MASK) > 0) {
|
||||
async.settlePromises(this);
|
||||
} else {
|
||||
this._ensurePossibleRejectionHandled();
|
||||
}
|
||||
};
|
||||
|
||||
Promise.prototype._fulfillPromises = function (len, value) {
|
||||
for (var i = 1; i < len; i++) {
|
||||
var handler = this._fulfillmentHandlerAt(i);
|
||||
var promise = this._promiseAt(i);
|
||||
var receiver = this._receiverAt(i);
|
||||
this._clearCallbackDataAtIndex(i);
|
||||
this._settlePromise(promise, handler, receiver, value);
|
||||
}
|
||||
};
|
||||
|
||||
Promise.prototype._rejectPromises = function (len, reason) {
|
||||
for (var i = 1; i < len; i++) {
|
||||
var handler = this._rejectionHandlerAt(i);
|
||||
var promise = this._promiseAt(i);
|
||||
var receiver = this._receiverAt(i);
|
||||
this._clearCallbackDataAtIndex(i);
|
||||
this._settlePromise(promise, handler, receiver, reason);
|
||||
}
|
||||
};
|
||||
|
||||
Promise.prototype._settlePromises = function () {
|
||||
var bitField = this._bitField;
|
||||
var len = BIT_FIELD_READ(LENGTH_MASK);
|
||||
|
||||
if (len > 0) {
|
||||
if (BIT_FIELD_CHECK(IS_REJECTED_OR_CANCELLED)) {
|
||||
var reason = this._fulfillmentHandler0;
|
||||
this._settlePromise0(this._rejectionHandler0, reason, bitField);
|
||||
this._rejectPromises(len, reason);
|
||||
} else {
|
||||
var value = this._rejectionHandler0;
|
||||
this._settlePromise0(this._fulfillmentHandler0, value, bitField);
|
||||
this._fulfillPromises(len, value);
|
||||
}
|
||||
this._setLength(0);
|
||||
}
|
||||
this._clearCancellationData();
|
||||
};
|
||||
|
||||
Promise.prototype._settledValue = function() {
|
||||
ASSERT(!this._isFollowing());
|
||||
ASSERT(this._isFateSealed());
|
||||
var bitField = this._bitField;
|
||||
if (BIT_FIELD_CHECK(IS_FULFILLED)) {
|
||||
return this._rejectionHandler0;
|
||||
} else if (BIT_FIELD_CHECK(IS_REJECTED)) {
|
||||
return this._fulfillmentHandler0;
|
||||
}
|
||||
// Implicit undefined for cancelled promise.
|
||||
};
|
||||
|
||||
if (typeof Symbol !== "undefined" && Symbol.toStringTag) {
|
||||
es5.defineProperty(Promise.prototype, Symbol.toStringTag, {
|
||||
get: function () {
|
||||
return "Object";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function deferResolve(v) {this.promise._resolveCallback(v);}
|
||||
function deferReject(v) {this.promise._rejectCallback(v, false);}
|
||||
|
||||
Promise.defer = Promise.pending = function() {
|
||||
debug.deprecated("Promise.defer", "new Promise");
|
||||
var promise = new Promise(INTERNAL);
|
||||
return {
|
||||
promise: promise,
|
||||
resolve: deferResolve,
|
||||
reject: deferReject
|
||||
};
|
||||
};
|
||||
|
||||
util.notEnumerableProp(Promise,
|
||||
"_makeSelfResolutionError",
|
||||
makeSelfResolutionError);
|
||||
|
||||
require("./method")(Promise, INTERNAL, tryConvertToPromise, apiRejection,
|
||||
debug);
|
||||
require("./bind")(Promise, INTERNAL, tryConvertToPromise, debug);
|
||||
require("./cancel")(Promise, PromiseArray, apiRejection, debug);
|
||||
require("./direct_resolve")(Promise);
|
||||
require("./synchronous_inspection")(Promise);
|
||||
require("./join")(
|
||||
Promise, PromiseArray, tryConvertToPromise, INTERNAL, async);
|
||||
Promise.Promise = Promise;
|
||||
Promise.version = "__VERSION__";
|
||||
};
|
|
@ -0,0 +1,203 @@
|
|||
"use strict";
|
||||
module.exports = function(Promise, INTERNAL, tryConvertToPromise,
|
||||
apiRejection, Proxyable) {
|
||||
var ASSERT = require("./assert");
|
||||
var util = require("./util");
|
||||
var isArray = util.isArray;
|
||||
|
||||
//To avoid eagerly allocating the objects
|
||||
//and also because undefined cannot be smuggled
|
||||
function toResolutionValue(val) {
|
||||
switch(val) {
|
||||
case RESOLVE_ARRAY: return [];
|
||||
case RESOLVE_OBJECT: return {};
|
||||
case RESOLVE_MAP: return new Map();
|
||||
}
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
function PromiseArray(values) {
|
||||
ASSERT(arguments.length === 1);
|
||||
var promise = this._promise = new Promise(INTERNAL);
|
||||
if (values instanceof Promise) {
|
||||
promise._propagateFrom(values, PROPAGATE_ALL);
|
||||
values.suppressUnhandledRejections();
|
||||
}
|
||||
promise._setOnCancel(this);
|
||||
this._values = values;
|
||||
this._length = 0;
|
||||
this._totalResolved = 0;
|
||||
this._init(undefined, RESOLVE_ARRAY);
|
||||
}
|
||||
util.inherits(PromiseArray, Proxyable);
|
||||
|
||||
PromiseArray.prototype.length = function () {
|
||||
return this._length;
|
||||
};
|
||||
|
||||
PromiseArray.prototype.promise = function () {
|
||||
return this._promise;
|
||||
};
|
||||
|
||||
PromiseArray.prototype._init = function init(_, resolveValueIfEmpty) {
|
||||
var values = tryConvertToPromise(this._values, this._promise);
|
||||
if (values instanceof Promise) {
|
||||
values = values._target();
|
||||
var bitField = values._bitField;
|
||||
USE(bitField);
|
||||
this._values = values;
|
||||
|
||||
if (BIT_FIELD_CHECK(IS_PENDING_AND_WAITING_NEG)) {
|
||||
ASSERT(typeof resolveValueIfEmpty === "number");
|
||||
ASSERT(resolveValueIfEmpty < 0);
|
||||
this._promise._setAsyncGuaranteed();
|
||||
return values._then(
|
||||
init,
|
||||
this._reject,
|
||||
undefined,
|
||||
this,
|
||||
resolveValueIfEmpty
|
||||
);
|
||||
} else if (BIT_FIELD_CHECK(IS_FULFILLED)) {
|
||||
values = values._value();
|
||||
} else if (BIT_FIELD_CHECK(IS_REJECTED)) {
|
||||
return this._reject(values._reason());
|
||||
} else {
|
||||
return this._cancel();
|
||||
}
|
||||
}
|
||||
values = util.asArray(values);
|
||||
if (values === null) {
|
||||
var err = apiRejection(
|
||||
COLLECTION_ERROR + util.classString(values)).reason();
|
||||
this._promise._rejectCallback(err, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (values.length === 0) {
|
||||
if (resolveValueIfEmpty === RESOLVE_CALL_METHOD) {
|
||||
this._resolveEmptyArray();
|
||||
}
|
||||
else {
|
||||
this._resolve(toResolutionValue(resolveValueIfEmpty));
|
||||
}
|
||||
return;
|
||||
}
|
||||
this._iterate(values);
|
||||
};
|
||||
|
||||
PromiseArray.prototype._iterate = function(values) {
|
||||
var len = this.getActualLength(values.length);
|
||||
this._length = len;
|
||||
this._values = this.shouldCopyValues() ? new Array(len) : this._values;
|
||||
var result = this._promise;
|
||||
var isResolved = false;
|
||||
var bitField = null;
|
||||
for (var i = 0; i < len; ++i) {
|
||||
var maybePromise = tryConvertToPromise(values[i], result);
|
||||
|
||||
if (maybePromise instanceof Promise) {
|
||||
maybePromise = maybePromise._target();
|
||||
bitField = maybePromise._bitField;
|
||||
} else {
|
||||
bitField = null;
|
||||
}
|
||||
|
||||
if (isResolved) {
|
||||
if (bitField !== null) {
|
||||
maybePromise.suppressUnhandledRejections();
|
||||
}
|
||||
} else if (bitField !== null) {
|
||||
if (BIT_FIELD_CHECK(IS_PENDING_AND_WAITING_NEG)) {
|
||||
// Optimized for just passing the updates through
|
||||
maybePromise._proxy(this, i);
|
||||
this._values[i] = maybePromise;
|
||||
} else if (BIT_FIELD_CHECK(IS_FULFILLED)) {
|
||||
isResolved = this._promiseFulfilled(maybePromise._value(), i);
|
||||
} else if (BIT_FIELD_CHECK(IS_REJECTED)) {
|
||||
isResolved = this._promiseRejected(maybePromise._reason(), i);
|
||||
} else {
|
||||
isResolved = this._promiseCancelled(i);
|
||||
}
|
||||
} else {
|
||||
isResolved = this._promiseFulfilled(maybePromise, i);
|
||||
}
|
||||
ASSERT(typeof isResolved === "boolean");
|
||||
}
|
||||
if (!isResolved) result._setAsyncGuaranteed();
|
||||
};
|
||||
|
||||
PromiseArray.prototype._isResolved = function () {
|
||||
return this._values === null;
|
||||
};
|
||||
|
||||
PromiseArray.prototype._resolve = function (value) {
|
||||
ASSERT(!this._isResolved());
|
||||
ASSERT(!(value instanceof Promise));
|
||||
this._values = null;
|
||||
this._promise._fulfill(value);
|
||||
};
|
||||
|
||||
PromiseArray.prototype._cancel = function() {
|
||||
if (this._isResolved() || !this._promise._isCancellable()) return;
|
||||
this._values = null;
|
||||
this._promise._cancel();
|
||||
};
|
||||
|
||||
PromiseArray.prototype._reject = function (reason) {
|
||||
ASSERT(!this._isResolved());
|
||||
this._values = null;
|
||||
this._promise._rejectCallback(reason, false);
|
||||
};
|
||||
|
||||
PromiseArray.prototype._promiseFulfilled = function (value, index) {
|
||||
ASSERT(!this._isResolved());
|
||||
ASSERT(isArray(this._values));
|
||||
ASSERT(typeof index === "number");
|
||||
this._values[index] = value;
|
||||
var totalResolved = ++this._totalResolved;
|
||||
if (totalResolved >= this._length) {
|
||||
this._resolve(this._values);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
PromiseArray.prototype._promiseCancelled = function() {
|
||||
this._cancel();
|
||||
return true;
|
||||
};
|
||||
|
||||
PromiseArray.prototype._promiseRejected = function (reason) {
|
||||
ASSERT(!this._isResolved());
|
||||
ASSERT(isArray(this._values));
|
||||
this._totalResolved++;
|
||||
this._reject(reason);
|
||||
return true;
|
||||
};
|
||||
|
||||
PromiseArray.prototype._resultCancelled = function() {
|
||||
if (this._isResolved()) return;
|
||||
var values = this._values;
|
||||
this._cancel();
|
||||
if (values instanceof Promise) {
|
||||
values.cancel();
|
||||
} else {
|
||||
for (var i = 0; i < values.length; ++i) {
|
||||
if (values[i] instanceof Promise) {
|
||||
values[i].cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
PromiseArray.prototype.shouldCopyValues = function () {
|
||||
return true;
|
||||
};
|
||||
|
||||
PromiseArray.prototype.getActualLength = function (len) {
|
||||
return len;
|
||||
};
|
||||
|
||||
return PromiseArray;
|
||||
};
|
|
@ -0,0 +1,326 @@
|
|||
"use strict";
|
||||
module.exports = function(Promise, INTERNAL) {
|
||||
var THIS = {};
|
||||
var util = require("./util");
|
||||
var nodebackForPromise = require("./nodeback");
|
||||
var withAppended = util.withAppended;
|
||||
var maybeWrapAsError = util.maybeWrapAsError;
|
||||
var canEvaluate = util.canEvaluate;
|
||||
var ASSERT = require("./assert");
|
||||
var TypeError = require("./errors").TypeError;
|
||||
var defaultSuffix = AFTER_PROMISIFIED_SUFFIX;
|
||||
var defaultPromisified = {__isPromisified__: true};
|
||||
var noCopyProps = [
|
||||
"arity", // Firefox 4
|
||||
"length",
|
||||
"name",
|
||||
"arguments",
|
||||
"caller",
|
||||
"callee",
|
||||
"prototype",
|
||||
"__isPromisified__"
|
||||
];
|
||||
var noCopyPropsPattern = new RegExp("^(?:" + noCopyProps.join("|") + ")$");
|
||||
|
||||
var defaultFilter = function(name) {
|
||||
return util.isIdentifier(name) &&
|
||||
name.charAt(0) !== "_" &&
|
||||
name !== "constructor";
|
||||
};
|
||||
|
||||
function propsFilter(key) {
|
||||
return !noCopyPropsPattern.test(key);
|
||||
}
|
||||
|
||||
function isPromisified(fn) {
|
||||
try {
|
||||
return fn.__isPromisified__ === true;
|
||||
}
|
||||
catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function hasPromisified(obj, key, suffix) {
|
||||
var val = util.getDataPropertyOrDefault(obj, key + suffix,
|
||||
defaultPromisified);
|
||||
return val ? isPromisified(val) : false;
|
||||
}
|
||||
function checkValid(ret, suffix, suffixRegexp) {
|
||||
// Verify that in the list of methods to promisify there is no
|
||||
// method that has a name ending in "Async"-suffix while
|
||||
// also having a method with the same name but no Async suffix
|
||||
for (var i = 0; i < ret.length; i += 2) {
|
||||
var key = ret[i];
|
||||
if (suffixRegexp.test(key)) {
|
||||
var keyWithoutAsyncSuffix = key.replace(suffixRegexp, "");
|
||||
for (var j = 0; j < ret.length; j += 2) {
|
||||
if (ret[j] === keyWithoutAsyncSuffix) {
|
||||
throw new TypeError(PROMISIFICATION_NORMAL_METHODS_ERROR
|
||||
.replace("%s", suffix));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function promisifiableMethods(obj, suffix, suffixRegexp, filter) {
|
||||
var keys = util.inheritedDataKeys(obj);
|
||||
var ret = [];
|
||||
for (var i = 0; i < keys.length; ++i) {
|
||||
var key = keys[i];
|
||||
var value = obj[key];
|
||||
var passesDefaultFilter = filter === defaultFilter
|
||||
? true : defaultFilter(key, value, obj);
|
||||
if (typeof value === "function" &&
|
||||
!isPromisified(value) &&
|
||||
!hasPromisified(obj, key, suffix) &&
|
||||
filter(key, value, obj, passesDefaultFilter)) {
|
||||
ret.push(key, value);
|
||||
}
|
||||
}
|
||||
checkValid(ret, suffix, suffixRegexp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
var escapeIdentRegex = function(str) {
|
||||
return str.replace(/([$])/, "\\$");
|
||||
};
|
||||
|
||||
var makeNodePromisifiedEval;
|
||||
if (!__BROWSER__) {
|
||||
//Gives an optimal sequence of argument count to try given a formal parameter
|
||||
//.length for a function
|
||||
var switchCaseArgumentOrder = function(likelyArgumentCount) {
|
||||
var ret = [likelyArgumentCount];
|
||||
var min = Math.max(0, likelyArgumentCount - 1 - PARAM_COUNTS_TO_TRY);
|
||||
for(var i = likelyArgumentCount - 1; i >= min; --i) {
|
||||
ret.push(i);
|
||||
}
|
||||
for(var i = likelyArgumentCount + 1; i <= PARAM_COUNTS_TO_TRY; ++i) {
|
||||
ret.push(i);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
var argumentSequence = function(argumentCount) {
|
||||
return util.filledRange(argumentCount, "_arg", "");
|
||||
};
|
||||
|
||||
var parameterDeclaration = function(parameterCount) {
|
||||
return util.filledRange(
|
||||
Math.max(parameterCount, PARAM_COUNTS_TO_TRY), "_arg", "");
|
||||
};
|
||||
|
||||
var parameterCount = function(fn) {
|
||||
if (typeof fn.length === "number") {
|
||||
return Math.max(Math.min(fn.length, MAX_PARAM_COUNT + 1), 0);
|
||||
}
|
||||
//Unsupported .length for functions
|
||||
return 0;
|
||||
};
|
||||
|
||||
makeNodePromisifiedEval =
|
||||
function(callback, receiver, originalName, fn, _, multiArgs) {
|
||||
//-1 for the callback parameter
|
||||
var newParameterCount = Math.max(0, parameterCount(fn) - 1);
|
||||
var argumentOrder = switchCaseArgumentOrder(newParameterCount);
|
||||
var shouldProxyThis = typeof callback === "string" || receiver === THIS;
|
||||
|
||||
function generateCallForArgumentCount(count) {
|
||||
var args = argumentSequence(count).join(", ");
|
||||
var comma = count > 0 ? ", " : "";
|
||||
var ret;
|
||||
if (shouldProxyThis) {
|
||||
ret = "ret = callback.call(this, {{args}}, nodeback); break;\n";
|
||||
} else {
|
||||
ret = receiver === undefined
|
||||
? "ret = callback({{args}}, nodeback); break;\n"
|
||||
: "ret = callback.call(receiver, {{args}}, nodeback); break;\n";
|
||||
}
|
||||
return ret.replace("{{args}}", args).replace(", ", comma);
|
||||
}
|
||||
|
||||
function generateArgumentSwitchCase() {
|
||||
var ret = "";
|
||||
for (var i = 0; i < argumentOrder.length; ++i) {
|
||||
ret += "case " + argumentOrder[i] +":" +
|
||||
generateCallForArgumentCount(argumentOrder[i]);
|
||||
}
|
||||
|
||||
ret += " \n\
|
||||
default: \n\
|
||||
var args = new Array(len + 1); \n\
|
||||
var i = 0; \n\
|
||||
for (var i = 0; i < len; ++i) { \n\
|
||||
args[i] = arguments[i]; \n\
|
||||
} \n\
|
||||
args[i] = nodeback; \n\
|
||||
[CodeForCall] \n\
|
||||
break; \n\
|
||||
".replace("[CodeForCall]", (shouldProxyThis
|
||||
? "ret = callback.apply(this, args);\n"
|
||||
: "ret = callback.apply(receiver, args);\n"));
|
||||
return ret;
|
||||
}
|
||||
|
||||
var getFunctionCode = typeof callback === "string"
|
||||
? ("this != null ? this['"+callback+"'] : fn")
|
||||
: "fn";
|
||||
var body = "'use strict'; \n\
|
||||
var ret = function (Parameters) { \n\
|
||||
'use strict'; \n\
|
||||
var len = arguments.length; \n\
|
||||
var promise = new Promise(INTERNAL); \n\
|
||||
promise._captureStackTrace(); \n\
|
||||
var nodeback = nodebackForPromise(promise, " + multiArgs + "); \n\
|
||||
var ret; \n\
|
||||
var callback = tryCatch([GetFunctionCode]); \n\
|
||||
switch(len) { \n\
|
||||
[CodeForSwitchCase] \n\
|
||||
} \n\
|
||||
if (ret === errorObj) { \n\
|
||||
promise._rejectCallback(maybeWrapAsError(ret.e), true, true);\n\
|
||||
} \n\
|
||||
if (!promise._isFateSealed()) promise._setAsyncGuaranteed(); \n\
|
||||
return promise; \n\
|
||||
}; \n\
|
||||
notEnumerableProp(ret, '__isPromisified__', true); \n\
|
||||
return ret; \n\
|
||||
".replace("[CodeForSwitchCase]", generateArgumentSwitchCase())
|
||||
.replace("[GetFunctionCode]", getFunctionCode);
|
||||
body = body.replace("Parameters", parameterDeclaration(newParameterCount));
|
||||
return new Function("Promise",
|
||||
"fn",
|
||||
"receiver",
|
||||
"withAppended",
|
||||
"maybeWrapAsError",
|
||||
"nodebackForPromise",
|
||||
"tryCatch",
|
||||
"errorObj",
|
||||
"notEnumerableProp",
|
||||
"INTERNAL",
|
||||
body)(
|
||||
Promise,
|
||||
fn,
|
||||
receiver,
|
||||
withAppended,
|
||||
maybeWrapAsError,
|
||||
nodebackForPromise,
|
||||
util.tryCatch,
|
||||
util.errorObj,
|
||||
util.notEnumerableProp,
|
||||
INTERNAL);
|
||||
};
|
||||
}
|
||||
|
||||
function makeNodePromisifiedClosure(callback, receiver, _, fn, __, multiArgs) {
|
||||
var defaultThis = (function() {return this;})();
|
||||
var method = callback;
|
||||
if (typeof method === "string") {
|
||||
callback = fn;
|
||||
}
|
||||
function promisified() {
|
||||
var _receiver = receiver;
|
||||
if (receiver === THIS) _receiver = this;
|
||||
ASSERT(typeof callback === "function");
|
||||
var promise = new Promise(INTERNAL);
|
||||
promise._captureStackTrace();
|
||||
var cb = typeof method === "string" && this !== defaultThis
|
||||
? this[method] : callback;
|
||||
var fn = nodebackForPromise(promise, multiArgs);
|
||||
try {
|
||||
cb.apply(_receiver, withAppended(arguments, fn));
|
||||
} catch(e) {
|
||||
promise._rejectCallback(maybeWrapAsError(e), true, true);
|
||||
}
|
||||
if (!promise._isFateSealed()) promise._setAsyncGuaranteed();
|
||||
return promise;
|
||||
}
|
||||
util.notEnumerableProp(promisified, "__isPromisified__", true);
|
||||
return promisified;
|
||||
}
|
||||
|
||||
var makeNodePromisified = canEvaluate
|
||||
? makeNodePromisifiedEval
|
||||
: makeNodePromisifiedClosure;
|
||||
|
||||
function promisifyAll(obj, suffix, filter, promisifier, multiArgs) {
|
||||
ASSERT(typeof suffix === "string");
|
||||
ASSERT(typeof filter === "function");
|
||||
var suffixRegexp = new RegExp(escapeIdentRegex(suffix) + "$");
|
||||
var methods =
|
||||
promisifiableMethods(obj, suffix, suffixRegexp, filter);
|
||||
|
||||
for (var i = 0, len = methods.length; i < len; i+= 2) {
|
||||
var key = methods[i];
|
||||
var fn = methods[i+1];
|
||||
var promisifiedKey = key + suffix;
|
||||
if (promisifier === makeNodePromisified) {
|
||||
obj[promisifiedKey] =
|
||||
makeNodePromisified(key, THIS, key, fn, suffix, multiArgs);
|
||||
} else {
|
||||
var promisified = promisifier(fn, function() {
|
||||
return makeNodePromisified(key, THIS, key,
|
||||
fn, suffix, multiArgs);
|
||||
});
|
||||
util.notEnumerableProp(promisified, "__isPromisified__", true);
|
||||
obj[promisifiedKey] = promisified;
|
||||
}
|
||||
}
|
||||
util.toFastProperties(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
function promisify(callback, receiver, multiArgs) {
|
||||
return makeNodePromisified(callback, receiver, undefined,
|
||||
callback, null, multiArgs);
|
||||
}
|
||||
|
||||
Promise.promisify = function (fn, options) {
|
||||
if (typeof fn !== "function") {
|
||||
throw new TypeError(FUNCTION_ERROR + util.classString(fn));
|
||||
}
|
||||
if (isPromisified(fn)) {
|
||||
return fn;
|
||||
}
|
||||
options = Object(options);
|
||||
var receiver = options.context === undefined ? THIS : options.context;
|
||||
var multiArgs = !!options.multiArgs;
|
||||
var ret = promisify(fn, receiver, multiArgs);
|
||||
util.copyDescriptors(fn, ret, propsFilter);
|
||||
return ret;
|
||||
};
|
||||
|
||||
Promise.promisifyAll = function (target, options) {
|
||||
if (typeof target !== "function" && typeof target !== "object") {
|
||||
throw new TypeError(PROMISIFY_TYPE_ERROR);
|
||||
}
|
||||
options = Object(options);
|
||||
var multiArgs = !!options.multiArgs;
|
||||
var suffix = options.suffix;
|
||||
if (typeof suffix !== "string") suffix = defaultSuffix;
|
||||
var filter = options.filter;
|
||||
if (typeof filter !== "function") filter = defaultFilter;
|
||||
var promisifier = options.promisifier;
|
||||
if (typeof promisifier !== "function") promisifier = makeNodePromisified;
|
||||
|
||||
if (!util.isIdentifier(suffix)) {
|
||||
throw new RangeError(SUFFIX_NOT_IDENTIFIER);
|
||||
}
|
||||
|
||||
var keys = util.inheritedDataKeys(target);
|
||||
for (var i = 0; i < keys.length; ++i) {
|
||||
var value = target[keys[i]];
|
||||
if (keys[i] !== "constructor" &&
|
||||
util.isClass(value)) {
|
||||
promisifyAll(value.prototype, suffix, filter, promisifier,
|
||||
multiArgs);
|
||||
promisifyAll(value, suffix, filter, promisifier, multiArgs);
|
||||
}
|
||||
}
|
||||
|
||||
return promisifyAll(target, suffix, filter, promisifier, multiArgs);
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
"use strict";
|
||||
module.exports = function(
|
||||
Promise, PromiseArray, tryConvertToPromise, apiRejection) {
|
||||
var ASSERT = require("./assert");
|
||||
var util = require("./util");
|
||||
var isObject = util.isObject;
|
||||
var es5 = require("./es5");
|
||||
var Es6Map;
|
||||
if (typeof Map === "function") Es6Map = Map;
|
||||
|
||||
var mapToEntries = (function() {
|
||||
var index = 0;
|
||||
var size = 0;
|
||||
|
||||
function extractEntry(value, key) {
|
||||
this[index] = value;
|
||||
this[index + size] = key;
|
||||
index++;
|
||||
}
|
||||
|
||||
return function mapToEntries(map) {
|
||||
size = map.size;
|
||||
index = 0;
|
||||
var ret = new Array(map.size * 2);
|
||||
map.forEach(extractEntry, ret);
|
||||
return ret;
|
||||
};
|
||||
})();
|
||||
|
||||
var entriesToMap = function(entries) {
|
||||
var ret = new Es6Map();
|
||||
var length = entries.length / 2 | 0;
|
||||
for (var i = 0; i < length; ++i) {
|
||||
var key = entries[length + i];
|
||||
var value = entries[i];
|
||||
ret.set(key, value);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
function PropertiesPromiseArray(obj) {
|
||||
var isMap = false;
|
||||
var entries;
|
||||
if (Es6Map !== undefined && obj instanceof Es6Map) {
|
||||
entries = mapToEntries(obj);
|
||||
isMap = true;
|
||||
} else {
|
||||
var keys = es5.keys(obj);
|
||||
var len = keys.length;
|
||||
entries = new Array(len * 2);
|
||||
for (var i = 0; i < len; ++i) {
|
||||
var key = keys[i];
|
||||
entries[i] = obj[key];
|
||||
entries[i + len] = key;
|
||||
}
|
||||
}
|
||||
this.constructor$(entries);
|
||||
this._isMap = isMap;
|
||||
this._init$(undefined, isMap ? RESOLVE_MAP : RESOLVE_OBJECT);
|
||||
}
|
||||
util.inherits(PropertiesPromiseArray, PromiseArray);
|
||||
|
||||
//Override
|
||||
PropertiesPromiseArray.prototype._init = function () {};
|
||||
|
||||
//Override
|
||||
PropertiesPromiseArray.prototype._promiseFulfilled = function (value, index) {
|
||||
ASSERT(!this._isResolved());
|
||||
ASSERT(!(value instanceof Promise));
|
||||
this._values[index] = value;
|
||||
var totalResolved = ++this._totalResolved;
|
||||
if (totalResolved >= this._length) {
|
||||
var val;
|
||||
if (this._isMap) {
|
||||
val = entriesToMap(this._values);
|
||||
} else {
|
||||
val = {};
|
||||
var keyOffset = this.length();
|
||||
for (var i = 0, len = this.length(); i < len; ++i) {
|
||||
val[this._values[i + keyOffset]] = this._values[i];
|
||||
}
|
||||
}
|
||||
this._resolve(val);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// Override
|
||||
PropertiesPromiseArray.prototype.shouldCopyValues = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
// Override
|
||||
PropertiesPromiseArray.prototype.getActualLength = function (len) {
|
||||
return len >> 1;
|
||||
};
|
||||
|
||||
function props(promises) {
|
||||
var ret;
|
||||
var castValue = tryConvertToPromise(promises);
|
||||
|
||||
if (!isObject(castValue)) {
|
||||
return apiRejection(PROPS_TYPE_ERROR);
|
||||
} else if (castValue instanceof Promise) {
|
||||
ret = castValue._then(
|
||||
Promise.props, undefined, undefined, undefined, undefined);
|
||||
} else {
|
||||
ret = new PropertiesPromiseArray(castValue).promise();
|
||||
}
|
||||
|
||||
if (castValue instanceof Promise) {
|
||||
ret._propagateFrom(castValue, PROPAGATE_BIND);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Promise.prototype.props = function () {
|
||||
return props(this);
|
||||
};
|
||||
|
||||
Promise.props = function (promises) {
|
||||
return props(promises);
|
||||
};
|
||||
};
|
|
@ -0,0 +1,79 @@
|
|||
"use strict";
|
||||
var ASSERT = require("./assert");
|
||||
function arrayMove(src, srcIndex, dst, dstIndex, len) {
|
||||
for (var j = 0; j < len; ++j) {
|
||||
dst[j + dstIndex] = src[j + srcIndex];
|
||||
src[j + srcIndex] = void 0;
|
||||
}
|
||||
}
|
||||
|
||||
function Queue(capacity) {
|
||||
this._capacity = capacity;
|
||||
this._length = 0;
|
||||
this._front = 0;
|
||||
}
|
||||
|
||||
Queue.prototype._willBeOverCapacity = function (size) {
|
||||
return this._capacity < size;
|
||||
};
|
||||
|
||||
Queue.prototype._pushOne = function (arg) {
|
||||
var length = this.length();
|
||||
this._checkCapacity(length + 1);
|
||||
var i = (this._front + length) & (this._capacity - 1);
|
||||
this[i] = arg;
|
||||
this._length = length + 1;
|
||||
};
|
||||
|
||||
Queue.prototype.push = function (fn, receiver, arg) {
|
||||
ASSERT(arguments.length === 3);
|
||||
ASSERT(typeof fn === "function");
|
||||
var length = this.length() + 3;
|
||||
if (this._willBeOverCapacity(length)) {
|
||||
//The fast array copies expect the
|
||||
//underlying array to be filled completely
|
||||
this._pushOne(fn);
|
||||
this._pushOne(receiver);
|
||||
this._pushOne(arg);
|
||||
return;
|
||||
}
|
||||
var j = this._front + length - 3;
|
||||
this._checkCapacity(length);
|
||||
var wrapMask = this._capacity - 1;
|
||||
this[(j + 0) & wrapMask] = fn;
|
||||
this[(j + 1) & wrapMask] = receiver;
|
||||
this[(j + 2) & wrapMask] = arg;
|
||||
this._length = length;
|
||||
};
|
||||
|
||||
Queue.prototype.shift = function () {
|
||||
ASSERT(this.length() > 0);
|
||||
var front = this._front,
|
||||
ret = this[front];
|
||||
|
||||
this[front] = undefined;
|
||||
this._front = (front + 1) & (this._capacity - 1);
|
||||
this._length--;
|
||||
return ret;
|
||||
};
|
||||
|
||||
Queue.prototype.length = function () {
|
||||
return this._length;
|
||||
};
|
||||
|
||||
Queue.prototype._checkCapacity = function (size) {
|
||||
if (this._capacity < size) {
|
||||
this._resizeTo(this._capacity << 1);
|
||||
}
|
||||
};
|
||||
|
||||
Queue.prototype._resizeTo = function (capacity) {
|
||||
var oldCapacity = this._capacity;
|
||||
this._capacity = capacity;
|
||||
var front = this._front;
|
||||
var length = this._length;
|
||||
var moveItemsCount = (front + length) & (oldCapacity - 1);
|
||||
arrayMove(this, 0, this, oldCapacity, moveItemsCount);
|
||||
};
|
||||
|
||||
module.exports = Queue;
|
|
@ -0,0 +1,50 @@
|
|||
"use strict";
|
||||
module.exports = function(
|
||||
Promise, INTERNAL, tryConvertToPromise, apiRejection) {
|
||||
var util = require("./util");
|
||||
|
||||
var raceLater = function (promise) {
|
||||
return promise.then(function(array) {
|
||||
return race(array, promise);
|
||||
});
|
||||
};
|
||||
|
||||
function race(promises, parent) {
|
||||
var maybePromise = tryConvertToPromise(promises);
|
||||
|
||||
if (maybePromise instanceof Promise) {
|
||||
return raceLater(maybePromise);
|
||||
} else {
|
||||
promises = util.asArray(promises);
|
||||
if (promises === null)
|
||||
return apiRejection(COLLECTION_ERROR + util.classString(promises));
|
||||
}
|
||||
|
||||
var ret = new Promise(INTERNAL);
|
||||
if (parent !== undefined) {
|
||||
ret._propagateFrom(parent, PROPAGATE_ALL);
|
||||
}
|
||||
var fulfill = ret._fulfill;
|
||||
var reject = ret._reject;
|
||||
for (var i = 0, len = promises.length; i < len; ++i) {
|
||||
var val = promises[i];
|
||||
|
||||
if (val === undefined && !(i in promises)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Promise.cast(val)._then(fulfill, reject, undefined, ret, null);
|
||||
}
|
||||
//Yes, if promises were empty, it will be forever pending :-)
|
||||
return ret;
|
||||
}
|
||||
|
||||
Promise.race = function (promises) {
|
||||
return race(promises, undefined);
|
||||
};
|
||||
|
||||
Promise.prototype.race = function () {
|
||||
return race(this, undefined);
|
||||
};
|
||||
|
||||
};
|
|
@ -0,0 +1,191 @@
|
|||
"use strict";
|
||||
module.exports = function(Promise,
|
||||
PromiseArray,
|
||||
apiRejection,
|
||||
tryConvertToPromise,
|
||||
INTERNAL,
|
||||
debug) {
|
||||
var util = require("./util");
|
||||
var tryCatch = util.tryCatch;
|
||||
|
||||
function ReductionPromiseArray(promises, fn, initialValue, _each) {
|
||||
this.constructor$(promises);
|
||||
var context = Promise._getContext();
|
||||
this._fn = util.contextBind(context, fn);
|
||||
if (initialValue !== undefined) {
|
||||
initialValue = Promise.resolve(initialValue);
|
||||
initialValue._attachCancellationCallback(this);
|
||||
}
|
||||
this._initialValue = initialValue;
|
||||
this._currentCancellable = null;
|
||||
if(_each === INTERNAL) {
|
||||
this._eachValues = Array(this._length);
|
||||
} else if (_each === 0) {
|
||||
this._eachValues = null;
|
||||
} else {
|
||||
this._eachValues = undefined;
|
||||
}
|
||||
this._promise._captureStackTrace();
|
||||
this._init$(undefined, RESOLVE_CALL_METHOD);
|
||||
}
|
||||
util.inherits(ReductionPromiseArray, PromiseArray);
|
||||
|
||||
ReductionPromiseArray.prototype._gotAccum = function(accum) {
|
||||
if (this._eachValues !== undefined &&
|
||||
this._eachValues !== null &&
|
||||
accum !== INTERNAL) {
|
||||
this._eachValues.push(accum);
|
||||
}
|
||||
};
|
||||
|
||||
ReductionPromiseArray.prototype._eachComplete = function(value) {
|
||||
if (this._eachValues !== null) {
|
||||
this._eachValues.push(value);
|
||||
}
|
||||
return this._eachValues;
|
||||
};
|
||||
|
||||
// Override
|
||||
ReductionPromiseArray.prototype._init = function() {};
|
||||
|
||||
// Override
|
||||
ReductionPromiseArray.prototype._resolveEmptyArray = function() {
|
||||
this._resolve(this._eachValues !== undefined ? this._eachValues
|
||||
: this._initialValue);
|
||||
};
|
||||
|
||||
// Override
|
||||
ReductionPromiseArray.prototype.shouldCopyValues = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
// Override
|
||||
ReductionPromiseArray.prototype._resolve = function(value) {
|
||||
this._promise._resolveCallback(value);
|
||||
this._values = null;
|
||||
};
|
||||
|
||||
// Override
|
||||
ReductionPromiseArray.prototype._resultCancelled = function(sender) {
|
||||
if (sender === this._initialValue) return this._cancel();
|
||||
if (this._isResolved()) return;
|
||||
this._resultCancelled$();
|
||||
if (this._currentCancellable instanceof Promise) {
|
||||
this._currentCancellable.cancel();
|
||||
}
|
||||
if (this._initialValue instanceof Promise) {
|
||||
this._initialValue.cancel();
|
||||
}
|
||||
};
|
||||
|
||||
// Override
|
||||
ReductionPromiseArray.prototype._iterate = function (values) {
|
||||
this._values = values;
|
||||
var value;
|
||||
var i;
|
||||
var length = values.length;
|
||||
if (this._initialValue !== undefined) {
|
||||
value = this._initialValue;
|
||||
i = 0;
|
||||
} else {
|
||||
value = Promise.resolve(values[0]);
|
||||
i = 1;
|
||||
}
|
||||
|
||||
this._currentCancellable = value;
|
||||
|
||||
for (var j = i; j < length; ++j) {
|
||||
var maybePromise = values[j];
|
||||
if (maybePromise instanceof Promise) {
|
||||
maybePromise.suppressUnhandledRejections();
|
||||
}
|
||||
}
|
||||
|
||||
if (!value.isRejected()) {
|
||||
for (; i < length; ++i) {
|
||||
var ctx = {
|
||||
accum: null,
|
||||
value: values[i],
|
||||
index: i,
|
||||
length: length,
|
||||
array: this
|
||||
};
|
||||
|
||||
value = value._then(gotAccum, undefined, undefined, ctx, undefined);
|
||||
|
||||
// Too many promises chained with asyncGuaranteed will result in
|
||||
// stack overflow. Break up long chains to reset stack.
|
||||
if ((i & 127) === 0) {
|
||||
value._setNoAsyncGuarantee();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this._eachValues !== undefined) {
|
||||
value = value
|
||||
._then(this._eachComplete, undefined, undefined, this, undefined);
|
||||
}
|
||||
value._then(completed, completed, undefined, value, this);
|
||||
};
|
||||
|
||||
Promise.prototype.reduce = function (fn, initialValue) {
|
||||
return reduce(this, fn, initialValue, null);
|
||||
};
|
||||
|
||||
Promise.reduce = function (promises, fn, initialValue, _each) {
|
||||
return reduce(promises, fn, initialValue, _each);
|
||||
};
|
||||
|
||||
function completed(valueOrReason, array) {
|
||||
if (this.isFulfilled()) {
|
||||
array._resolve(valueOrReason);
|
||||
} else {
|
||||
array._reject(valueOrReason);
|
||||
}
|
||||
}
|
||||
|
||||
function reduce(promises, fn, initialValue, _each) {
|
||||
if (typeof fn !== "function") {
|
||||
return apiRejection(FUNCTION_ERROR + util.classString(fn));
|
||||
}
|
||||
var array = new ReductionPromiseArray(promises, fn, initialValue, _each);
|
||||
return array.promise();
|
||||
}
|
||||
|
||||
function gotAccum(accum) {
|
||||
this.accum = accum;
|
||||
this.array._gotAccum(accum);
|
||||
var value = tryConvertToPromise(this.value, this.array._promise);
|
||||
if (value instanceof Promise) {
|
||||
this.array._currentCancellable = value;
|
||||
return value._then(gotValue, undefined, undefined, this, undefined);
|
||||
} else {
|
||||
return gotValue.call(this, value);
|
||||
}
|
||||
}
|
||||
|
||||
function gotValue(value) {
|
||||
var array = this.array;
|
||||
var promise = array._promise;
|
||||
var fn = tryCatch(array._fn);
|
||||
promise._pushContext();
|
||||
var ret;
|
||||
if (array._eachValues !== undefined) {
|
||||
ret = fn.call(promise._boundValue(), value, this.index, this.length);
|
||||
} else {
|
||||
ret = fn.call(promise._boundValue(),
|
||||
this.accum, value, this.index, this.length);
|
||||
}
|
||||
if (ret instanceof Promise) {
|
||||
array._currentCancellable = ret;
|
||||
}
|
||||
var promiseCreated = promise._popContext();
|
||||
debug.checkForgottenReturns(
|
||||
ret,
|
||||
promiseCreated,
|
||||
array._eachValues !== undefined ? "Promise.each" : "Promise.reduce",
|
||||
promise
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
};
|
|
@ -0,0 +1,79 @@
|
|||
"use strict";
|
||||
var util = require("./util");
|
||||
var schedule;
|
||||
var noAsyncScheduler = function() {
|
||||
throw new Error(NO_ASYNC_SCHEDULER);
|
||||
};
|
||||
var NativePromise = util.getNativePromise();
|
||||
// This file figures out which scheduler to use for Bluebird. It normalizes
|
||||
// async task scheduling across target platforms. Note that not all JS target
|
||||
// platforms come supported. The scheduler is overridable with `setScheduler`.
|
||||
|
||||
// Our scheduler for Node.js/io.js is setImmediate for recent
|
||||
// versions of node because of macrotask semantics.
|
||||
// The `typeof` check is for an edge case with nw.js.
|
||||
if (util.isNode && typeof MutationObserver === "undefined") {
|
||||
var GlobalSetImmediate = global.setImmediate;
|
||||
var ProcessNextTick = process.nextTick;
|
||||
schedule = util.isRecentNode
|
||||
? function(fn) { GlobalSetImmediate.call(global, fn); }
|
||||
: function(fn) { ProcessNextTick.call(process, fn); };
|
||||
} else if (typeof NativePromise === "function" &&
|
||||
typeof NativePromise.resolve === "function") {
|
||||
var nativePromise = NativePromise.resolve();
|
||||
schedule = function(fn) {
|
||||
nativePromise.then(fn);
|
||||
};
|
||||
// Outside of Node, we're using MutationObservers because they provide low
|
||||
// latency. The second check is to guard against iOS standalone apps which
|
||||
// do not fire DOM mutation events for some reason on iOS 8.3+ and cordova
|
||||
// apps which have the same bug but are not `.navigator.standalone`
|
||||
} else if ((typeof MutationObserver !== "undefined") &&
|
||||
!(typeof window !== "undefined" &&
|
||||
window.navigator &&
|
||||
(window.navigator.standalone || window.cordova)) &&
|
||||
("classList" in document.documentElement)) {
|
||||
schedule = (function() {
|
||||
// Using 2 mutation observers to batch multiple updates into one.
|
||||
var div = document.createElement("div");
|
||||
var opts = {attributes: true};
|
||||
var toggleScheduled = false;
|
||||
var div2 = document.createElement("div");
|
||||
var o2 = new MutationObserver(function() {
|
||||
div.classList.toggle("foo");
|
||||
toggleScheduled = false;
|
||||
});
|
||||
o2.observe(div2, opts);
|
||||
|
||||
var scheduleToggle = function() {
|
||||
if (toggleScheduled) return;
|
||||
toggleScheduled = true;
|
||||
div2.classList.toggle("foo");
|
||||
};
|
||||
|
||||
return function schedule(fn) {
|
||||
var o = new MutationObserver(function() {
|
||||
o.disconnect();
|
||||
fn();
|
||||
});
|
||||
o.observe(div, opts);
|
||||
scheduleToggle();
|
||||
};
|
||||
})();
|
||||
// setImmediate has higher latency but is still pretty good. This is useful for
|
||||
// cases where MutationObserver is not defined (older IE, for example).
|
||||
} else if (typeof setImmediate !== "undefined") {
|
||||
schedule = function (fn) {
|
||||
setImmediate(fn);
|
||||
};
|
||||
// setTimeout also works, it has the most latency but it does the trick.
|
||||
} else if (typeof setTimeout !== "undefined") {
|
||||
schedule = function (fn) {
|
||||
setTimeout(fn, 0);
|
||||
};
|
||||
} else {
|
||||
// Do __Not__ default to a sync scheduler, that would break Promises/A+
|
||||
// compliancy and cause race conditions.
|
||||
schedule = noAsyncScheduler;
|
||||
}
|
||||
module.exports = schedule;
|
|
@ -0,0 +1,55 @@
|
|||
"use strict";
|
||||
module.exports =
|
||||
function(Promise, PromiseArray, debug) {
|
||||
var ASSERT = require("./assert");
|
||||
var PromiseInspection = Promise.PromiseInspection;
|
||||
var util = require("./util");
|
||||
|
||||
function SettledPromiseArray(values) {
|
||||
this.constructor$(values);
|
||||
}
|
||||
util.inherits(SettledPromiseArray, PromiseArray);
|
||||
|
||||
SettledPromiseArray.prototype._promiseResolved = function (index, inspection) {
|
||||
ASSERT(typeof index === "number");
|
||||
this._values[index] = inspection;
|
||||
var totalResolved = ++this._totalResolved;
|
||||
if (totalResolved >= this._length) {
|
||||
this._resolve(this._values);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
//override
|
||||
SettledPromiseArray.prototype._promiseFulfilled = function (value, index) {
|
||||
ASSERT(!this._isResolved());
|
||||
ASSERT(typeof index === "number");
|
||||
var ret = new PromiseInspection();
|
||||
ret._bitField = IS_FULFILLED;
|
||||
ret._settledValueField = value;
|
||||
return this._promiseResolved(index, ret);
|
||||
};
|
||||
//override
|
||||
SettledPromiseArray.prototype._promiseRejected = function (reason, index) {
|
||||
ASSERT(!this._isResolved());
|
||||
ASSERT(typeof index === "number");
|
||||
var ret = new PromiseInspection();
|
||||
ret._bitField = IS_REJECTED;
|
||||
ret._settledValueField = reason;
|
||||
return this._promiseResolved(index, ret);
|
||||
};
|
||||
|
||||
Promise.settle = function (promises) {
|
||||
debug.deprecated(".settle()", ".reflect()");
|
||||
return new SettledPromiseArray(promises).promise();
|
||||
};
|
||||
|
||||
Promise.allSettled = function (promises) {
|
||||
return new SettledPromiseArray(promises).promise();
|
||||
};
|
||||
|
||||
Promise.prototype.settle = function () {
|
||||
return Promise.settle(this);
|
||||
};
|
||||
};
|
|
@ -0,0 +1,159 @@
|
|||
"use strict";
|
||||
module.exports =
|
||||
function(Promise, PromiseArray, apiRejection) {
|
||||
var ASSERT = require("./assert");
|
||||
var util = require("./util");
|
||||
var RangeError = require("./errors").RangeError;
|
||||
var AggregateError = require("./errors").AggregateError;
|
||||
var isArray = util.isArray;
|
||||
var CANCELLATION = {};
|
||||
|
||||
|
||||
function SomePromiseArray(values) {
|
||||
this.constructor$(values);
|
||||
this._howMany = 0;
|
||||
this._unwrap = false;
|
||||
this._initialized = false;
|
||||
}
|
||||
util.inherits(SomePromiseArray, PromiseArray);
|
||||
|
||||
SomePromiseArray.prototype._init = function () {
|
||||
if (!this._initialized) {
|
||||
return;
|
||||
}
|
||||
if (this._howMany === 0) {
|
||||
this._resolve([]);
|
||||
return;
|
||||
}
|
||||
this._init$(undefined, RESOLVE_CALL_METHOD);
|
||||
var isArrayResolved = isArray(this._values);
|
||||
if (!this._isResolved() &&
|
||||
isArrayResolved &&
|
||||
this._howMany > this._canPossiblyFulfill()) {
|
||||
this._reject(this._getRangeError(this.length()));
|
||||
}
|
||||
};
|
||||
|
||||
SomePromiseArray.prototype.init = function () {
|
||||
this._initialized = true;
|
||||
this._init();
|
||||
};
|
||||
|
||||
SomePromiseArray.prototype.setUnwrap = function () {
|
||||
this._unwrap = true;
|
||||
};
|
||||
|
||||
SomePromiseArray.prototype.howMany = function () {
|
||||
return this._howMany;
|
||||
};
|
||||
|
||||
SomePromiseArray.prototype.setHowMany = function (count) {
|
||||
ASSERT(!this._isResolved());
|
||||
this._howMany = count;
|
||||
};
|
||||
|
||||
//override
|
||||
SomePromiseArray.prototype._promiseFulfilled = function (value) {
|
||||
ASSERT(!this._isResolved());
|
||||
this._addFulfilled(value);
|
||||
if (this._fulfilled() === this.howMany()) {
|
||||
this._values.length = this.howMany();
|
||||
if (this.howMany() === 1 && this._unwrap) {
|
||||
this._resolve(this._values[0]);
|
||||
} else {
|
||||
this._resolve(this._values);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
};
|
||||
//override
|
||||
SomePromiseArray.prototype._promiseRejected = function (reason) {
|
||||
ASSERT(!this._isResolved());
|
||||
this._addRejected(reason);
|
||||
return this._checkOutcome();
|
||||
};
|
||||
|
||||
//override
|
||||
SomePromiseArray.prototype._promiseCancelled = function () {
|
||||
if (this._values instanceof Promise || this._values == null) {
|
||||
return this._cancel();
|
||||
}
|
||||
ASSERT(!this._isResolved());
|
||||
this._addRejected(CANCELLATION);
|
||||
return this._checkOutcome();
|
||||
};
|
||||
|
||||
SomePromiseArray.prototype._checkOutcome = function() {
|
||||
if (this.howMany() > this._canPossiblyFulfill()) {
|
||||
var e = new AggregateError();
|
||||
for (var i = this.length(); i < this._values.length; ++i) {
|
||||
if (this._values[i] !== CANCELLATION) {
|
||||
e.push(this._values[i]);
|
||||
}
|
||||
}
|
||||
if (e.length > 0) {
|
||||
this._reject(e);
|
||||
} else {
|
||||
this._cancel();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
SomePromiseArray.prototype._fulfilled = function () {
|
||||
return this._totalResolved;
|
||||
};
|
||||
|
||||
SomePromiseArray.prototype._rejected = function () {
|
||||
return this._values.length - this.length();
|
||||
};
|
||||
|
||||
//Use the same array past .length() to store rejection reasons
|
||||
SomePromiseArray.prototype._addRejected = function (reason) {
|
||||
this._values.push(reason);
|
||||
};
|
||||
|
||||
SomePromiseArray.prototype._addFulfilled = function (value) {
|
||||
this._values[this._totalResolved++] = value;
|
||||
};
|
||||
|
||||
SomePromiseArray.prototype._canPossiblyFulfill = function () {
|
||||
return this.length() - this._rejected();
|
||||
};
|
||||
|
||||
SomePromiseArray.prototype._getRangeError = function (count) {
|
||||
var message = "Input array must contain at least " +
|
||||
this._howMany + " items but contains only " + count + " items";
|
||||
return new RangeError(message);
|
||||
};
|
||||
|
||||
SomePromiseArray.prototype._resolveEmptyArray = function () {
|
||||
this._reject(this._getRangeError(0));
|
||||
};
|
||||
|
||||
function some(promises, howMany) {
|
||||
if ((howMany | 0) !== howMany || howMany < 0) {
|
||||
return apiRejection(POSITIVE_INTEGER_ERROR);
|
||||
}
|
||||
var ret = new SomePromiseArray(promises);
|
||||
var promise = ret.promise();
|
||||
ASSERT(promise.isPending());
|
||||
ASSERT(ret instanceof SomePromiseArray);
|
||||
ret.setHowMany(howMany);
|
||||
ret.init();
|
||||
return promise;
|
||||
}
|
||||
|
||||
Promise.some = function (promises, howMany) {
|
||||
return some(promises, howMany);
|
||||
};
|
||||
|
||||
Promise.prototype.some = function (howMany) {
|
||||
return some(this, howMany);
|
||||
};
|
||||
|
||||
Promise._SomePromiseArray = SomePromiseArray;
|
||||
};
|
|
@ -0,0 +1,103 @@
|
|||
"use strict";
|
||||
module.exports = function(Promise) {
|
||||
function PromiseInspection(promise) {
|
||||
if (promise !== undefined) {
|
||||
promise = promise._target();
|
||||
this._bitField = promise._bitField;
|
||||
this._settledValueField = promise._isFateSealed()
|
||||
? promise._settledValue() : undefined;
|
||||
}
|
||||
else {
|
||||
this._bitField = 0;
|
||||
this._settledValueField = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
PromiseInspection.prototype._settledValue = function() {
|
||||
return this._settledValueField;
|
||||
};
|
||||
|
||||
var value = PromiseInspection.prototype.value = function () {
|
||||
if (!this.isFulfilled()) {
|
||||
throw new TypeError(INSPECTION_VALUE_ERROR);
|
||||
}
|
||||
return this._settledValue();
|
||||
};
|
||||
|
||||
var reason = PromiseInspection.prototype.error =
|
||||
PromiseInspection.prototype.reason = function () {
|
||||
if (!this.isRejected()) {
|
||||
throw new TypeError(INSPECTION_REASON_ERROR);
|
||||
}
|
||||
return this._settledValue();
|
||||
};
|
||||
|
||||
var isFulfilled = PromiseInspection.prototype.isFulfilled = function() {
|
||||
return (this._bitField & IS_FULFILLED) !== 0;
|
||||
};
|
||||
|
||||
var isRejected = PromiseInspection.prototype.isRejected = function () {
|
||||
return (this._bitField & IS_REJECTED) !== 0;
|
||||
};
|
||||
|
||||
var isPending = PromiseInspection.prototype.isPending = function () {
|
||||
return (this._bitField & IS_REJECTED_OR_FULFILLED_OR_CANCELLED) === 0;
|
||||
};
|
||||
|
||||
var isResolved = PromiseInspection.prototype.isResolved = function () {
|
||||
return (this._bitField & IS_REJECTED_OR_FULFILLED) !== 0;
|
||||
};
|
||||
|
||||
PromiseInspection.prototype.isCancelled = function() {
|
||||
return (this._bitField & IS_CANCELLED_OR_WILL_BE_CANCELLED) !== 0;
|
||||
};
|
||||
|
||||
Promise.prototype.__isCancelled = function() {
|
||||
return (this._bitField & IS_CANCELLED) === IS_CANCELLED;
|
||||
};
|
||||
|
||||
Promise.prototype._isCancelled = function() {
|
||||
return this._target().__isCancelled();
|
||||
};
|
||||
|
||||
Promise.prototype.isCancelled = function() {
|
||||
return (this._target()._bitField & IS_CANCELLED_OR_WILL_BE_CANCELLED) !== 0;
|
||||
};
|
||||
|
||||
Promise.prototype.isPending = function() {
|
||||
return isPending.call(this._target());
|
||||
};
|
||||
|
||||
Promise.prototype.isRejected = function() {
|
||||
return isRejected.call(this._target());
|
||||
};
|
||||
|
||||
Promise.prototype.isFulfilled = function() {
|
||||
return isFulfilled.call(this._target());
|
||||
};
|
||||
|
||||
Promise.prototype.isResolved = function() {
|
||||
return isResolved.call(this._target());
|
||||
};
|
||||
|
||||
Promise.prototype.value = function() {
|
||||
return value.call(this._target());
|
||||
};
|
||||
|
||||
Promise.prototype.reason = function() {
|
||||
var target = this._target();
|
||||
target._unsetRejectionIsUnhandled();
|
||||
return reason.call(target);
|
||||
};
|
||||
|
||||
Promise.prototype._value = function() {
|
||||
return this._settledValue();
|
||||
};
|
||||
|
||||
Promise.prototype._reason = function() {
|
||||
this._unsetRejectionIsUnhandled();
|
||||
return this._settledValue();
|
||||
};
|
||||
|
||||
Promise.PromiseInspection = PromiseInspection;
|
||||
};
|
|
@ -0,0 +1,89 @@
|
|||
"use strict";
|
||||
module.exports = function(Promise, INTERNAL) {
|
||||
var ASSERT = require("./assert");
|
||||
var util = require("./util");
|
||||
var errorObj = util.errorObj;
|
||||
var isObject = util.isObject;
|
||||
|
||||
function tryConvertToPromise(obj, context) {
|
||||
if (isObject(obj)) {
|
||||
if (obj instanceof Promise) return obj;
|
||||
var then = getThen(obj);
|
||||
if (then === errorObj) {
|
||||
if (context) context._pushContext();
|
||||
var ret = Promise.reject(then.e);
|
||||
if (context) context._popContext();
|
||||
return ret;
|
||||
} else if (typeof then === "function") {
|
||||
//Make casting from another bluebird fast
|
||||
if (isAnyBluebirdPromise(obj)) {
|
||||
var ret = new Promise(INTERNAL);
|
||||
obj._then(
|
||||
ret._fulfill,
|
||||
ret._reject,
|
||||
undefined,
|
||||
ret,
|
||||
null
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
return doThenable(obj, then, context);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
function doGetThen(obj) {
|
||||
return obj.then;
|
||||
}
|
||||
|
||||
function getThen(obj) {
|
||||
try {
|
||||
return doGetThen(obj);
|
||||
} catch (e) {
|
||||
errorObj.e = e;
|
||||
return errorObj;
|
||||
}
|
||||
}
|
||||
|
||||
var hasProp = {}.hasOwnProperty;
|
||||
function isAnyBluebirdPromise(obj) {
|
||||
try {
|
||||
return hasProp.call(obj, "_promise0");
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function doThenable(x, then, context) {
|
||||
ASSERT(typeof then === "function");
|
||||
var promise = new Promise(INTERNAL);
|
||||
var ret = promise;
|
||||
if (context) context._pushContext();
|
||||
promise._captureStackTrace();
|
||||
if (context) context._popContext();
|
||||
var synchronous = true;
|
||||
var result = util.tryCatch(then).call(x, resolve, reject);
|
||||
synchronous = false;
|
||||
|
||||
if (promise && result === errorObj) {
|
||||
promise._rejectCallback(result.e, true, true);
|
||||
promise = null;
|
||||
}
|
||||
|
||||
function resolve(value) {
|
||||
if (!promise) return;
|
||||
promise._resolveCallback(value);
|
||||
promise = null;
|
||||
}
|
||||
|
||||
function reject(reason) {
|
||||
if (!promise) return;
|
||||
promise._rejectCallback(reason, synchronous, true);
|
||||
promise = null;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
return tryConvertToPromise;
|
||||
};
|
|
@ -0,0 +1,93 @@
|
|||
"use strict";
|
||||
module.exports = function(Promise, INTERNAL, debug) {
|
||||
var util = require("./util");
|
||||
var TimeoutError = Promise.TimeoutError;
|
||||
|
||||
function HandleWrapper(handle) {
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
HandleWrapper.prototype._resultCancelled = function() {
|
||||
clearTimeout(this.handle);
|
||||
};
|
||||
|
||||
var afterValue = function(value) { return delay(+this).thenReturn(value); };
|
||||
var delay = Promise.delay = function (ms, value) {
|
||||
var ret;
|
||||
var handle;
|
||||
if (value !== undefined) {
|
||||
ret = Promise.resolve(value)
|
||||
._then(afterValue, null, null, ms, undefined);
|
||||
if (debug.cancellation() && value instanceof Promise) {
|
||||
ret._setOnCancel(value);
|
||||
}
|
||||
} else {
|
||||
ret = new Promise(INTERNAL);
|
||||
handle = setTimeout(function() { ret._fulfill(); }, +ms);
|
||||
if (debug.cancellation()) {
|
||||
ret._setOnCancel(new HandleWrapper(handle));
|
||||
}
|
||||
ret._captureStackTrace();
|
||||
}
|
||||
ret._setAsyncGuaranteed();
|
||||
return ret;
|
||||
};
|
||||
|
||||
Promise.prototype.delay = function (ms) {
|
||||
return delay(ms, this);
|
||||
};
|
||||
|
||||
var afterTimeout = function (promise, message, parent) {
|
||||
var err;
|
||||
if (typeof message !== "string") {
|
||||
if (message instanceof Error) {
|
||||
err = message;
|
||||
} else {
|
||||
err = new TimeoutError(TIMEOUT_ERROR);
|
||||
}
|
||||
} else {
|
||||
err = new TimeoutError(message);
|
||||
}
|
||||
util.markAsOriginatingFromRejection(err);
|
||||
promise._attachExtraTrace(err);
|
||||
promise._reject(err);
|
||||
|
||||
if (parent != null) {
|
||||
parent.cancel();
|
||||
}
|
||||
};
|
||||
|
||||
function successClear(value) {
|
||||
clearTimeout(this.handle);
|
||||
return value;
|
||||
}
|
||||
|
||||
function failureClear(reason) {
|
||||
clearTimeout(this.handle);
|
||||
throw reason;
|
||||
}
|
||||
|
||||
Promise.prototype.timeout = function (ms, message) {
|
||||
ms = +ms;
|
||||
var ret, parent;
|
||||
|
||||
var handleWrapper = new HandleWrapper(setTimeout(function timeoutTimeout() {
|
||||
if (ret.isPending()) {
|
||||
afterTimeout(ret, message, parent);
|
||||
}
|
||||
}, ms));
|
||||
|
||||
if (debug.cancellation()) {
|
||||
parent = this.then();
|
||||
ret = parent._then(successClear, failureClear,
|
||||
undefined, handleWrapper, undefined);
|
||||
ret._setOnCancel(handleWrapper);
|
||||
} else {
|
||||
ret = this._then(successClear, failureClear,
|
||||
undefined, handleWrapper, undefined);
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
};
|
|
@ -0,0 +1,226 @@
|
|||
"use strict";
|
||||
module.exports = function (Promise, apiRejection, tryConvertToPromise,
|
||||
createContext, INTERNAL, debug) {
|
||||
var util = require("./util");
|
||||
var TypeError = require("./errors").TypeError;
|
||||
var inherits = require("./util").inherits;
|
||||
var errorObj = util.errorObj;
|
||||
var tryCatch = util.tryCatch;
|
||||
var NULL = {};
|
||||
|
||||
function thrower(e) {
|
||||
setTimeout(function(){throw e;}, 0);
|
||||
}
|
||||
|
||||
function castPreservingDisposable(thenable) {
|
||||
var maybePromise = tryConvertToPromise(thenable);
|
||||
if (maybePromise !== thenable &&
|
||||
typeof thenable._isDisposable === "function" &&
|
||||
typeof thenable._getDisposer === "function" &&
|
||||
thenable._isDisposable()) {
|
||||
maybePromise._setDisposable(thenable._getDisposer());
|
||||
}
|
||||
return maybePromise;
|
||||
}
|
||||
function dispose(resources, inspection) {
|
||||
var i = 0;
|
||||
var len = resources.length;
|
||||
var ret = new Promise(INTERNAL);
|
||||
function iterator() {
|
||||
if (i >= len) return ret._fulfill();
|
||||
var maybePromise = castPreservingDisposable(resources[i++]);
|
||||
if (maybePromise instanceof Promise &&
|
||||
maybePromise._isDisposable()) {
|
||||
try {
|
||||
maybePromise = tryConvertToPromise(
|
||||
maybePromise._getDisposer().tryDispose(inspection),
|
||||
resources.promise);
|
||||
} catch (e) {
|
||||
return thrower(e);
|
||||
}
|
||||
if (maybePromise instanceof Promise) {
|
||||
return maybePromise._then(iterator, thrower,
|
||||
null, null, null);
|
||||
}
|
||||
}
|
||||
iterator();
|
||||
}
|
||||
iterator();
|
||||
return ret;
|
||||
}
|
||||
|
||||
function Disposer(data, promise, context) {
|
||||
this._data = data;
|
||||
this._promise = promise;
|
||||
this._context = context;
|
||||
}
|
||||
|
||||
Disposer.prototype.data = function () {
|
||||
return this._data;
|
||||
};
|
||||
|
||||
Disposer.prototype.promise = function () {
|
||||
return this._promise;
|
||||
};
|
||||
|
||||
Disposer.prototype.resource = function () {
|
||||
if (this.promise().isFulfilled()) {
|
||||
return this.promise().value();
|
||||
}
|
||||
return NULL;
|
||||
};
|
||||
|
||||
Disposer.prototype.tryDispose = function(inspection) {
|
||||
var resource = this.resource();
|
||||
var context = this._context;
|
||||
if (context !== undefined) context._pushContext();
|
||||
var ret = resource !== NULL
|
||||
? this.doDispose(resource, inspection) : null;
|
||||
if (context !== undefined) context._popContext();
|
||||
this._promise._unsetDisposable();
|
||||
this._data = null;
|
||||
return ret;
|
||||
};
|
||||
|
||||
Disposer.isDisposer = function (d) {
|
||||
return (d != null &&
|
||||
typeof d.resource === "function" &&
|
||||
typeof d.tryDispose === "function");
|
||||
};
|
||||
|
||||
function FunctionDisposer(fn, promise, context) {
|
||||
this.constructor$(fn, promise, context);
|
||||
}
|
||||
inherits(FunctionDisposer, Disposer);
|
||||
|
||||
FunctionDisposer.prototype.doDispose = function (resource, inspection) {
|
||||
var fn = this.data();
|
||||
return fn.call(resource, resource, inspection);
|
||||
};
|
||||
|
||||
function maybeUnwrapDisposer(value) {
|
||||
if (Disposer.isDisposer(value)) {
|
||||
this.resources[this.index]._setDisposable(value);
|
||||
return value.promise();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function ResourceList(length) {
|
||||
this.length = length;
|
||||
this.promise = null;
|
||||
this[length-1] = null;
|
||||
}
|
||||
|
||||
ResourceList.prototype._resultCancelled = function() {
|
||||
var len = this.length;
|
||||
for (var i = 0; i < len; ++i) {
|
||||
var item = this[i];
|
||||
if (item instanceof Promise) {
|
||||
item.cancel();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Promise.using = function () {
|
||||
var len = arguments.length;
|
||||
if (len < 2) return apiRejection(
|
||||
"you must pass at least 2 arguments to Promise.using");
|
||||
var fn = arguments[len - 1];
|
||||
if (typeof fn !== "function") {
|
||||
return apiRejection(FUNCTION_ERROR + util.classString(fn));
|
||||
}
|
||||
var input;
|
||||
var spreadArgs = true;
|
||||
if (len === 2 && Array.isArray(arguments[0])) {
|
||||
input = arguments[0];
|
||||
len = input.length;
|
||||
spreadArgs = false;
|
||||
} else {
|
||||
input = arguments;
|
||||
len--;
|
||||
}
|
||||
var resources = new ResourceList(len);
|
||||
for (var i = 0; i < len; ++i) {
|
||||
var resource = input[i];
|
||||
if (Disposer.isDisposer(resource)) {
|
||||
var disposer = resource;
|
||||
resource = resource.promise();
|
||||
resource._setDisposable(disposer);
|
||||
} else {
|
||||
var maybePromise = tryConvertToPromise(resource);
|
||||
if (maybePromise instanceof Promise) {
|
||||
resource =
|
||||
maybePromise._then(maybeUnwrapDisposer, null, null, {
|
||||
resources: resources,
|
||||
index: i
|
||||
}, undefined);
|
||||
}
|
||||
}
|
||||
resources[i] = resource;
|
||||
}
|
||||
|
||||
var reflectedResources = new Array(resources.length);
|
||||
for (var i = 0; i < reflectedResources.length; ++i) {
|
||||
reflectedResources[i] = Promise.resolve(resources[i]).reflect();
|
||||
}
|
||||
|
||||
var resultPromise = Promise.all(reflectedResources)
|
||||
.then(function(inspections) {
|
||||
for (var i = 0; i < inspections.length; ++i) {
|
||||
var inspection = inspections[i];
|
||||
if (inspection.isRejected()) {
|
||||
errorObj.e = inspection.error();
|
||||
return errorObj;
|
||||
} else if (!inspection.isFulfilled()) {
|
||||
resultPromise.cancel();
|
||||
return;
|
||||
}
|
||||
inspections[i] = inspection.value();
|
||||
}
|
||||
promise._pushContext();
|
||||
|
||||
fn = tryCatch(fn);
|
||||
var ret = spreadArgs
|
||||
? fn.apply(undefined, inspections) : fn(inspections);
|
||||
var promiseCreated = promise._popContext();
|
||||
debug.checkForgottenReturns(
|
||||
ret, promiseCreated, "Promise.using", promise);
|
||||
return ret;
|
||||
});
|
||||
|
||||
var promise = resultPromise.lastly(function() {
|
||||
var inspection = new Promise.PromiseInspection(resultPromise);
|
||||
return dispose(resources, inspection);
|
||||
});
|
||||
resources.promise = promise;
|
||||
promise._setOnCancel(resources);
|
||||
return promise;
|
||||
};
|
||||
|
||||
Promise.prototype._setDisposable = function (disposer) {
|
||||
this._bitField = this._bitField | IS_DISPOSABLE;
|
||||
this._disposer = disposer;
|
||||
};
|
||||
|
||||
Promise.prototype._isDisposable = function () {
|
||||
return (this._bitField & IS_DISPOSABLE) > 0;
|
||||
};
|
||||
|
||||
Promise.prototype._getDisposer = function () {
|
||||
return this._disposer;
|
||||
};
|
||||
|
||||
Promise.prototype._unsetDisposable = function () {
|
||||
this._bitField = this._bitField & (~IS_DISPOSABLE);
|
||||
this._disposer = undefined;
|
||||
};
|
||||
|
||||
Promise.prototype.disposer = function (fn) {
|
||||
if (typeof fn === "function") {
|
||||
return new FunctionDisposer(fn, this, createContext());
|
||||
}
|
||||
throw new TypeError();
|
||||
};
|
||||
|
||||
};
|
|
@ -0,0 +1,432 @@
|
|||
"use strict";
|
||||
var ASSERT = require("./assert");
|
||||
var es5 = require("./es5");
|
||||
// Assume CSP if browser
|
||||
var canEvaluate = typeof navigator == "undefined";
|
||||
|
||||
//Try catch is not supported in optimizing
|
||||
//compiler, so it is isolated
|
||||
var errorObj = {e: {}};
|
||||
var tryCatchTarget;
|
||||
var globalObject = typeof self !== "undefined" ? self :
|
||||
typeof window !== "undefined" ? window :
|
||||
typeof global !== "undefined" ? global :
|
||||
this !== undefined ? this : null;
|
||||
|
||||
function tryCatcher() {
|
||||
try {
|
||||
var target = tryCatchTarget;
|
||||
tryCatchTarget = null;
|
||||
return target.apply(this, arguments);
|
||||
} catch (e) {
|
||||
errorObj.e = e;
|
||||
return errorObj;
|
||||
}
|
||||
}
|
||||
function tryCatch(fn) {
|
||||
ASSERT(typeof fn === "function");
|
||||
tryCatchTarget = fn;
|
||||
return tryCatcher;
|
||||
}
|
||||
|
||||
//Un-magical enough that using this doesn't prevent
|
||||
//extending classes from outside using any convention
|
||||
var inherits = function(Child, Parent) {
|
||||
var hasProp = {}.hasOwnProperty;
|
||||
|
||||
function T() {
|
||||
this.constructor = Child;
|
||||
this.constructor$ = Parent;
|
||||
for (var propertyName in Parent.prototype) {
|
||||
if (hasProp.call(Parent.prototype, propertyName) &&
|
||||
propertyName.charAt(propertyName.length-1) !== "$"
|
||||
) {
|
||||
this[propertyName + "$"] = Parent.prototype[propertyName];
|
||||
}
|
||||
}
|
||||
}
|
||||
T.prototype = Parent.prototype;
|
||||
Child.prototype = new T();
|
||||
return Child.prototype;
|
||||
};
|
||||
|
||||
|
||||
function isPrimitive(val) {
|
||||
return val == null || val === true || val === false ||
|
||||
typeof val === "string" || typeof val === "number";
|
||||
|
||||
}
|
||||
|
||||
function isObject(value) {
|
||||
return typeof value === "function" ||
|
||||
typeof value === "object" && value !== null;
|
||||
}
|
||||
|
||||
function maybeWrapAsError(maybeError) {
|
||||
if (!isPrimitive(maybeError)) return maybeError;
|
||||
|
||||
return new Error(safeToString(maybeError));
|
||||
}
|
||||
|
||||
function withAppended(target, appendee) {
|
||||
var len = target.length;
|
||||
var ret = new Array(len + 1);
|
||||
var i;
|
||||
for (i = 0; i < len; ++i) {
|
||||
ret[i] = target[i];
|
||||
}
|
||||
ret[i] = appendee;
|
||||
return ret;
|
||||
}
|
||||
|
||||
function getDataPropertyOrDefault(obj, key, defaultValue) {
|
||||
if (es5.isES5) {
|
||||
var desc = Object.getOwnPropertyDescriptor(obj, key);
|
||||
|
||||
if (desc != null) {
|
||||
return desc.get == null && desc.set == null
|
||||
? desc.value
|
||||
: defaultValue;
|
||||
}
|
||||
} else {
|
||||
return {}.hasOwnProperty.call(obj, key) ? obj[key] : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function notEnumerableProp(obj, name, value) {
|
||||
if (isPrimitive(obj)) return obj;
|
||||
var descriptor = {
|
||||
value: value,
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
writable: true
|
||||
};
|
||||
es5.defineProperty(obj, name, descriptor);
|
||||
return obj;
|
||||
}
|
||||
|
||||
function thrower(r) {
|
||||
throw r;
|
||||
}
|
||||
|
||||
var inheritedDataKeys = (function() {
|
||||
var excludedPrototypes = [
|
||||
Array.prototype,
|
||||
Object.prototype,
|
||||
Function.prototype
|
||||
];
|
||||
|
||||
var isExcludedProto = function(val) {
|
||||
for (var i = 0; i < excludedPrototypes.length; ++i) {
|
||||
if (excludedPrototypes[i] === val) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (es5.isES5) {
|
||||
var getKeys = Object.getOwnPropertyNames;
|
||||
return function(obj) {
|
||||
var ret = [];
|
||||
var visitedKeys = Object.create(null);
|
||||
while (obj != null && !isExcludedProto(obj)) {
|
||||
var keys;
|
||||
try {
|
||||
keys = getKeys(obj);
|
||||
} catch (e) {
|
||||
return ret;
|
||||
}
|
||||
for (var i = 0; i < keys.length; ++i) {
|
||||
var key = keys[i];
|
||||
if (visitedKeys[key]) continue;
|
||||
visitedKeys[key] = true;
|
||||
var desc = Object.getOwnPropertyDescriptor(obj, key);
|
||||
if (desc != null && desc.get == null && desc.set == null) {
|
||||
ret.push(key);
|
||||
}
|
||||
}
|
||||
obj = es5.getPrototypeOf(obj);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
} else {
|
||||
var hasProp = {}.hasOwnProperty;
|
||||
return function(obj) {
|
||||
if (isExcludedProto(obj)) return [];
|
||||
var ret = [];
|
||||
|
||||
/*jshint forin:false */
|
||||
enumeration: for (var key in obj) {
|
||||
if (hasProp.call(obj, key)) {
|
||||
ret.push(key);
|
||||
} else {
|
||||
for (var i = 0; i < excludedPrototypes.length; ++i) {
|
||||
if (hasProp.call(excludedPrototypes[i], key)) {
|
||||
continue enumeration;
|
||||
}
|
||||
}
|
||||
ret.push(key);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
var thisAssignmentPattern = /this\s*\.\s*\S+\s*=/;
|
||||
function isClass(fn) {
|
||||
try {
|
||||
if (typeof fn === "function") {
|
||||
var keys = es5.names(fn.prototype);
|
||||
|
||||
var hasMethods = es5.isES5 && keys.length > 1;
|
||||
var hasMethodsOtherThanConstructor = keys.length > 0 &&
|
||||
!(keys.length === 1 && keys[0] === "constructor");
|
||||
var hasThisAssignmentAndStaticMethods =
|
||||
thisAssignmentPattern.test(fn + "") && es5.names(fn).length > 0;
|
||||
|
||||
if (hasMethods || hasMethodsOtherThanConstructor ||
|
||||
hasThisAssignmentAndStaticMethods) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function toFastProperties(obj) {
|
||||
/*jshint -W027,-W055,-W031*/
|
||||
function FakeConstructor() {}
|
||||
FakeConstructor.prototype = obj;
|
||||
var receiver = new FakeConstructor();
|
||||
function ic() {
|
||||
return typeof receiver.foo;
|
||||
}
|
||||
ic();
|
||||
ic();
|
||||
ASSERT("%HasFastProperties", true, obj);
|
||||
return obj;
|
||||
// Prevent the function from being optimized through dead code elimination
|
||||
// or further optimizations. This code is never reached but even using eval
|
||||
// in unreachable code causes v8 to not optimize functions.
|
||||
eval(obj);
|
||||
}
|
||||
|
||||
var rident = /^[a-z$_][a-z$_0-9]*$/i;
|
||||
function isIdentifier(str) {
|
||||
return rident.test(str);
|
||||
}
|
||||
|
||||
function filledRange(count, prefix, suffix) {
|
||||
var ret = new Array(count);
|
||||
for(var i = 0; i < count; ++i) {
|
||||
ret[i] = prefix + i + suffix;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function safeToString(obj) {
|
||||
try {
|
||||
return obj + "";
|
||||
} catch (e) {
|
||||
return "[no string representation]";
|
||||
}
|
||||
}
|
||||
|
||||
function isError(obj) {
|
||||
return obj instanceof Error ||
|
||||
(obj !== null &&
|
||||
typeof obj === "object" &&
|
||||
typeof obj.message === "string" &&
|
||||
typeof obj.name === "string");
|
||||
}
|
||||
|
||||
function markAsOriginatingFromRejection(e) {
|
||||
try {
|
||||
notEnumerableProp(e, OPERATIONAL_ERROR_KEY, true);
|
||||
}
|
||||
catch(ignore) {}
|
||||
}
|
||||
|
||||
function originatesFromRejection(e) {
|
||||
if (e == null) return false;
|
||||
return ((e instanceof Error[BLUEBIRD_ERRORS].OperationalError) ||
|
||||
e[OPERATIONAL_ERROR_KEY] === true);
|
||||
}
|
||||
|
||||
function canAttachTrace(obj) {
|
||||
return isError(obj) && es5.propertyIsWritable(obj, "stack");
|
||||
}
|
||||
|
||||
var ensureErrorObject = (function() {
|
||||
if (!("stack" in new Error())) {
|
||||
return function(value) {
|
||||
if (canAttachTrace(value)) return value;
|
||||
try {throw new Error(safeToString(value));}
|
||||
catch(err) {return err;}
|
||||
};
|
||||
} else {
|
||||
return function(value) {
|
||||
if (canAttachTrace(value)) return value;
|
||||
return new Error(safeToString(value));
|
||||
};
|
||||
}
|
||||
})();
|
||||
|
||||
function classString(obj) {
|
||||
return {}.toString.call(obj);
|
||||
}
|
||||
|
||||
function copyDescriptors(from, to, filter) {
|
||||
var keys = es5.names(from);
|
||||
for (var i = 0; i < keys.length; ++i) {
|
||||
var key = keys[i];
|
||||
if (filter(key)) {
|
||||
try {
|
||||
es5.defineProperty(to, key, es5.getDescriptor(from, key));
|
||||
} catch (ignore) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var asArray = function(v) {
|
||||
if (es5.isArray(v)) {
|
||||
return v;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
if (typeof Symbol !== "undefined" && Symbol.iterator) {
|
||||
var ArrayFrom = typeof Array.from === "function" ? function(v) {
|
||||
return Array.from(v);
|
||||
} : function(v) {
|
||||
var ret = [];
|
||||
var it = v[Symbol.iterator]();
|
||||
var itResult;
|
||||
while (!((itResult = it.next()).done)) {
|
||||
ret.push(itResult.value);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
asArray = function(v) {
|
||||
if (es5.isArray(v)) {
|
||||
return v;
|
||||
} else if (v != null && typeof v[Symbol.iterator] === "function") {
|
||||
return ArrayFrom(v);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
var isNode = typeof process !== "undefined" &&
|
||||
classString(process).toLowerCase() === "[object process]";
|
||||
|
||||
var hasEnvVariables = typeof process !== "undefined" &&
|
||||
typeof process.env !== "undefined";
|
||||
|
||||
function env(key) {
|
||||
return hasEnvVariables ? process.env[key] : undefined;
|
||||
}
|
||||
|
||||
function getNativePromise() {
|
||||
if (typeof Promise === "function") {
|
||||
try {
|
||||
var promise = new Promise(function(){});
|
||||
if (classString(promise) === "[object Promise]") {
|
||||
return Promise;
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
||||
var reflectHandler;
|
||||
function contextBind(ctx, cb) {
|
||||
if (ctx === null ||
|
||||
typeof cb !== "function" ||
|
||||
cb === reflectHandler) {
|
||||
return cb;
|
||||
}
|
||||
|
||||
if (ctx.domain !== null) {
|
||||
cb = ctx.domain.bind(cb);
|
||||
}
|
||||
|
||||
var async = ctx.async;
|
||||
if (async !== null) {
|
||||
var old = cb;
|
||||
cb = function() {
|
||||
INLINE_SLICE_LEFT_PADDED(2, args, arguments);
|
||||
args[0] = old;
|
||||
args[1] = this;
|
||||
return async.runInAsyncScope.apply(async, args);
|
||||
};
|
||||
}
|
||||
return cb;
|
||||
}
|
||||
|
||||
var ret = {
|
||||
setReflectHandler: function(fn) {
|
||||
reflectHandler = fn;
|
||||
},
|
||||
isClass: isClass,
|
||||
isIdentifier: isIdentifier,
|
||||
inheritedDataKeys: inheritedDataKeys,
|
||||
getDataPropertyOrDefault: getDataPropertyOrDefault,
|
||||
thrower: thrower,
|
||||
isArray: es5.isArray,
|
||||
asArray: asArray,
|
||||
notEnumerableProp: notEnumerableProp,
|
||||
isPrimitive: isPrimitive,
|
||||
isObject: isObject,
|
||||
isError: isError,
|
||||
canEvaluate: canEvaluate,
|
||||
errorObj: errorObj,
|
||||
tryCatch: tryCatch,
|
||||
inherits: inherits,
|
||||
withAppended: withAppended,
|
||||
maybeWrapAsError: maybeWrapAsError,
|
||||
toFastProperties: toFastProperties,
|
||||
filledRange: filledRange,
|
||||
toString: safeToString,
|
||||
canAttachTrace: canAttachTrace,
|
||||
ensureErrorObject: ensureErrorObject,
|
||||
originatesFromRejection: originatesFromRejection,
|
||||
markAsOriginatingFromRejection: markAsOriginatingFromRejection,
|
||||
classString: classString,
|
||||
copyDescriptors: copyDescriptors,
|
||||
isNode: isNode,
|
||||
hasEnvVariables: hasEnvVariables,
|
||||
env: env,
|
||||
global: globalObject,
|
||||
getNativePromise: getNativePromise,
|
||||
contextBind: contextBind
|
||||
};
|
||||
ret.isRecentNode = ret.isNode && (function() {
|
||||
var version;
|
||||
if (process.versions && process.versions.node) {
|
||||
version = process.versions.node.split(".").map(Number);
|
||||
} else if (process.version) {
|
||||
version = process.version.split(".").map(Number);
|
||||
}
|
||||
return (version[0] === 0 && version[1] > 10) || (version[0] > 0);
|
||||
})();
|
||||
ret.nodeSupportsAsyncResource = ret.isNode && (function() {
|
||||
var supportsAsync = false;
|
||||
try {
|
||||
var res = require("async_hooks").AsyncResource;
|
||||
supportsAsync = typeof res.prototype.runInAsyncScope === "function";
|
||||
} catch (e) {
|
||||
supportsAsync = false;
|
||||
}
|
||||
return supportsAsync;
|
||||
})();
|
||||
|
||||
if (ret.isNode) ret.toFastProperties(process);
|
||||
|
||||
try {throw new Error(); } catch (e) {ret.lastLineError = e;}
|
||||
module.exports = ret;
|
|
@ -0,0 +1,76 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testFulfilled = require("./helpers/testThreeCases").testFulfilled;
|
||||
|
||||
var adapter = global.adapter;
|
||||
var pending = adapter.pending;
|
||||
|
||||
var dummy = { dummy: "dummy" }; // we fulfill or reject with this when we don't intend to test against it
|
||||
|
||||
describe("2.1.2.1: When fulfilled, a promise: must not transition to any other state.", function () {
|
||||
testFulfilled(dummy, function (promise, done) {
|
||||
var onFulfilledCalled = false;
|
||||
|
||||
promise.then(function onFulfilled() {
|
||||
onFulfilledCalled = true;
|
||||
}, function onRejected() {
|
||||
assert.strictEqual(onFulfilledCalled, false);
|
||||
done();
|
||||
});
|
||||
|
||||
setTimeout(function(){done();}, 100);
|
||||
});
|
||||
|
||||
specify("trying to fulfill then immediately reject", function (done) {
|
||||
var tuple = pending();
|
||||
var onFulfilledCalled = false;
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
onFulfilledCalled = true;
|
||||
}, function onRejected() {
|
||||
assert.strictEqual(onFulfilledCalled, false);
|
||||
done();
|
||||
});
|
||||
|
||||
tuple.fulfill(dummy);
|
||||
tuple.reject(dummy);
|
||||
setTimeout(function(){done();}, 100);
|
||||
});
|
||||
|
||||
specify("trying to fulfill then reject, delayed", function (done) {
|
||||
var tuple = pending();
|
||||
var onFulfilledCalled = false;
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
onFulfilledCalled = true;
|
||||
}, function onRejected() {
|
||||
assert.strictEqual(onFulfilledCalled, false);
|
||||
done();
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.fulfill(dummy);
|
||||
tuple.reject(dummy);
|
||||
}, 50);
|
||||
setTimeout(function(){done();}, 100);
|
||||
});
|
||||
|
||||
specify("trying to fulfill immediately then reject delayed", function (done) {
|
||||
var tuple = pending();
|
||||
var onFulfilledCalled = false;
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
onFulfilledCalled = true;
|
||||
}, function onRejected() {
|
||||
assert.strictEqual(onFulfilledCalled, false);
|
||||
done();
|
||||
});
|
||||
|
||||
tuple.fulfill(dummy);
|
||||
setTimeout(function () {
|
||||
tuple.reject(dummy);
|
||||
}, 50);
|
||||
setTimeout(function(){done();}, 100);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,76 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testRejected = require("./helpers/testThreeCases").testRejected;
|
||||
|
||||
var adapter = global.adapter;
|
||||
var pending = adapter.pending;
|
||||
|
||||
var dummy = { dummy: "dummy" }; // we fulfill or reject with this when we don't intend to test against it
|
||||
|
||||
describe("2.1.3.1: When rejected, a promise: must not transition to any other state.", function () {
|
||||
testRejected(dummy, function (promise, done) {
|
||||
var onRejectedCalled = false;
|
||||
|
||||
promise.then(function onFulfilled() {
|
||||
assert.strictEqual(onRejectedCalled, false);
|
||||
done();
|
||||
}, function onRejected() {
|
||||
onRejectedCalled = true;
|
||||
});
|
||||
|
||||
setTimeout(function(){done();}, 100);
|
||||
});
|
||||
|
||||
specify("trying to reject then immediately fulfill", function (done) {
|
||||
var tuple = pending();
|
||||
var onRejectedCalled = false;
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
assert.strictEqual(onRejectedCalled, false);
|
||||
done();
|
||||
}, function onRejected() {
|
||||
onRejectedCalled = true;
|
||||
});
|
||||
|
||||
tuple.reject(dummy);
|
||||
tuple.fulfill(dummy);
|
||||
setTimeout(function(){done();}, 100);
|
||||
});
|
||||
|
||||
specify("trying to reject then fulfill, delayed", function (done) {
|
||||
var tuple = pending();
|
||||
var onRejectedCalled = false;
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
assert.strictEqual(onRejectedCalled, false);
|
||||
done();
|
||||
}, function onRejected() {
|
||||
onRejectedCalled = true;
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.reject(dummy);
|
||||
tuple.fulfill(dummy);
|
||||
}, 50);
|
||||
setTimeout(function(){done();}, 100);
|
||||
});
|
||||
|
||||
specify("trying to reject immediately then fulfill delayed", function (done) {
|
||||
var tuple = pending();
|
||||
var onRejectedCalled = false;
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
assert.strictEqual(onRejectedCalled, false);
|
||||
done();
|
||||
}, function onRejected() {
|
||||
onRejectedCalled = true;
|
||||
});
|
||||
|
||||
tuple.reject(dummy);
|
||||
setTimeout(function () {
|
||||
tuple.fulfill(dummy);
|
||||
}, 50);
|
||||
setTimeout(function(){done();}, 100);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,41 @@
|
|||
"use strict";
|
||||
|
||||
var adapter = global.adapter;
|
||||
var fulfilled = adapter.fulfilled;
|
||||
var rejected = adapter.rejected;
|
||||
|
||||
var dummy = { dummy: "dummy" }; // we fulfill or reject with this when we don't intend to test against it
|
||||
|
||||
describe("2.2.1: Both `onFulfilled` and `onRejected` are optional arguments.", function () {
|
||||
describe("2.2.1.1: If `onFulfilled` is not a function, it must be ignored.", function () {
|
||||
function testNonFunction(nonFunction, stringRepresentation) {
|
||||
specify("`onFulfilled` is " + stringRepresentation, function (done) {
|
||||
rejected(dummy).then(nonFunction, function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
testNonFunction(undefined, "`undefined`");
|
||||
testNonFunction(null, "`null`");
|
||||
testNonFunction(false, "`false`");
|
||||
testNonFunction(5, "`5`");
|
||||
testNonFunction({}, "an object");
|
||||
});
|
||||
|
||||
describe("2.2.1.2: If `onRejected` is not a function, it must be ignored.", function () {
|
||||
function testNonFunction(nonFunction, stringRepresentation) {
|
||||
specify("`onRejected` is " + stringRepresentation, function (done) {
|
||||
fulfilled(dummy).then(function () {
|
||||
done();
|
||||
}, nonFunction);
|
||||
});
|
||||
}
|
||||
|
||||
testNonFunction(undefined, "`undefined`");
|
||||
testNonFunction(null, "`null`");
|
||||
testNonFunction(false, "`false`");
|
||||
testNonFunction(5, "`5`");
|
||||
testNonFunction({}, "an object");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,151 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testFulfilled = require("./helpers/testThreeCases").testFulfilled;
|
||||
|
||||
var adapter = global.adapter;
|
||||
var fulfilled = adapter.fulfilled;
|
||||
var pending = adapter.pending;
|
||||
|
||||
var dummy = { dummy: "dummy" }; // we fulfill or reject with this when we don't intend to test against it
|
||||
var sentinel = { sentinel: "sentinel" }; // a sentinel fulfillment value to test for with strict equality
|
||||
|
||||
describe("2.2.2: If `onFulfilled` is a function,", function () {
|
||||
describe("2.2.2.1: it must be called after `promise` is fulfilled, with `promise`’s fulfillment value as its " +
|
||||
"first argument.", function () {
|
||||
testFulfilled(sentinel, function (promise, done) {
|
||||
promise.then(function onFulfilled(value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("2.2.2.2: it must not be called before `promise` is fulfilled", function () {
|
||||
specify("fulfilled after a delay", function (done) {
|
||||
var tuple = pending();
|
||||
var isFulfilled = false;
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
assert.strictEqual(isFulfilled, true);
|
||||
done();
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.fulfill(dummy);
|
||||
isFulfilled = true;
|
||||
}, 50);
|
||||
});
|
||||
|
||||
specify("never fulfilled", function (done) {
|
||||
var tuple = pending();
|
||||
var onFulfilledCalled = false;
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
onFulfilledCalled = true;
|
||||
done();
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
assert.strictEqual(onFulfilledCalled, false);
|
||||
done();
|
||||
}, 150);
|
||||
});
|
||||
});
|
||||
|
||||
describe("2.2.2.3: it must not be called more than once.", function () {
|
||||
specify("already-fulfilled", function (done) {
|
||||
var timesCalled = 0;
|
||||
|
||||
fulfilled(dummy).then(function onFulfilled() {
|
||||
assert.strictEqual(++timesCalled, 1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
specify("trying to fulfill a pending promise more than once, immediately", function (done) {
|
||||
var tuple = pending();
|
||||
var timesCalled = 0;
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
assert.strictEqual(++timesCalled, 1);
|
||||
done();
|
||||
});
|
||||
|
||||
tuple.fulfill(dummy);
|
||||
tuple.fulfill(dummy);
|
||||
});
|
||||
|
||||
specify("trying to fulfill a pending promise more than once, delayed", function (done) {
|
||||
var tuple = pending();
|
||||
var timesCalled = 0;
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
assert.strictEqual(++timesCalled, 1);
|
||||
done();
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.fulfill(dummy);
|
||||
tuple.fulfill(dummy);
|
||||
}, 50);
|
||||
});
|
||||
|
||||
specify("trying to fulfill a pending promise more than once, immediately then delayed", function (done) {
|
||||
var tuple = pending();
|
||||
var timesCalled = 0;
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
assert.strictEqual(++timesCalled, 1);
|
||||
done();
|
||||
});
|
||||
|
||||
tuple.fulfill(dummy);
|
||||
setTimeout(function () {
|
||||
tuple.fulfill(dummy);
|
||||
}, 50);
|
||||
});
|
||||
|
||||
specify("when multiple `then` calls are made, spaced apart in time", function (done) {
|
||||
var tuple = pending();
|
||||
var timesCalled = [0, 0, 0];
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
assert.strictEqual(++timesCalled[0], 1);
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
assert.strictEqual(++timesCalled[1], 1);
|
||||
});
|
||||
}, 50);
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
assert.strictEqual(++timesCalled[2], 1);
|
||||
done();
|
||||
});
|
||||
}, 100);
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.fulfill(dummy);
|
||||
}, 150);
|
||||
});
|
||||
|
||||
specify("when `then` is interleaved with fulfillment", function (done) {
|
||||
var tuple = pending();
|
||||
var timesCalled = [0, 0];
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
assert.strictEqual(++timesCalled[0], 1);
|
||||
});
|
||||
|
||||
tuple.fulfill(dummy);
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
assert.strictEqual(++timesCalled[1], 1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,151 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testRejected = require("./helpers/testThreeCases").testRejected;
|
||||
|
||||
var adapter = global.adapter;
|
||||
var rejected = adapter.rejected;
|
||||
var pending = adapter.pending;
|
||||
|
||||
var dummy = { dummy: "dummy" }; // we fulfill or reject with this when we don't intend to test against it
|
||||
var sentinel = { sentinel: "sentinel" }; // a sentinel fulfillment value to test for with strict equality
|
||||
|
||||
describe("2.2.3: If `onRejected` is a function,", function () {
|
||||
describe("2.2.3.1: it must be called after `promise` is rejected, with `promise`’s rejection reason as its " +
|
||||
"first argument.", function () {
|
||||
testRejected(sentinel, function (promise, done) {
|
||||
promise.then(null, function onRejected(reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("2.2.3.2: it must not be called before `promise` is rejected", function () {
|
||||
specify("rejected after a delay", function (done) {
|
||||
var tuple = pending();
|
||||
var isRejected = false;
|
||||
|
||||
tuple.promise.then(null, function onRejected() {
|
||||
assert.strictEqual(isRejected, true);
|
||||
done();
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.reject(dummy);
|
||||
isRejected = true;
|
||||
}, 50);
|
||||
});
|
||||
|
||||
specify("never rejected", function (done) {
|
||||
var tuple = pending();
|
||||
var onRejectedCalled = false;
|
||||
|
||||
tuple.promise.then(null, function onRejected() {
|
||||
onRejectedCalled = true;
|
||||
done();
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
assert.strictEqual(onRejectedCalled, false);
|
||||
done();
|
||||
}, 150);
|
||||
});
|
||||
});
|
||||
|
||||
describe("2.2.3.3: it must not be called more than once.", function () {
|
||||
specify("already-rejected", function (done) {
|
||||
var timesCalled = 0;
|
||||
|
||||
rejected(dummy).then(null, function onRejected() {
|
||||
assert.strictEqual(++timesCalled, 1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
specify("trying to reject a pending promise more than once, immediately", function (done) {
|
||||
var tuple = pending();
|
||||
var timesCalled = 0;
|
||||
|
||||
tuple.promise.then(null, function onRejected() {
|
||||
assert.strictEqual(++timesCalled, 1);
|
||||
done();
|
||||
});
|
||||
|
||||
tuple.reject(dummy);
|
||||
tuple.reject(dummy);
|
||||
});
|
||||
|
||||
specify("trying to reject a pending promise more than once, delayed", function (done) {
|
||||
var tuple = pending();
|
||||
var timesCalled = 0;
|
||||
|
||||
tuple.promise.then(null, function onRejected() {
|
||||
assert.strictEqual(++timesCalled, 1);
|
||||
done();
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.reject(dummy);
|
||||
tuple.reject(dummy);
|
||||
}, 50);
|
||||
});
|
||||
|
||||
specify("trying to reject a pending promise more than once, immediately then delayed", function (done) {
|
||||
var tuple = pending();
|
||||
var timesCalled = 0;
|
||||
|
||||
tuple.promise.then(null, function onRejected() {
|
||||
assert.strictEqual(++timesCalled, 1);
|
||||
done();
|
||||
});
|
||||
|
||||
tuple.reject(dummy);
|
||||
setTimeout(function () {
|
||||
tuple.reject(dummy);
|
||||
}, 50);
|
||||
});
|
||||
|
||||
specify("when multiple `then` calls are made, spaced apart in time", function (done) {
|
||||
var tuple = pending();
|
||||
var timesCalled = [0, 0, 0];
|
||||
|
||||
tuple.promise.then(null, function onRejected() {
|
||||
assert.strictEqual(++timesCalled[0], 1);
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.promise.then(null, function onRejected() {
|
||||
assert.strictEqual(++timesCalled[1], 1);
|
||||
});
|
||||
}, 50);
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.promise.then(null, function onRejected() {
|
||||
assert.strictEqual(++timesCalled[2], 1);
|
||||
done();
|
||||
});
|
||||
}, 100);
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.reject(dummy);
|
||||
}, 150);
|
||||
});
|
||||
|
||||
specify("when `then` is interleaved with rejection", function (done) {
|
||||
var tuple = pending();
|
||||
var timesCalled = [0, 0];
|
||||
|
||||
tuple.promise.then(null, function onRejected() {
|
||||
assert.strictEqual(++timesCalled[0], 1);
|
||||
});
|
||||
|
||||
tuple.reject(dummy);
|
||||
|
||||
tuple.promise.then(null, function onRejected() {
|
||||
assert.strictEqual(++timesCalled[1], 1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,182 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testFulfilled = require("./helpers/testThreeCases").testFulfilled;
|
||||
var testRejected = require("./helpers/testThreeCases").testRejected;
|
||||
|
||||
var adapter = global.adapter;
|
||||
var fulfilled = adapter.fulfilled;
|
||||
var rejected = adapter.rejected;
|
||||
var pending = adapter.pending;
|
||||
|
||||
var dummy = { dummy: "dummy" }; // we fulfill or reject with this when we don't intend to test against it
|
||||
|
||||
describe("2.2.4: `onFulfilled` or `onRejected` must not be called until the execution context stack contains only " +
|
||||
"platform code.", function () {
|
||||
describe("`then` returns before the promise becomes fulfilled or rejected", function () {
|
||||
testFulfilled(dummy, function (promise, done) {
|
||||
var thenHasReturned = false;
|
||||
|
||||
promise.then(function onFulfilled() {
|
||||
assert.strictEqual(thenHasReturned, true);
|
||||
done();
|
||||
});
|
||||
|
||||
thenHasReturned = true;
|
||||
});
|
||||
testRejected(dummy, function (promise, done) {
|
||||
var thenHasReturned = false;
|
||||
|
||||
promise.then(null, function onRejected() {
|
||||
assert.strictEqual(thenHasReturned, true);
|
||||
done();
|
||||
});
|
||||
|
||||
thenHasReturned = true;
|
||||
});
|
||||
});
|
||||
|
||||
describe("Clean-stack execution ordering tests (fulfillment case)", function () {
|
||||
specify("when `onFulfilled` is added immediately before the promise is fulfilled",
|
||||
function () {
|
||||
var tuple = pending();
|
||||
var onFulfilledCalled = false;
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
onFulfilledCalled = true;
|
||||
});
|
||||
|
||||
tuple.fulfill(dummy);
|
||||
|
||||
assert.strictEqual(onFulfilledCalled, false);
|
||||
});
|
||||
|
||||
specify("when `onFulfilled` is added immediately after the promise is fulfilled",
|
||||
function () {
|
||||
var tuple = pending();
|
||||
var onFulfilledCalled = false;
|
||||
|
||||
tuple.fulfill(dummy);
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
onFulfilledCalled = true;
|
||||
});
|
||||
|
||||
assert.strictEqual(onFulfilledCalled, false);
|
||||
});
|
||||
|
||||
specify("when one `onFulfilled` is added inside another `onFulfilled`", function (done) {
|
||||
var promise = fulfilled();
|
||||
var firstOnFulfilledFinished = false;
|
||||
|
||||
promise.then(function () {
|
||||
promise.then(function () {
|
||||
assert.strictEqual(firstOnFulfilledFinished, true);
|
||||
done();
|
||||
});
|
||||
firstOnFulfilledFinished = true;
|
||||
});
|
||||
});
|
||||
|
||||
specify("when `onFulfilled` is added inside an `onRejected`", function (done) {
|
||||
var promise = rejected();
|
||||
var promise2 = fulfilled();
|
||||
var firstOnRejectedFinished = false;
|
||||
|
||||
promise.then(null, function () {
|
||||
promise2.then(function () {
|
||||
assert.strictEqual(firstOnRejectedFinished, true);
|
||||
done();
|
||||
});
|
||||
firstOnRejectedFinished = true;
|
||||
});
|
||||
});
|
||||
|
||||
specify("when the promise is fulfilled asynchronously", function (done) {
|
||||
var tuple = pending();
|
||||
var firstStackFinished = false;
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.fulfill(dummy);
|
||||
firstStackFinished = true;
|
||||
}, 0);
|
||||
|
||||
tuple.promise.then(function () {
|
||||
assert.strictEqual(firstStackFinished, true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Clean-stack execution ordering tests (rejection case)", function () {
|
||||
specify("when `onRejected` is added immediately before the promise is rejected",
|
||||
function () {
|
||||
var tuple = pending();
|
||||
var onRejectedCalled = false;
|
||||
|
||||
tuple.promise.then(null, function onRejected() {
|
||||
onRejectedCalled = true;
|
||||
});
|
||||
|
||||
tuple.reject(dummy);
|
||||
|
||||
assert.strictEqual(onRejectedCalled, false);
|
||||
});
|
||||
|
||||
specify("when `onRejected` is added immediately after the promise is rejected",
|
||||
function () {
|
||||
var tuple = pending();
|
||||
var onRejectedCalled = false;
|
||||
|
||||
tuple.reject(dummy);
|
||||
|
||||
tuple.promise.then(null, function onRejected() {
|
||||
onRejectedCalled = true;
|
||||
});
|
||||
|
||||
assert.strictEqual(onRejectedCalled, false);
|
||||
});
|
||||
|
||||
specify("when `onRejected` is added inside an `onFulfilled`", function (done) {
|
||||
var promise = fulfilled();
|
||||
var promise2 = rejected();
|
||||
var firstOnFulfilledFinished = false;
|
||||
|
||||
promise.then(function () {
|
||||
promise2.then(null, function () {
|
||||
assert.strictEqual(firstOnFulfilledFinished, true);
|
||||
done();
|
||||
});
|
||||
firstOnFulfilledFinished = true;
|
||||
});
|
||||
});
|
||||
|
||||
specify("when one `onRejected` is added inside another `onRejected`", function (done) {
|
||||
var promise = rejected();
|
||||
var firstOnRejectedFinished = false;
|
||||
|
||||
promise.then(null, function () {
|
||||
promise.then(null, function () {
|
||||
assert.strictEqual(firstOnRejectedFinished, true);
|
||||
done();
|
||||
});
|
||||
firstOnRejectedFinished = true;
|
||||
});
|
||||
});
|
||||
|
||||
specify("when the promise is rejected asynchronously", function (done) {
|
||||
var tuple = pending();
|
||||
var firstStackFinished = false;
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.reject(dummy);
|
||||
firstStackFinished = true;
|
||||
}, 0);
|
||||
|
||||
tuple.promise.then(null, function () {
|
||||
assert.strictEqual(firstStackFinished, true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,58 @@
|
|||
/*jshint strict: false */
|
||||
|
||||
var assert = require("assert");
|
||||
|
||||
var adapter = global.adapter;
|
||||
var fulfilled = adapter.fulfilled;
|
||||
var rejected = adapter.rejected;
|
||||
|
||||
var dummy = { dummy: "dummy" }; // we fulfill or reject with this when we don't intend to test against it
|
||||
|
||||
var undefinedThisStrict = (function() {
|
||||
"use strict";
|
||||
return this;
|
||||
})();
|
||||
|
||||
var undefinedThisSloppy = (function() {
|
||||
return this;
|
||||
})();
|
||||
|
||||
describe("2.2.5 `onFulfilled` and `onRejected` must be called as functions (i.e. with no `this` value).", function () {
|
||||
describe("strict mode", function () {
|
||||
specify("fulfilled", function (done) {
|
||||
fulfilled(dummy).then(function onFulfilled() {
|
||||
"use strict";
|
||||
|
||||
assert(this === undefinedThisStrict ||
|
||||
this === undefinedThisSloppy);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
specify("rejected", function (done) {
|
||||
rejected(dummy).then(null, function onRejected() {
|
||||
"use strict";
|
||||
|
||||
assert(this === undefinedThisStrict ||
|
||||
this === undefinedThisSloppy);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("sloppy mode", function () {
|
||||
specify("fulfilled", function (done) {
|
||||
fulfilled(dummy).then(function onFulfilled() {
|
||||
assert.strictEqual(this, undefinedThisSloppy);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
specify("rejected", function (done) {
|
||||
rejected(dummy).then(null, function onRejected() {
|
||||
assert.strictEqual(this, undefinedThisSloppy);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,257 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var sinon = require("sinon");
|
||||
var testFulfilled = require("./helpers/testThreeCases").testFulfilled;
|
||||
var testRejected = require("./helpers/testThreeCases").testRejected;
|
||||
|
||||
var dummy = { dummy: "dummy" }; // we fulfill or reject with this when we don't intend to test against it
|
||||
var other = { other: "other" }; // a value we don't want to be strict equal to
|
||||
var sentinel = { sentinel: "sentinel" }; // a sentinel fulfillment value to test for with strict equality
|
||||
var sentinel2 = { sentinel2: "sentinel2" };
|
||||
var sentinel3 = { sentinel3: "sentinel3" };
|
||||
|
||||
function callbackAggregator(times, ultimateCallback) {
|
||||
var soFar = 0;
|
||||
return function () {
|
||||
if (++soFar === times) {
|
||||
ultimateCallback();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
describe("2.2.6: `then` may be called multiple times on the same promise.", function () {
|
||||
describe("2.2.6.1: If/when `promise` is fulfilled, all respective `onFulfilled` callbacks must execute in the " +
|
||||
"order of their originating calls to `then`.", function () {
|
||||
describe("multiple boring fulfillment handlers", function () {
|
||||
testFulfilled(sentinel, function (promise, done) {
|
||||
var handler1 = sinon.stub().returns(other);
|
||||
var handler2 = sinon.stub().returns(other);
|
||||
var handler3 = sinon.stub().returns(other);
|
||||
|
||||
var spy = sinon.spy();
|
||||
promise.then(handler1, spy);
|
||||
promise.then(handler2, spy);
|
||||
promise.then(handler3, spy);
|
||||
|
||||
promise.then(function (value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
|
||||
sinon.assert.calledWith(handler1, sinon.match.same(sentinel));
|
||||
sinon.assert.calledWith(handler2, sinon.match.same(sentinel));
|
||||
sinon.assert.calledWith(handler3, sinon.match.same(sentinel));
|
||||
sinon.assert.notCalled(spy);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("multiple fulfillment handlers, one of which throws", function () {
|
||||
testFulfilled(sentinel, function (promise, done) {
|
||||
var handler1 = sinon.stub().returns(other);
|
||||
var handler2 = sinon.stub().throws(other);
|
||||
var handler3 = sinon.stub().returns(other);
|
||||
|
||||
var spy = sinon.spy();
|
||||
promise.then(handler1, spy);
|
||||
promise.then(handler2, spy).caught(function(){});
|
||||
promise.then(handler3, spy);
|
||||
|
||||
promise.then(function (value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
|
||||
sinon.assert.calledWith(handler1, sinon.match.same(sentinel));
|
||||
sinon.assert.calledWith(handler2, sinon.match.same(sentinel));
|
||||
sinon.assert.calledWith(handler3, sinon.match.same(sentinel));
|
||||
sinon.assert.notCalled(spy);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("results in multiple branching chains with their own fulfillment values", function () {
|
||||
testFulfilled(dummy, function (promise, done) {
|
||||
var semiDone = callbackAggregator(3, done);
|
||||
|
||||
promise.then(function () {
|
||||
return sentinel;
|
||||
}).then(function (value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
semiDone();
|
||||
});
|
||||
|
||||
promise.then(function () {
|
||||
throw sentinel2;
|
||||
}).then(null, function (reason) {
|
||||
assert.strictEqual(reason, sentinel2);
|
||||
semiDone();
|
||||
});
|
||||
|
||||
promise.then(function () {
|
||||
return sentinel3;
|
||||
}).then(function (value) {
|
||||
assert.strictEqual(value, sentinel3);
|
||||
semiDone();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("`onFulfilled` handlers are called in the original order", function () {
|
||||
testFulfilled(dummy, function (promise, done) {
|
||||
var handler1 = sinon.spy(function handler1() {});
|
||||
var handler2 = sinon.spy(function handler2() {});
|
||||
var handler3 = sinon.spy(function handler3() {});
|
||||
|
||||
promise.then(handler1);
|
||||
promise.then(handler2);
|
||||
promise.then(handler3);
|
||||
|
||||
promise.then(function () {
|
||||
sinon.assert.callOrder(handler1, handler2, handler3);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe("even when one handler is added inside another handler", function () {
|
||||
testFulfilled(dummy, function (promise, done) {
|
||||
var handler1 = sinon.spy(function handler1() {});
|
||||
var handler2 = sinon.spy(function handler2() {});
|
||||
var handler3 = sinon.spy(function handler3() {});
|
||||
|
||||
promise.then(function () {
|
||||
handler1();
|
||||
promise.then(handler3);
|
||||
});
|
||||
promise.then(handler2);
|
||||
|
||||
promise.then(function () {
|
||||
// Give implementations a bit of extra time to flush their internal queue, if necessary.
|
||||
setTimeout(function () {
|
||||
sinon.assert.callOrder(handler1, handler2, handler3);
|
||||
done();
|
||||
}, 15);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("2.2.6.2: If/when `promise` is rejected, all respective `onRejected` callbacks must execute in the " +
|
||||
"order of their originating calls to `then`.", function () {
|
||||
describe("multiple boring rejection handlers", function () {
|
||||
testRejected(sentinel, function (promise, done) {
|
||||
var handler1 = sinon.stub().returns(other);
|
||||
var handler2 = sinon.stub().returns(other);
|
||||
var handler3 = sinon.stub().returns(other);
|
||||
|
||||
var spy = sinon.spy();
|
||||
promise.then(spy, handler1);
|
||||
promise.then(spy, handler2);
|
||||
promise.then(spy, handler3);
|
||||
|
||||
promise.then(null, function (reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
|
||||
sinon.assert.calledWith(handler1, sinon.match.same(sentinel));
|
||||
sinon.assert.calledWith(handler2, sinon.match.same(sentinel));
|
||||
sinon.assert.calledWith(handler3, sinon.match.same(sentinel));
|
||||
sinon.assert.notCalled(spy);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("multiple rejection handlers, one of which throws", function () {
|
||||
testRejected(sentinel, function (promise, done) {
|
||||
var handler1 = sinon.stub().returns(other);
|
||||
var handler2 = sinon.stub().throws(other);
|
||||
var handler3 = sinon.stub().returns(other);
|
||||
|
||||
var spy = sinon.spy();
|
||||
promise.then(spy, handler1);
|
||||
promise.then(spy, handler2).caught(function(){});
|
||||
promise.then(spy, handler3);
|
||||
|
||||
promise.then(null, function (reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
|
||||
sinon.assert.calledWith(handler1, sinon.match.same(sentinel));
|
||||
sinon.assert.calledWith(handler2, sinon.match.same(sentinel));
|
||||
sinon.assert.calledWith(handler3, sinon.match.same(sentinel));
|
||||
sinon.assert.notCalled(spy);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("results in multiple branching chains with their own fulfillment values", function () {
|
||||
testRejected(sentinel, function (promise, done) {
|
||||
var semiDone = callbackAggregator(3, done);
|
||||
|
||||
promise.then(null, function () {
|
||||
return sentinel;
|
||||
}).then(function (value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
semiDone();
|
||||
});
|
||||
|
||||
promise.then(null, function () {
|
||||
throw sentinel2;
|
||||
}).then(null, function (reason) {
|
||||
assert.strictEqual(reason, sentinel2);
|
||||
semiDone();
|
||||
});
|
||||
|
||||
promise.then(null, function () {
|
||||
return sentinel3;
|
||||
}).then(function (value) {
|
||||
assert.strictEqual(value, sentinel3);
|
||||
semiDone();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("`onRejected` handlers are called in the original order", function () {
|
||||
testRejected(dummy, function (promise, done) {
|
||||
var handler1 = sinon.spy(function handler1() {});
|
||||
var handler2 = sinon.spy(function handler2() {});
|
||||
var handler3 = sinon.spy(function handler3() {});
|
||||
|
||||
promise.then(null, handler1);
|
||||
promise.then(null, handler2);
|
||||
promise.then(null, handler3);
|
||||
|
||||
promise.then(null, function () {
|
||||
sinon.assert.callOrder(handler1, handler2, handler3);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe("even when one handler is added inside another handler", function () {
|
||||
testRejected(dummy, function (promise, done) {
|
||||
var handler1 = sinon.spy(function handler1() {});
|
||||
var handler2 = sinon.spy(function handler2() {});
|
||||
var handler3 = sinon.spy(function handler3() {});
|
||||
|
||||
promise.then(null, function () {
|
||||
handler1();
|
||||
promise.then(null, handler3);
|
||||
});
|
||||
promise.then(null, handler2);
|
||||
|
||||
promise.then(null, function () {
|
||||
// Give implementations a bit of extra time to flush their internal queue, if necessary.
|
||||
setTimeout(function () {
|
||||
sinon.assert.callOrder(handler1, handler2, handler3);
|
||||
done();
|
||||
}, 15);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,109 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testFulfilled = require("./helpers/testThreeCases").testFulfilled;
|
||||
var testRejected = require("./helpers/testThreeCases").testRejected;
|
||||
var reasons = require("./helpers/reasons");
|
||||
|
||||
var adapter = global.adapter;
|
||||
var pending = adapter.pending;
|
||||
|
||||
var dummy = { dummy: "dummy" }; // we fulfill or reject with this when we don't intend to test against it
|
||||
var sentinel = { sentinel: "sentinel" }; // a sentinel fulfillment value to test for with strict equality
|
||||
var other = { other: "other" }; // a value we don't want to be strict equal to
|
||||
|
||||
describe("2.2.7: `then` must return a promise: `promise2 = promise1.then(onFulfilled, onRejected)`", function () {
|
||||
specify("is a promise", function () {
|
||||
var promise1 = pending().promise;
|
||||
var promise2 = promise1.then();
|
||||
|
||||
assert(typeof promise2 === "object" || typeof promise2 === "function");
|
||||
assert.notStrictEqual(promise2, null);
|
||||
assert.strictEqual(typeof promise2.then, "function");
|
||||
});
|
||||
|
||||
describe("2.2.7.1: If either `onFulfilled` or `onRejected` returns a value `x`, run the Promise Resolution " +
|
||||
"Procedure `[[Resolve]](promise2, x)`", function () {
|
||||
specify("see separate 3.3 tests", function () { });
|
||||
});
|
||||
|
||||
describe("2.2.7.2: If either `onFulfilled` or `onRejected` throws an exception `e`, `promise2` must be rejected " +
|
||||
"with `e` as the reason.", function () {
|
||||
function testReason(expectedReason, stringRepresentation) {
|
||||
describe("The reason is " + stringRepresentation, function () {
|
||||
testFulfilled(dummy, function (promise1, done) {
|
||||
var promise2 = promise1.then(function onFulfilled() {
|
||||
throw expectedReason;
|
||||
});
|
||||
|
||||
promise2.then(null, function onPromise2Rejected(actualReason) {
|
||||
assert.strictEqual(actualReason, expectedReason);
|
||||
done();
|
||||
});
|
||||
});
|
||||
testRejected(dummy, function (promise1, done) {
|
||||
var promise2 = promise1.then(null, function onRejected() {
|
||||
throw expectedReason;
|
||||
});
|
||||
|
||||
promise2.then(null, function onPromise2Rejected(actualReason) {
|
||||
assert.strictEqual(actualReason, expectedReason);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Object.keys(reasons).forEach(function (stringRepresentation) {
|
||||
testReason(reasons[stringRepresentation], stringRepresentation);
|
||||
});
|
||||
});
|
||||
|
||||
describe("2.2.7.3: If `onFulfilled` is not a function and `promise1` is fulfilled, `promise2` must be fulfilled " +
|
||||
"with the same value.", function () {
|
||||
|
||||
function testNonFunction(nonFunction, stringRepresentation) {
|
||||
describe("`onFulfilled` is " + stringRepresentation, function () {
|
||||
testFulfilled(sentinel, function (promise1, done) {
|
||||
var promise2 = promise1.then(nonFunction);
|
||||
|
||||
promise2.then(function onPromise2Fulfilled(value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
testNonFunction(undefined, "`undefined`");
|
||||
testNonFunction(null, "`null`");
|
||||
testNonFunction(false, "`false`");
|
||||
testNonFunction(5, "`5`");
|
||||
testNonFunction({}, "an object");
|
||||
testNonFunction([function () { return other; }], "an array containing a function");
|
||||
});
|
||||
|
||||
describe("2.2.7.4: If `onRejected` is not a function and `promise1` is rejected, `promise2` must be rejected " +
|
||||
"with the same reason.", function () {
|
||||
|
||||
function testNonFunction(nonFunction, stringRepresentation) {
|
||||
describe("`onRejected` is " + stringRepresentation, function () {
|
||||
testRejected(sentinel, function (promise1, done) {
|
||||
var promise2 = promise1.then(null, nonFunction);
|
||||
|
||||
promise2.then(null, function onPromise2Rejected(reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
testNonFunction(undefined, "`undefined`");
|
||||
testNonFunction(null, "`null`");
|
||||
testNonFunction(false, "`false`");
|
||||
testNonFunction(5, "`5`");
|
||||
testNonFunction({}, "an object");
|
||||
testNonFunction([function () { return other; }], "an array containing a function");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,34 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
|
||||
var adapter = global.adapter;
|
||||
var fulfilled = adapter.fulfilled;
|
||||
var rejected = adapter.rejected;
|
||||
|
||||
var dummy = { dummy: "dummy" }; // we fulfill or reject with this when we don't intend to test against it
|
||||
|
||||
describe("2.3.1: If `promise` and `x` refer to the same object, reject `promise` with a `TypeError' as the reason.",
|
||||
function () {
|
||||
specify("via return from a fulfilled promise", function (done) {
|
||||
var promise = fulfilled(dummy).then(function () {
|
||||
return promise;
|
||||
});
|
||||
|
||||
promise.then(null, function (reason) {
|
||||
assert(reason instanceof adapter.TypeError);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
specify("via return from a rejected promise", function (done) {
|
||||
var promise = rejected(dummy).then(null, function () {
|
||||
return promise;
|
||||
});
|
||||
|
||||
promise.then(null, function (reason) {
|
||||
assert(reason instanceof adapter.TypeError);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,126 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
|
||||
var adapter = global.adapter;
|
||||
var fulfilled = adapter.fulfilled;
|
||||
var rejected = adapter.rejected;
|
||||
var pending = adapter.pending;
|
||||
|
||||
var dummy = { dummy: "dummy" }; // we fulfill or reject with this when we don't intend to test against it
|
||||
var sentinel = { sentinel: "sentinel" }; // a sentinel fulfillment value to test for with strict equality
|
||||
|
||||
function testPromiseResolution(xFactory, test) {
|
||||
specify("via return from a fulfilled promise", function (done) {
|
||||
var promise = fulfilled(dummy).then(function onBasePromiseFulfilled() {
|
||||
return xFactory();
|
||||
});
|
||||
|
||||
test(promise, done);
|
||||
});
|
||||
|
||||
specify("via return from a rejected promise", function (done) {
|
||||
var promise = rejected(dummy).then(null, function onBasePromiseRejected() {
|
||||
return xFactory();
|
||||
});
|
||||
|
||||
test(promise, done);
|
||||
});
|
||||
}
|
||||
|
||||
describe("2.3.2: If `x` is a promise, adopt its state", function () {
|
||||
describe("2.3.2.1: If `x` is pending, `promise` must remain pending until `x` is fulfilled or rejected.",
|
||||
function () {
|
||||
function xFactory() {
|
||||
return pending().promise;
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
var wasFulfilled = false;
|
||||
var wasRejected = false;
|
||||
|
||||
promise.then(
|
||||
function onPromiseFulfilled() {
|
||||
wasFulfilled = true;
|
||||
},
|
||||
function onPromiseRejected() {
|
||||
wasRejected = true;
|
||||
}
|
||||
);
|
||||
|
||||
setTimeout(function () {
|
||||
assert.strictEqual(wasFulfilled, false);
|
||||
assert.strictEqual(wasRejected, false);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
|
||||
describe("2.3.2.2: If/when `x` is fulfilled, fulfill `promise` with the same value.", function () {
|
||||
describe("`x` is already-fulfilled", function () {
|
||||
function xFactory() {
|
||||
return fulfilled(sentinel);
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
promise.then(function onPromiseFulfilled(value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("`x` is eventually-fulfilled", function () {
|
||||
var tuple = null;
|
||||
|
||||
function xFactory() {
|
||||
tuple = pending();
|
||||
setTimeout(function () {
|
||||
tuple.fulfill(sentinel);
|
||||
}, 50);
|
||||
return tuple.promise;
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
promise.then(function onPromiseFulfilled(value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("2.3.2.3: If/when `x` is rejected, reject `promise` with the same reason.", function () {
|
||||
describe("`x` is already-rejected", function () {
|
||||
function xFactory() {
|
||||
return rejected(sentinel);
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
promise.then(null, function onPromiseRejected(reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("`x` is eventually-rejected", function () {
|
||||
var tuple = null;
|
||||
|
||||
function xFactory() {
|
||||
tuple = pending();
|
||||
setTimeout(function () {
|
||||
tuple.reject(sentinel);
|
||||
}, 50);
|
||||
return tuple.promise;
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
promise.then(null, function onPromiseRejected(reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,993 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var thenables = require("./helpers/thenables");
|
||||
var reasons = require("./helpers/reasons");
|
||||
|
||||
var adapter = global.adapter;
|
||||
var fulfilled = adapter.fulfilled;
|
||||
var rejected = adapter.rejected;
|
||||
var pending = adapter.pending;
|
||||
|
||||
var dummy = { dummy: "dummy" }; // we fulfill or reject with this when we don't intend to test against it
|
||||
var sentinel = { sentinel: "sentinel" }; // a sentinel fulfillment value to test for with strict equality
|
||||
var other = { other: "other" }; // a value we don't want to be strict equal to
|
||||
var sentinelArray = [sentinel]; // a sentinel fulfillment value to test when we need an array
|
||||
|
||||
function testPromiseResolution(xFactory, test) {
|
||||
specify("via return from a fulfilled promise", function (done) {
|
||||
var promise = fulfilled(dummy).then(function onBasePromiseFulfilled() {
|
||||
return xFactory();
|
||||
});
|
||||
|
||||
test(promise, done);
|
||||
});
|
||||
|
||||
specify("via return from a rejected promise", function (done) {
|
||||
var promise = rejected(dummy).then(null, function onBasePromiseRejected() {
|
||||
return xFactory();
|
||||
});
|
||||
|
||||
test(promise, done);
|
||||
});
|
||||
}
|
||||
|
||||
function testCallingResolvePromise(yFactory, stringRepresentation, test) {
|
||||
describe("`y` is " + stringRepresentation, function () {
|
||||
describe("`then` calls `resolvePromise` synchronously", function () {
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function (resolvePromise) {
|
||||
resolvePromise(yFactory());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, test);
|
||||
});
|
||||
|
||||
describe("`then` calls `resolvePromise` asynchronously", function () {
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function (resolvePromise) {
|
||||
setTimeout(function () {
|
||||
resolvePromise(yFactory());
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, test);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testCallingRejectPromise(r, stringRepresentation, test) {
|
||||
describe("`r` is " + stringRepresentation, function () {
|
||||
describe("`then` calls `rejectPromise` synchronously", function () {
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function (resolvePromise, rejectPromise) {
|
||||
rejectPromise(r);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, test);
|
||||
});
|
||||
|
||||
describe("`then` calls `rejectPromise` asynchronously", function () {
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function (resolvePromise, rejectPromise) {
|
||||
setTimeout(function () {
|
||||
rejectPromise(r);
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, test);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testCallingResolvePromiseFulfillsWith(yFactory, stringRepresentation, fulfillmentValue) {
|
||||
testCallingResolvePromise(yFactory, stringRepresentation, function (promise, done) {
|
||||
|
||||
promise.then(function onPromiseFulfilled(value) {
|
||||
assert.strictEqual(value, fulfillmentValue);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testCallingResolvePromiseRejectsWith(yFactory, stringRepresentation, rejectionReason) {
|
||||
testCallingResolvePromise(yFactory, stringRepresentation, function (promise, done) {
|
||||
|
||||
promise.then(null, function onPromiseRejected(reason) {
|
||||
assert.strictEqual(reason, rejectionReason);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testCallingRejectPromiseRejectsWith(reason, stringRepresentation) {
|
||||
testCallingRejectPromise(reason, stringRepresentation, function (promise, done) {
|
||||
|
||||
promise.then(null, function onPromiseRejected(rejectionReason) {
|
||||
assert.strictEqual(rejectionReason, reason);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe("2.3.3: Otherwise, if `x` is an object or function,", function () {
|
||||
describe("2.3.3.1: Let `then` be `x.then`", function () {
|
||||
describe("`x` is an object with null prototype", function () {
|
||||
var numberOfTimesThenWasRetrieved = null;
|
||||
|
||||
beforeEach(function () {
|
||||
numberOfTimesThenWasRetrieved = 0;
|
||||
});
|
||||
|
||||
function xFactory() {
|
||||
return Object.create(null, {
|
||||
then: {
|
||||
get: function () {
|
||||
++numberOfTimesThenWasRetrieved;
|
||||
return function thenMethodForX(onFulfilled) {
|
||||
onFulfilled();
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
|
||||
promise.then(function () {
|
||||
assert.strictEqual(numberOfTimesThenWasRetrieved, 1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("`x` is an object with normal Object.prototype", function () {
|
||||
var numberOfTimesThenWasRetrieved = null;
|
||||
|
||||
beforeEach(function () {
|
||||
numberOfTimesThenWasRetrieved = 0;
|
||||
});
|
||||
|
||||
function xFactory() {
|
||||
return Object.create(Object.prototype, {
|
||||
then: {
|
||||
get: function () {
|
||||
++numberOfTimesThenWasRetrieved;
|
||||
return function thenMethodForX(onFulfilled) {
|
||||
onFulfilled();
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
|
||||
promise.then(function () {
|
||||
assert.strictEqual(numberOfTimesThenWasRetrieved, 1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("`x` is a function", function () {
|
||||
var numberOfTimesThenWasRetrieved = null;
|
||||
|
||||
beforeEach(function () {
|
||||
numberOfTimesThenWasRetrieved = 0;
|
||||
});
|
||||
|
||||
function xFactory() {
|
||||
function x() { }
|
||||
|
||||
Object.defineProperty(x, "then", {
|
||||
get: function () {
|
||||
++numberOfTimesThenWasRetrieved;
|
||||
return function thenMethodForX(onFulfilled) {
|
||||
onFulfilled();
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
|
||||
promise.then(function () {
|
||||
assert.strictEqual(numberOfTimesThenWasRetrieved, 1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("2.3.3.2: If retrieving the property `x.then` results in a thrown exception `e`, reject `promise` with " +
|
||||
"`e` as the reason.", function () {
|
||||
function testRejectionViaThrowingGetter(e, stringRepresentation) {
|
||||
function xFactory() {
|
||||
return Object.create(Object.prototype, {
|
||||
then: {
|
||||
get: function () {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
describe("`e` is " + stringRepresentation, function () {
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
|
||||
promise.then(null, function (reason) {
|
||||
assert.strictEqual(reason, e);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Object.keys(reasons).forEach(function (stringRepresentation) {
|
||||
testRejectionViaThrowingGetter(reasons[stringRepresentation], stringRepresentation);
|
||||
});
|
||||
});
|
||||
|
||||
describe("2.3.3.3: If `then` is a function, call it with `x` as `this`, first argument `resolvePromise`, and " +
|
||||
"second argument `rejectPromise`", function () {
|
||||
describe("Calls with `x` as `this` and two function arguments", function () {
|
||||
function xFactory() {
|
||||
var x = {
|
||||
then: function (onFulfilled, onRejected) {
|
||||
assert.strictEqual(this, x);
|
||||
assert.strictEqual(typeof onFulfilled, "function");
|
||||
assert.strictEqual(typeof onRejected, "function");
|
||||
onFulfilled();
|
||||
}
|
||||
};
|
||||
return x;
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
|
||||
promise.then(function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Uses the original value of `then`", function () {
|
||||
var numberOfTimesThenWasRetrieved = null;
|
||||
|
||||
beforeEach(function () {
|
||||
numberOfTimesThenWasRetrieved = 0;
|
||||
});
|
||||
|
||||
function xFactory() {
|
||||
return Object.create(Object.prototype, {
|
||||
then: {
|
||||
get: function () {
|
||||
if (numberOfTimesThenWasRetrieved === 0) {
|
||||
return function (onFulfilled) {
|
||||
onFulfilled();
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
|
||||
promise.then(function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("2.3.3.3.1: If/when `resolvePromise` is called with value `y`, run `[[Resolve]](promise, y)`",
|
||||
function () {
|
||||
describe("`y` is not a thenable", function () {
|
||||
testCallingResolvePromiseFulfillsWith(function () { return undefined; }, "`undefined`", undefined);
|
||||
testCallingResolvePromiseFulfillsWith(function () { return null; }, "`null`", null);
|
||||
testCallingResolvePromiseFulfillsWith(function () { return false; }, "`false`", false);
|
||||
testCallingResolvePromiseFulfillsWith(function () { return 5; }, "`5`", 5);
|
||||
testCallingResolvePromiseFulfillsWith(function () { return sentinel; }, "an object", sentinel);
|
||||
testCallingResolvePromiseFulfillsWith(function () { return sentinelArray; }, "an array", sentinelArray);
|
||||
});
|
||||
|
||||
describe("`y` is a thenable", function () {
|
||||
Object.keys(thenables.fulfilled).forEach(function (stringRepresentation) {
|
||||
function yFactory() {
|
||||
return thenables.fulfilled[stringRepresentation](sentinel);
|
||||
}
|
||||
|
||||
testCallingResolvePromiseFulfillsWith(yFactory, stringRepresentation, sentinel);
|
||||
});
|
||||
|
||||
Object.keys(thenables.rejected).forEach(function (stringRepresentation) {
|
||||
function yFactory() {
|
||||
return thenables.rejected[stringRepresentation](sentinel);
|
||||
}
|
||||
|
||||
testCallingResolvePromiseRejectsWith(yFactory, stringRepresentation, sentinel);
|
||||
});
|
||||
});
|
||||
|
||||
describe("`y` is a thenable for a thenable", function () {
|
||||
Object.keys(thenables.fulfilled).forEach(function (outerStringRepresentation) {
|
||||
var outerThenableFactory = thenables.fulfilled[outerStringRepresentation];
|
||||
|
||||
Object.keys(thenables.fulfilled).forEach(function (innerStringRepresentation) {
|
||||
var innerThenableFactory = thenables.fulfilled[innerStringRepresentation];
|
||||
|
||||
var stringRepresentation = outerStringRepresentation + " for " + innerStringRepresentation;
|
||||
|
||||
function yFactory() {
|
||||
return outerThenableFactory(innerThenableFactory(sentinel));
|
||||
}
|
||||
|
||||
testCallingResolvePromiseFulfillsWith(yFactory, stringRepresentation, sentinel);
|
||||
});
|
||||
|
||||
Object.keys(thenables.rejected).forEach(function (innerStringRepresentation) {
|
||||
var innerThenableFactory = thenables.rejected[innerStringRepresentation];
|
||||
|
||||
var stringRepresentation = outerStringRepresentation + " for " + innerStringRepresentation;
|
||||
|
||||
function yFactory() {
|
||||
return outerThenableFactory(innerThenableFactory(sentinel));
|
||||
}
|
||||
|
||||
testCallingResolvePromiseRejectsWith(yFactory, stringRepresentation, sentinel);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("2.3.3.3.2: If/when `rejectPromise` is called with reason `r`, reject `promise` with `r`",
|
||||
function () {
|
||||
Object.keys(reasons).forEach(function (stringRepresentation) {
|
||||
testCallingRejectPromiseRejectsWith(reasons[stringRepresentation], stringRepresentation);
|
||||
});
|
||||
});
|
||||
|
||||
describe("2.3.3.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 () {
|
||||
describe("calling `resolvePromise` then `rejectPromise`, both synchronously", function () {
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function (resolvePromise, rejectPromise) {
|
||||
resolvePromise(sentinel);
|
||||
rejectPromise(other);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
|
||||
promise.then(function (value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("calling `resolvePromise` synchronously then `rejectPromise` asynchronously", function () {
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function (resolvePromise, rejectPromise) {
|
||||
resolvePromise(sentinel);
|
||||
|
||||
setTimeout(function () {
|
||||
rejectPromise(other);
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
|
||||
promise.then(function (value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("calling `resolvePromise` then `rejectPromise`, both asynchronously", function () {
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function (resolvePromise, rejectPromise) {
|
||||
setTimeout(function () {
|
||||
resolvePromise(sentinel);
|
||||
}, 0);
|
||||
|
||||
setTimeout(function () {
|
||||
rejectPromise(other);
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
|
||||
promise.then(function (value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("calling `resolvePromise` with an asynchronously-fulfilled promise, then calling " +
|
||||
"`rejectPromise`, both synchronously", function () {
|
||||
function xFactory() {
|
||||
var tuple = pending();
|
||||
setTimeout(function () {
|
||||
tuple.fulfill(sentinel);
|
||||
}, 50);
|
||||
|
||||
return {
|
||||
then: function (resolvePromise, rejectPromise) {
|
||||
resolvePromise(tuple.promise);
|
||||
rejectPromise(other);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
|
||||
promise.then(function (value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("calling `resolvePromise` with an asynchronously-rejected promise, then calling " +
|
||||
"`rejectPromise`, both synchronously", function () {
|
||||
function xFactory() {
|
||||
var tuple = pending();
|
||||
setTimeout(function () {
|
||||
tuple.reject(sentinel);
|
||||
}, 50);
|
||||
|
||||
return {
|
||||
then: function (resolvePromise, rejectPromise) {
|
||||
resolvePromise(tuple.promise);
|
||||
rejectPromise(other);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
promise.then(null, function (reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("calling `rejectPromise` then `resolvePromise`, both synchronously", function () {
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function (resolvePromise, rejectPromise) {
|
||||
rejectPromise(sentinel);
|
||||
resolvePromise(other);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
|
||||
promise.then(null, function (reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("calling `rejectPromise` synchronously then `resolvePromise` asynchronously", function () {
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function (resolvePromise, rejectPromise) {
|
||||
rejectPromise(sentinel);
|
||||
|
||||
setTimeout(function () {
|
||||
resolvePromise(other);
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
|
||||
promise.then(null, function (reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("calling `rejectPromise` then `resolvePromise`, both asynchronously", function () {
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function (resolvePromise, rejectPromise) {
|
||||
setTimeout(function () {
|
||||
rejectPromise(sentinel);
|
||||
}, 0);
|
||||
|
||||
setTimeout(function () {
|
||||
resolvePromise(other);
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
|
||||
promise.then(null, function (reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("calling `resolvePromise` twice synchronously", function () {
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function (resolvePromise) {
|
||||
resolvePromise(sentinel);
|
||||
resolvePromise(other);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
|
||||
promise.then(function (value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("calling `resolvePromise` twice, first synchronously then asynchronously", function () {
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function (resolvePromise) {
|
||||
resolvePromise(sentinel);
|
||||
|
||||
setTimeout(function () {
|
||||
resolvePromise(other);
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
|
||||
promise.then(function (value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("calling `resolvePromise` twice, both times asynchronously", function () {
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function (resolvePromise) {
|
||||
setTimeout(function () {
|
||||
resolvePromise(sentinel);
|
||||
}, 0);
|
||||
|
||||
setTimeout(function () {
|
||||
resolvePromise(other);
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
|
||||
promise.then(function (value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("calling `resolvePromise` with an asynchronously-fulfilled promise, then calling it again, both " +
|
||||
"times synchronously", function () {
|
||||
function xFactory() {
|
||||
var tuple = pending();
|
||||
setTimeout(function () {
|
||||
tuple.fulfill(sentinel);
|
||||
}, 50);
|
||||
|
||||
return {
|
||||
then: function (resolvePromise) {
|
||||
resolvePromise(tuple.promise);
|
||||
resolvePromise(other);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
|
||||
promise.then(function (value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("calling `resolvePromise` with an asynchronously-rejected promise, then calling it again, both " +
|
||||
"times synchronously", function () {
|
||||
function xFactory() {
|
||||
var tuple = pending();
|
||||
setTimeout(function () {
|
||||
tuple.reject(sentinel);
|
||||
}, 50);
|
||||
|
||||
return {
|
||||
then: function (resolvePromise) {
|
||||
resolvePromise(tuple.promise);
|
||||
resolvePromise(other);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
|
||||
promise.then(null, function (reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("calling `rejectPromise` twice synchronously", function () {
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function (resolvePromise, rejectPromise) {
|
||||
rejectPromise(sentinel);
|
||||
rejectPromise(other);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
promise.then(null, function (reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("calling `rejectPromise` twice, first synchronously then asynchronously", function () {
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function (resolvePromise, rejectPromise) {
|
||||
rejectPromise(sentinel);
|
||||
|
||||
setTimeout(function () {
|
||||
resolvePromise(other);
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
promise.then(null, function (reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("calling `rejectPromise` twice, both times asynchronously", function () {
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function (resolvePromise, rejectPromise) {
|
||||
setTimeout(function () {
|
||||
rejectPromise(sentinel);
|
||||
}, 0);
|
||||
|
||||
setTimeout(function () {
|
||||
resolvePromise(other);
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
promise.then(null, function (reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("saving and abusing `resolvePromise` and `rejectPromise`", function () {
|
||||
var savedResolvePromise, savedRejectPromise;
|
||||
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function (resolvePromise, rejectPromise) {
|
||||
savedResolvePromise = resolvePromise;
|
||||
savedRejectPromise = rejectPromise;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
savedResolvePromise = null;
|
||||
savedRejectPromise = null;
|
||||
});
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
var timesFulfilled = 0;
|
||||
var timesRejected = 0;
|
||||
|
||||
promise.then(
|
||||
function () {
|
||||
++timesFulfilled;
|
||||
},
|
||||
function () {
|
||||
++timesRejected;
|
||||
}
|
||||
);
|
||||
|
||||
if (savedResolvePromise && savedRejectPromise) {
|
||||
savedResolvePromise(dummy);
|
||||
savedResolvePromise(dummy);
|
||||
savedRejectPromise(dummy);
|
||||
savedRejectPromise(dummy);
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
savedResolvePromise(dummy);
|
||||
savedResolvePromise(dummy);
|
||||
savedRejectPromise(dummy);
|
||||
savedRejectPromise(dummy);
|
||||
}, 4);
|
||||
|
||||
setTimeout(function () {
|
||||
assert.strictEqual(timesFulfilled, 1);
|
||||
assert.strictEqual(timesRejected, 0);
|
||||
done();
|
||||
}, 60);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("2.3.3.3.4: If calling `then` throws an exception `e`,", function () {
|
||||
describe("2.3.3.3.4.1: If `resolvePromise` or `rejectPromise` have been called, ignore it.", function () {
|
||||
describe("`resolvePromise` was called with a non-thenable", function () {
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function (resolvePromise) {
|
||||
resolvePromise(sentinel);
|
||||
throw other;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
promise.then(function (value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("`resolvePromise` was called with an asynchronously-fulfilled promise", function () {
|
||||
function xFactory() {
|
||||
var tuple = pending();
|
||||
setTimeout(function () {
|
||||
tuple.fulfill(sentinel);
|
||||
}, 50);
|
||||
|
||||
return {
|
||||
then: function (resolvePromise) {
|
||||
resolvePromise(tuple.promise);
|
||||
throw other;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
promise.then(function (value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("`resolvePromise` was called with an asynchronously-rejected promise", function () {
|
||||
function xFactory() {
|
||||
var tuple = pending();
|
||||
setTimeout(function () {
|
||||
tuple.reject(sentinel);
|
||||
}, 50);
|
||||
|
||||
return {
|
||||
then: function (resolvePromise) {
|
||||
resolvePromise(tuple.promise);
|
||||
throw other;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
promise.then(null, function (reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("`rejectPromise` was called", function () {
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function (resolvePromise, rejectPromise) {
|
||||
rejectPromise(sentinel);
|
||||
throw other;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
promise.then(null, function (reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("`resolvePromise` then `rejectPromise` were called", function () {
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function (resolvePromise, rejectPromise) {
|
||||
resolvePromise(sentinel);
|
||||
rejectPromise(other);
|
||||
throw other;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
promise.then(function (value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("`rejectPromise` then `resolvePromise` were called", function () {
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function (resolvePromise, rejectPromise) {
|
||||
rejectPromise(sentinel);
|
||||
resolvePromise(other);
|
||||
throw other;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
promise.then(null, function (reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("2.3.3.3.4.2: Otherwise, reject `promise` with `e` as the reason.", function () {
|
||||
describe("straightforward case", function () {
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function () {
|
||||
throw sentinel;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
promise.then(null, function (reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("`resolvePromise` is called asynchronously before the `throw`", function () {
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function (resolvePromise) {
|
||||
setTimeout(function () {
|
||||
resolvePromise(other);
|
||||
}, 0);
|
||||
throw sentinel;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
promise.then(null, function (reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("`rejectPromise` is called asynchronously before the `throw`", function () {
|
||||
function xFactory() {
|
||||
return {
|
||||
then: function (resolvePromise, rejectPromise) {
|
||||
setTimeout(function () {
|
||||
rejectPromise(other);
|
||||
}, 0);
|
||||
throw sentinel;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
promise.then(null, function (reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("2.3.3.4: If `then` is not a function, fulfill promise with `x`", function () {
|
||||
function testFulfillViaNonFunction(then, stringRepresentation) {
|
||||
var x = null;
|
||||
|
||||
beforeEach(function () {
|
||||
x = { then: then };
|
||||
});
|
||||
|
||||
function xFactory() {
|
||||
return x;
|
||||
}
|
||||
|
||||
describe("`then` is " + stringRepresentation, function () {
|
||||
testPromiseResolution(xFactory, function (promise, done) {
|
||||
promise.then(function (value) {
|
||||
assert.strictEqual(value, x);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
testFulfillViaNonFunction(5, "`5`");
|
||||
testFulfillViaNonFunction({}, "an object");
|
||||
testFulfillViaNonFunction([function () { }], "an array containing a function");
|
||||
testFulfillViaNonFunction(/a-b/i, "a regular expression");
|
||||
testFulfillViaNonFunction(Object.create(Function.prototype), "an object inheriting from `Function.prototype`");
|
||||
|
||||
|
||||
|
||||
});
|
||||
});
|
|
@ -0,0 +1,69 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testFulfilled = require("./helpers/testThreeCases").testFulfilled;
|
||||
var testRejected = require("./helpers/testThreeCases").testRejected;
|
||||
|
||||
var dummy = { dummy: "dummy" }; // we fulfill or reject with this when we don't intend to test against it
|
||||
|
||||
describe("2.3.4: If `x` is not an object or function, fulfill `promise` with `x`", function () {
|
||||
function testValue(expectedValue, stringRepresentation, beforeEachHook, afterEachHook) {
|
||||
describe("The value is " + stringRepresentation, function () {
|
||||
if (typeof beforeEachHook === "function") {
|
||||
beforeEach(beforeEachHook);
|
||||
}
|
||||
if (typeof afterEachHook === "function") {
|
||||
afterEach(afterEachHook);
|
||||
}
|
||||
|
||||
testFulfilled(dummy, function (promise1, done) {
|
||||
var promise2 = promise1.then(function onFulfilled() {
|
||||
return expectedValue;
|
||||
});
|
||||
|
||||
promise2.then(function onPromise2Fulfilled(actualValue) {
|
||||
assert.strictEqual(actualValue, expectedValue);
|
||||
done();
|
||||
});
|
||||
});
|
||||
testRejected(dummy, function (promise1, done) {
|
||||
var promise2 = promise1.then(null, function onRejected() {
|
||||
return expectedValue;
|
||||
});
|
||||
|
||||
promise2.then(function onPromise2Fulfilled(actualValue) {
|
||||
assert.strictEqual(actualValue, expectedValue);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
testValue(undefined, "`undefined`");
|
||||
testValue(null, "`null`");
|
||||
testValue(false, "`false`");
|
||||
testValue(true, "`true`");
|
||||
testValue(0, "`0`");
|
||||
|
||||
testValue(
|
||||
true,
|
||||
"`true` with `Boolean.prototype` modified to have a `then` method",
|
||||
function () {
|
||||
Boolean.prototype.then = function () {};
|
||||
},
|
||||
function () {
|
||||
delete Boolean.prototype.then;
|
||||
}
|
||||
);
|
||||
|
||||
testValue(
|
||||
1,
|
||||
"`1` with `Number.prototype` modified to have a `then` method",
|
||||
function () {
|
||||
Number.prototype.then = function () {};
|
||||
},
|
||||
function () {
|
||||
delete Number.prototype.then;
|
||||
}
|
||||
);
|
||||
});
|
|
@ -0,0 +1,41 @@
|
|||
"use strict";
|
||||
|
||||
var adapter = global.adapter;
|
||||
var fulfilled = adapter.fulfilled;
|
||||
var rejected = adapter.rejected;
|
||||
|
||||
var dummy = { dummy: "dummy" }; // we fulfill or reject with this when we don't intend to test against it
|
||||
|
||||
describe("3.2.1: Both `onFulfilled` and `onRejected` are optional arguments.", function () {
|
||||
describe("3.2.1.1: If `onFulfilled` is not a function, it must be ignored.", function () {
|
||||
function testNonFunction(nonFunction, stringRepresentation) {
|
||||
specify("`onFulfilled` is " + stringRepresentation, function (done) {
|
||||
rejected(dummy).then(nonFunction, function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
testNonFunction(undefined, "`undefined`");
|
||||
testNonFunction(null, "`null`");
|
||||
testNonFunction(false, "`false`");
|
||||
testNonFunction(5, "`5`");
|
||||
testNonFunction({}, "an object");
|
||||
});
|
||||
|
||||
describe("3.2.1.2: If `onRejected` is not a function, it must be ignored.", function () {
|
||||
function testNonFunction(nonFunction, stringRepresentation) {
|
||||
specify("`onRejected` is " + stringRepresentation, function (done) {
|
||||
fulfilled(dummy).then(function () {
|
||||
done();
|
||||
}, nonFunction);
|
||||
});
|
||||
}
|
||||
|
||||
testNonFunction(undefined, "`undefined`");
|
||||
testNonFunction(null, "`null`");
|
||||
testNonFunction(false, "`false`");
|
||||
testNonFunction(5, "`5`");
|
||||
testNonFunction({}, "an object");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,187 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testFulfilled = require("./helpers/testThreeCases").testFulfilled;
|
||||
var testRejected = require("./helpers/testThreeCases").testRejected;
|
||||
|
||||
var adapter = global.adapter;
|
||||
var fulfilled = adapter.fulfilled;
|
||||
var pending = adapter.pending;
|
||||
|
||||
var dummy = { dummy: "dummy" }; // we fulfill or reject with this when we don't intend to test against it
|
||||
var sentinel = { sentinel: "sentinel" }; // a sentinel fulfillment value to test for with strict equality
|
||||
|
||||
describe("3.2.2: If `onFulfilled` is a function,", function () {
|
||||
describe("3.2.2.1: it must be called after `promise` is fulfilled, with `promise`’s fulfillment value as its " +
|
||||
"first argument.", function () {
|
||||
testFulfilled(sentinel, function (promise, done) {
|
||||
promise.then(function onFulfilled(value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("3.2.2.2: it must not be called more than once.", function () {
|
||||
specify("already-fulfilled", function (done) {
|
||||
var timesCalled = 0;
|
||||
|
||||
fulfilled(dummy).then(function onFulfilled() {
|
||||
assert.strictEqual(++timesCalled, 1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
specify("trying to fulfill a pending promise more than once, immediately", function (done) {
|
||||
var tuple = pending();
|
||||
var timesCalled = 0;
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
assert.strictEqual(++timesCalled, 1);
|
||||
done();
|
||||
});
|
||||
|
||||
tuple.fulfill(dummy);
|
||||
tuple.fulfill(dummy);
|
||||
});
|
||||
|
||||
specify("trying to fulfill a pending promise more than once, delayed", function (done) {
|
||||
var tuple = pending();
|
||||
var timesCalled = 0;
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
assert.strictEqual(++timesCalled, 1);
|
||||
done();
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.fulfill(dummy);
|
||||
tuple.fulfill(dummy);
|
||||
}, 50);
|
||||
});
|
||||
|
||||
specify("trying to fulfill a pending promise more than once, immediately then delayed", function (done) {
|
||||
var tuple = pending();
|
||||
var timesCalled = 0;
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
assert.strictEqual(++timesCalled, 1);
|
||||
done();
|
||||
});
|
||||
|
||||
tuple.fulfill(dummy);
|
||||
setTimeout(function () {
|
||||
tuple.fulfill(dummy);
|
||||
}, 50);
|
||||
});
|
||||
|
||||
specify("when multiple `then` calls are made, spaced apart in time", function (done) {
|
||||
var tuple = pending();
|
||||
var timesCalled = [0, 0, 0];
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
assert.strictEqual(++timesCalled[0], 1);
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
assert.strictEqual(++timesCalled[1], 1);
|
||||
});
|
||||
}, 50);
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
assert.strictEqual(++timesCalled[2], 1);
|
||||
done();
|
||||
});
|
||||
}, 100);
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.fulfill(dummy);
|
||||
}, 150);
|
||||
});
|
||||
|
||||
specify("when `then` is interleaved with fulfillment", function (done) {
|
||||
var tuple = pending();
|
||||
var timesCalled = [0, 0];
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
assert.strictEqual(++timesCalled[0], 1);
|
||||
});
|
||||
|
||||
tuple.fulfill(dummy);
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
assert.strictEqual(++timesCalled[1], 1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("3.2.2.3: it must not be called if `onRejected` has been called.", function () {
|
||||
testRejected(dummy, function (promise, done) {
|
||||
var onRejectedCalled = false;
|
||||
|
||||
promise.then(function onFulfilled() {
|
||||
assert.strictEqual(onRejectedCalled, false);
|
||||
done();
|
||||
}, function onRejected() {
|
||||
onRejectedCalled = true;
|
||||
});
|
||||
|
||||
setTimeout(function(){done();}, 100);
|
||||
});
|
||||
|
||||
specify("trying to reject then immediately fulfill", function (done) {
|
||||
var tuple = pending();
|
||||
var onRejectedCalled = false;
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
assert.strictEqual(onRejectedCalled, false);
|
||||
done();
|
||||
}, function onRejected() {
|
||||
onRejectedCalled = true;
|
||||
});
|
||||
|
||||
tuple.reject(dummy);
|
||||
tuple.fulfill(dummy);
|
||||
setTimeout(function(){done();}, 100);
|
||||
});
|
||||
|
||||
specify("trying to reject then fulfill, delayed", function (done) {
|
||||
var tuple = pending();
|
||||
var onRejectedCalled = false;
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
assert.strictEqual(onRejectedCalled, false);
|
||||
done();
|
||||
}, function onRejected() {
|
||||
onRejectedCalled = true;
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.reject(dummy);
|
||||
tuple.fulfill(dummy);
|
||||
}, 50);
|
||||
setTimeout(function(){done();}, 100);
|
||||
});
|
||||
|
||||
specify("trying to reject immediately then fulfill delayed", function (done) {
|
||||
var tuple = pending();
|
||||
var onRejectedCalled = false;
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
assert.strictEqual(onRejectedCalled, false);
|
||||
done();
|
||||
}, function onRejected() {
|
||||
onRejectedCalled = true;
|
||||
});
|
||||
|
||||
tuple.reject(dummy);
|
||||
setTimeout(function () {
|
||||
tuple.fulfill(dummy);
|
||||
}, 50);
|
||||
setTimeout(function(){done();}, 100);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,187 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testFulfilled = require("./helpers/testThreeCases").testFulfilled;
|
||||
var testRejected = require("./helpers/testThreeCases").testRejected;
|
||||
|
||||
var adapter = global.adapter;
|
||||
var rejected = adapter.rejected;
|
||||
var pending = adapter.pending;
|
||||
|
||||
var dummy = { dummy: "dummy" }; // we fulfill or reject with this when we don't intend to test against it
|
||||
var sentinel = { sentinel: "sentinel" }; // a sentinel fulfillment value to test for with strict equality
|
||||
|
||||
describe("3.2.3: If `onRejected` is a function,", function () {
|
||||
describe("3.2.3.1: it must be called after `promise` is rejected, with `promise`’s rejection reason as its " +
|
||||
"first argument.", function () {
|
||||
testRejected(sentinel, function (promise, done) {
|
||||
promise.then(null, function onRejected(reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("3.2.3.2: it must not be called more than once.", function () {
|
||||
specify("already-rejected", function (done) {
|
||||
var timesCalled = 0;
|
||||
|
||||
rejected(dummy).then(null, function onRejected() {
|
||||
assert.strictEqual(++timesCalled, 1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
specify("trying to reject a pending promise more than once, immediately", function (done) {
|
||||
var tuple = pending();
|
||||
var timesCalled = 0;
|
||||
|
||||
tuple.promise.then(null, function onRejected() {
|
||||
assert.strictEqual(++timesCalled, 1);
|
||||
done();
|
||||
});
|
||||
|
||||
tuple.reject(dummy);
|
||||
tuple.reject(dummy);
|
||||
});
|
||||
|
||||
specify("trying to reject a pending promise more than once, delayed", function (done) {
|
||||
var tuple = pending();
|
||||
var timesCalled = 0;
|
||||
|
||||
tuple.promise.then(null, function onRejected() {
|
||||
assert.strictEqual(++timesCalled, 1);
|
||||
done();
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.reject(dummy);
|
||||
tuple.reject(dummy);
|
||||
}, 50);
|
||||
});
|
||||
|
||||
specify("trying to reject a pending promise more than once, immediately then delayed", function (done) {
|
||||
var tuple = pending();
|
||||
var timesCalled = 0;
|
||||
|
||||
tuple.promise.then(null, function onRejected() {
|
||||
assert.strictEqual(++timesCalled, 1);
|
||||
done();
|
||||
});
|
||||
|
||||
tuple.reject(dummy);
|
||||
setTimeout(function () {
|
||||
tuple.reject(dummy);
|
||||
}, 50);
|
||||
});
|
||||
|
||||
specify("when multiple `then` calls are made, spaced apart in time", function (done) {
|
||||
var tuple = pending();
|
||||
var timesCalled = [0, 0, 0];
|
||||
|
||||
tuple.promise.then(null, function onRejected() {
|
||||
assert.strictEqual(++timesCalled[0], 1);
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.promise.then(null, function onRejected() {
|
||||
assert.strictEqual(++timesCalled[1], 1);
|
||||
});
|
||||
}, 50);
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.promise.then(null, function onRejected() {
|
||||
assert.strictEqual(++timesCalled[2], 1);
|
||||
done();
|
||||
});
|
||||
}, 100);
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.reject(dummy);
|
||||
}, 150);
|
||||
});
|
||||
|
||||
specify("when `then` is interleaved with rejection", function (done) {
|
||||
var tuple = pending();
|
||||
var timesCalled = [0, 0];
|
||||
|
||||
tuple.promise.then(null, function onRejected() {
|
||||
assert.strictEqual(++timesCalled[0], 1);
|
||||
});
|
||||
|
||||
tuple.reject(dummy);
|
||||
|
||||
tuple.promise.then(null, function onRejected() {
|
||||
assert.strictEqual(++timesCalled[1], 1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("3.2.3.3: it must not be called if `onFulfilled` has been called.", function () {
|
||||
testFulfilled(dummy, function (promise, done) {
|
||||
var onFulfilledCalled = false;
|
||||
|
||||
promise.then(function onFulfilled() {
|
||||
onFulfilledCalled = true;
|
||||
}, function onRejected() {
|
||||
assert.strictEqual(onFulfilledCalled, false);
|
||||
done();
|
||||
});
|
||||
|
||||
setTimeout(function(){done();}, 100);
|
||||
});
|
||||
|
||||
specify("trying to fulfill then immediately reject", function (done) {
|
||||
var tuple = pending();
|
||||
var onFulfilledCalled = false;
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
onFulfilledCalled = true;
|
||||
}, function onRejected() {
|
||||
assert.strictEqual(onFulfilledCalled, false);
|
||||
done();
|
||||
});
|
||||
|
||||
tuple.fulfill(dummy);
|
||||
tuple.reject(dummy);
|
||||
setTimeout(function(){done();}, 100);
|
||||
});
|
||||
|
||||
specify("trying to fulfill then reject, delayed", function (done) {
|
||||
var tuple = pending();
|
||||
var onFulfilledCalled = false;
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
onFulfilledCalled = true;
|
||||
}, function onRejected() {
|
||||
assert.strictEqual(onFulfilledCalled, false);
|
||||
done();
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
tuple.fulfill(dummy);
|
||||
tuple.reject(dummy);
|
||||
}, 50);
|
||||
setTimeout(function(){done();}, 100);
|
||||
});
|
||||
|
||||
specify("trying to fulfill immediately then reject delayed", function (done) {
|
||||
var tuple = pending();
|
||||
var onFulfilledCalled = false;
|
||||
|
||||
tuple.promise.then(function onFulfilled() {
|
||||
onFulfilledCalled = true;
|
||||
}, function onRejected() {
|
||||
assert.strictEqual(onFulfilledCalled, false);
|
||||
done();
|
||||
});
|
||||
|
||||
tuple.fulfill(dummy);
|
||||
setTimeout(function () {
|
||||
tuple.reject(dummy);
|
||||
}, 50);
|
||||
setTimeout(function(){done();}, 100);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,31 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testFulfilled = require("./helpers/testThreeCases").testFulfilled;
|
||||
var testRejected = require("./helpers/testThreeCases").testRejected;
|
||||
|
||||
var dummy = { dummy: "dummy" }; // we fulfill or reject with this when we don't intend to test against it
|
||||
|
||||
describe("3.2.4: `then` must return before `onFulfilled` or `onRejected` is called", function () {
|
||||
testFulfilled(dummy, function (promise, done) {
|
||||
var thenHasReturned = false;
|
||||
|
||||
promise.then(function onFulfilled() {
|
||||
assert(thenHasReturned);
|
||||
done();
|
||||
});
|
||||
|
||||
thenHasReturned = true;
|
||||
});
|
||||
|
||||
testRejected(dummy, function (promise, done) {
|
||||
var thenHasReturned = false;
|
||||
|
||||
promise.then(null, function onRejected() {
|
||||
assert(thenHasReturned);
|
||||
done();
|
||||
});
|
||||
|
||||
thenHasReturned = true;
|
||||
});
|
||||
});
|
|
@ -0,0 +1,257 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var sinon = require("sinon");
|
||||
var testFulfilled = require("./helpers/testThreeCases").testFulfilled;
|
||||
var testRejected = require("./helpers/testThreeCases").testRejected;
|
||||
|
||||
var dummy = { dummy: "dummy" }; // we fulfill or reject with this when we don't intend to test against it
|
||||
var other = { other: "other" }; // a value we don't want to be strict equal to
|
||||
var sentinel = { sentinel: "sentinel" }; // a sentinel fulfillment value to test for with strict equality
|
||||
var sentinel2 = { sentinel2: "sentinel2" };
|
||||
var sentinel3 = { sentinel3: "sentinel3" };
|
||||
|
||||
function callbackAggregator(times, ultimateCallback) {
|
||||
var soFar = 0;
|
||||
return function () {
|
||||
if (++soFar === times) {
|
||||
ultimateCallback();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
describe("3.2.5: `then` may be called multiple times on the same promise.", function () {
|
||||
describe("3.2.5.1: If/when `promise` is fulfilled, respective `onFulfilled` callbacks must execute in the order " +
|
||||
"of their originating calls to `then`.", function () {
|
||||
describe("multiple boring fulfillment handlers", function () {
|
||||
testFulfilled(sentinel, function (promise, done) {
|
||||
var handler1 = sinon.stub().returns(other);
|
||||
var handler2 = sinon.stub().returns(other);
|
||||
var handler3 = sinon.stub().returns(other);
|
||||
|
||||
var spy = sinon.spy();
|
||||
promise.then(handler1, spy);
|
||||
promise.then(handler2, spy);
|
||||
promise.then(handler3, spy);
|
||||
|
||||
promise.then(function (value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
|
||||
sinon.assert.calledWith(handler1, sinon.match.same(sentinel));
|
||||
sinon.assert.calledWith(handler2, sinon.match.same(sentinel));
|
||||
sinon.assert.calledWith(handler3, sinon.match.same(sentinel));
|
||||
sinon.assert.notCalled(spy);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("multiple fulfillment handlers, one of which throws", function () {
|
||||
testFulfilled(sentinel, function (promise, done) {
|
||||
var handler1 = sinon.stub().returns(other);
|
||||
var handler2 = sinon.stub().throws(other);
|
||||
var handler3 = sinon.stub().returns(other);
|
||||
|
||||
var spy = sinon.spy();
|
||||
promise.then(handler1, spy);
|
||||
promise.then(handler2, spy).caught(function(){});
|
||||
promise.then(handler3, spy);
|
||||
|
||||
promise.then(function (value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
|
||||
sinon.assert.calledWith(handler1, sinon.match.same(sentinel));
|
||||
sinon.assert.calledWith(handler2, sinon.match.same(sentinel));
|
||||
sinon.assert.calledWith(handler3, sinon.match.same(sentinel));
|
||||
sinon.assert.notCalled(spy);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("results in multiple branching chains with their own fulfillment values", function () {
|
||||
testFulfilled(dummy, function (promise, done) {
|
||||
var semiDone = callbackAggregator(3, done);
|
||||
|
||||
promise.then(function () {
|
||||
return sentinel;
|
||||
}).then(function (value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
semiDone();
|
||||
});
|
||||
|
||||
promise.then(function () {
|
||||
throw sentinel2;
|
||||
}).then(null, function (reason) {
|
||||
assert.strictEqual(reason, sentinel2);
|
||||
semiDone();
|
||||
});
|
||||
|
||||
promise.then(function () {
|
||||
return sentinel3;
|
||||
}).then(function (value) {
|
||||
assert.strictEqual(value, sentinel3);
|
||||
semiDone();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("`onFulfilled` handlers are called in the original order", function () {
|
||||
testFulfilled(dummy, function (promise, done) {
|
||||
var handler1 = sinon.spy(function handler1() {});
|
||||
var handler2 = sinon.spy(function handler2() {});
|
||||
var handler3 = sinon.spy(function handler3() {});
|
||||
|
||||
promise.then(handler1);
|
||||
promise.then(handler2);
|
||||
promise.then(handler3);
|
||||
|
||||
promise.then(function () {
|
||||
sinon.assert.callOrder(handler1, handler2, handler3);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe("even when one handler is added inside another handler", function () {
|
||||
testFulfilled(dummy, function (promise, done) {
|
||||
var handler1 = sinon.spy(function handler1() {});
|
||||
var handler2 = sinon.spy(function handler2() {});
|
||||
var handler3 = sinon.spy(function handler3() {});
|
||||
|
||||
promise.then(function () {
|
||||
handler1();
|
||||
promise.then(handler3);
|
||||
});
|
||||
promise.then(handler2);
|
||||
|
||||
promise.then(function () {
|
||||
// Give implementations a bit of extra time to flush their internal queue, if necessary.
|
||||
setTimeout(function () {
|
||||
sinon.assert.callOrder(handler1, handler2, handler3);
|
||||
done();
|
||||
}, 15);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("3.2.5.2: If/when `promise` is rejected, respective `onRejected` callbacks must execute in the order " +
|
||||
"of their originating calls to `then`.", function () {
|
||||
describe("multiple boring rejection handlers", function () {
|
||||
testRejected(sentinel, function (promise, done) {
|
||||
var handler1 = sinon.stub().returns(other);
|
||||
var handler2 = sinon.stub().returns(other);
|
||||
var handler3 = sinon.stub().returns(other);
|
||||
|
||||
var spy = sinon.spy();
|
||||
promise.then(spy, handler1);
|
||||
promise.then(spy, handler2);
|
||||
promise.then(spy, handler3);
|
||||
|
||||
promise.then(null, function (reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
|
||||
sinon.assert.calledWith(handler1, sinon.match.same(sentinel));
|
||||
sinon.assert.calledWith(handler2, sinon.match.same(sentinel));
|
||||
sinon.assert.calledWith(handler3, sinon.match.same(sentinel));
|
||||
sinon.assert.notCalled(spy);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("multiple rejection handlers, one of which throws", function () {
|
||||
testRejected(sentinel, function (promise, done) {
|
||||
var handler1 = sinon.stub().returns(other);
|
||||
var handler2 = sinon.stub().throws(other);
|
||||
var handler3 = sinon.stub().returns(other);
|
||||
|
||||
var spy = sinon.spy();
|
||||
promise.then(spy, handler1);
|
||||
promise.then(spy, handler2).caught(function(){});
|
||||
promise.then(spy, handler3);
|
||||
|
||||
promise.then(null, function (reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
|
||||
sinon.assert.calledWith(handler1, sinon.match.same(sentinel));
|
||||
sinon.assert.calledWith(handler2, sinon.match.same(sentinel));
|
||||
sinon.assert.calledWith(handler3, sinon.match.same(sentinel));
|
||||
sinon.assert.notCalled(spy);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("results in multiple branching chains with their own fulfillment values", function () {
|
||||
testRejected(sentinel, function (promise, done) {
|
||||
var semiDone = callbackAggregator(3, done);
|
||||
|
||||
promise.then(null, function () {
|
||||
return sentinel;
|
||||
}).then(function (value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
semiDone();
|
||||
});
|
||||
|
||||
promise.then(null, function () {
|
||||
throw sentinel2;
|
||||
}).then(null, function (reason) {
|
||||
assert.strictEqual(reason, sentinel2);
|
||||
semiDone();
|
||||
});
|
||||
|
||||
promise.then(null, function () {
|
||||
return sentinel3;
|
||||
}).then(function (value) {
|
||||
assert.strictEqual(value, sentinel3);
|
||||
semiDone();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("`onRejected` handlers are called in the original order", function () {
|
||||
testRejected(dummy, function (promise, done) {
|
||||
var handler1 = sinon.spy(function handler1() {});
|
||||
var handler2 = sinon.spy(function handler2() {});
|
||||
var handler3 = sinon.spy(function handler3() {});
|
||||
|
||||
promise.then(null, handler1);
|
||||
promise.then(null, handler2);
|
||||
promise.then(null, handler3);
|
||||
|
||||
promise.then(null, function () {
|
||||
sinon.assert.callOrder(handler1, handler2, handler3);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe("even when one handler is added inside another handler", function () {
|
||||
testRejected(dummy, function (promise, done) {
|
||||
var handler1 = sinon.spy(function handler1() {});
|
||||
var handler2 = sinon.spy(function handler2() {});
|
||||
var handler3 = sinon.spy(function handler3() {});
|
||||
|
||||
promise.then(null, function () {
|
||||
handler1();
|
||||
promise.then(null, handler3);
|
||||
});
|
||||
promise.then(null, handler2);
|
||||
|
||||
promise.then(null, function () {
|
||||
// Give implementations a bit of extra time to flush their internal queue, if necessary.
|
||||
setTimeout(function () {
|
||||
sinon.assert.callOrder(handler1, handler2, handler3);
|
||||
done();
|
||||
}, 15);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,322 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testFulfilled = require("./helpers/testThreeCases").testFulfilled;
|
||||
var testRejected = require("./helpers/testThreeCases").testRejected;
|
||||
|
||||
var adapter = global.adapter;
|
||||
var fulfilled = adapter.fulfilled;
|
||||
var rejected = adapter.rejected;
|
||||
var pending = adapter.pending;
|
||||
|
||||
var dummy = { dummy: "dummy" }; // we fulfill or reject with this when we don't intend to test against it
|
||||
var sentinel = { sentinel: "sentinel" }; // a sentinel fulfillment value to test for with strict equality
|
||||
var other = { other: "other" }; // a value we don't want to be strict equal to
|
||||
|
||||
describe("3.2.6: `then` must return a promise: `promise2 = promise1.then(onFulfilled, onRejected)`", function () {
|
||||
specify("is a promise", function () {
|
||||
var promise1 = pending().promise;
|
||||
var promise2 = promise1.then();
|
||||
|
||||
assert(typeof promise2 === "object" || typeof promise2 === "function");
|
||||
assert.notStrictEqual(promise2, null);
|
||||
assert.strictEqual(typeof promise2.then, "function");
|
||||
});
|
||||
|
||||
describe("3.2.6.1: If either `onFulfilled` or `onRejected` returns a value that is not a promise, `promise2` " +
|
||||
"must be fulfilled with that value.", function () {
|
||||
function testValue(expectedValue, stringRepresentation) {
|
||||
describe("The value is " + stringRepresentation, function () {
|
||||
testFulfilled(dummy, function (promise1, done) {
|
||||
var promise2 = promise1.then(function onFulfilled() {
|
||||
return expectedValue;
|
||||
});
|
||||
|
||||
promise2.then(function onPromise2Fulfilled(actualValue) {
|
||||
assert.strictEqual(actualValue, expectedValue);
|
||||
done();
|
||||
});
|
||||
});
|
||||
testRejected(dummy, function (promise1, done) {
|
||||
var promise2 = promise1.then(null, function onRejected() {
|
||||
return expectedValue;
|
||||
});
|
||||
|
||||
promise2.then(function onPromise2Fulfilled(actualValue) {
|
||||
assert.strictEqual(actualValue, expectedValue);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
testValue(undefined, "`undefined`");
|
||||
testValue(null, "`null`");
|
||||
testValue(false, "`false`");
|
||||
testValue(0, "`0`");
|
||||
testValue(new Error(), "an error");
|
||||
testValue(new Date(), "a date");
|
||||
testValue({}, "an object");
|
||||
testValue({ then: 5 }, "an object with a non-function `then` property");
|
||||
});
|
||||
|
||||
describe("3.2.6.2: If either `onFulfilled` or `onRejected` throws an exception, `promise2` " +
|
||||
"must be rejected with the thrown exception as the reason.", function () {
|
||||
function testReason(expectedReason, stringRepresentation) {
|
||||
describe("The reason is " + stringRepresentation, function () {
|
||||
testFulfilled(dummy, function (promise1, done) {
|
||||
var promise2 = promise1.then(function onFulfilled() {
|
||||
throw expectedReason;
|
||||
});
|
||||
|
||||
promise2.then(null, function onPromise2Rejected(actualReason) {
|
||||
assert.strictEqual(actualReason, expectedReason);
|
||||
done();
|
||||
});
|
||||
});
|
||||
testRejected(dummy, function (promise1, done) {
|
||||
var promise2 = promise1.then(null, function onRejected() {
|
||||
throw expectedReason;
|
||||
});
|
||||
|
||||
promise2.then(null, function onPromise2Rejected(actualReason) {
|
||||
assert.strictEqual(actualReason, expectedReason);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
testReason(undefined, "`undefined`");
|
||||
testReason(null, "`null`");
|
||||
testReason(false, "`false`");
|
||||
testReason(0, "`0`");
|
||||
testReason(new Error(), "an error");
|
||||
testReason(new Date(), "a date");
|
||||
testReason({}, "an object");
|
||||
testReason({ then: function () { } }, "a promise-alike");
|
||||
testReason(fulfilled(dummy), "a fulfilled promise");
|
||||
var promise = rejected(dummy); promise.caught(function(){});
|
||||
testReason(promise, "a rejected promise");
|
||||
});
|
||||
|
||||
describe("3.2.6.3: If either `onFulfilled` or `onRejected` returns a promise (call it `returnedPromise`), " +
|
||||
"`promise2` must assume the state of `returnedPromise`", function () {
|
||||
describe("3.2.6.3.1: If `returnedPromise` is pending, `promise2` must remain pending until `returnedPromise` " +
|
||||
"is fulfilled or rejected.", function () {
|
||||
testFulfilled(dummy, function (promise1, done) {
|
||||
var wasFulfilled = false;
|
||||
var wasRejected = false;
|
||||
|
||||
var promise2 = promise1.then(function onFulfilled() {
|
||||
var returnedPromise = pending().promise;
|
||||
return returnedPromise;
|
||||
});
|
||||
|
||||
promise2.then(
|
||||
function onPromise2Fulfilled() {
|
||||
wasFulfilled = true;
|
||||
},
|
||||
function onPromise2Rejected() {
|
||||
wasRejected = true;
|
||||
}
|
||||
);
|
||||
|
||||
setTimeout(function () {
|
||||
assert.strictEqual(wasFulfilled, false);
|
||||
assert.strictEqual(wasRejected, false);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
testRejected(dummy, function (promise1, done) {
|
||||
var wasFulfilled = false;
|
||||
var wasRejected = false;
|
||||
|
||||
var promise2 = promise1.then(null, function onRejected() {
|
||||
var returnedPromise = pending().promise;
|
||||
return returnedPromise;
|
||||
});
|
||||
|
||||
promise2.then(
|
||||
function onPromise2Fulfilled() {
|
||||
wasFulfilled = true;
|
||||
},
|
||||
function onPromise2Rejected() {
|
||||
wasRejected = true;
|
||||
}
|
||||
);
|
||||
|
||||
setTimeout(function () {
|
||||
assert.strictEqual(wasFulfilled, false);
|
||||
assert.strictEqual(wasRejected, false);
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
|
||||
describe("3.2.6.3.2: If/when `returnedPromise` is fulfilled, `promise2` must be fulfilled with the same value.",
|
||||
function () {
|
||||
describe("`promise1` is fulfilled, and `returnedPromise` is:", function () {
|
||||
testFulfilled(sentinel, function (returnedPromise, done) {
|
||||
var promise1 = fulfilled(dummy);
|
||||
var promise2 = promise1.then(function onFulfilled() {
|
||||
return returnedPromise;
|
||||
});
|
||||
|
||||
promise2.then(function onPromise2Fulfilled(value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
specify("a pseudo-promise", function (done) {
|
||||
var promise1 = fulfilled(dummy);
|
||||
var promise2 = promise1.then(function onFulfilled() {
|
||||
return {
|
||||
then: function (f) { f(sentinel); }
|
||||
};
|
||||
});
|
||||
|
||||
promise2.then(function onPromise2Fulfilled(value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("`promise1` is rejected, and `returnedPromise` is:", function () {
|
||||
testFulfilled(sentinel, function (returnedPromise, done) {
|
||||
var promise1 = rejected(dummy);
|
||||
var promise2 = promise1.then(null, function onRejected() {
|
||||
return returnedPromise;
|
||||
});
|
||||
|
||||
promise2.then(function onPromise2Fulfilled(value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
specify("a pseudo-promise", function (done) {
|
||||
var promise1 = rejected(dummy);
|
||||
var promise2 = promise1.then(null, function onRejected() {
|
||||
return {
|
||||
then: function (f) { f(sentinel); }
|
||||
};
|
||||
});
|
||||
|
||||
promise2.then(function onPromise2Fulfilled(value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("3.2.6.3.3: If/when `returnedPromise` is rejected, `promise2` must be rejected with the same reason.",
|
||||
function () {
|
||||
describe("`promise1` is fulfilled, and `returnedPromise` is:", function () {
|
||||
testRejected(sentinel, function (returnedPromise, done) {
|
||||
var promise1 = fulfilled(dummy);
|
||||
var promise2 = promise1.then(function onFulfilled() {
|
||||
return returnedPromise;
|
||||
});
|
||||
|
||||
promise2.then(null, function onPromise2Rejected(reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
specify("a pseudo-promise", function (done) {
|
||||
var promise1 = fulfilled(dummy);
|
||||
var promise2 = promise1.then(function onFulfilled() {
|
||||
return {
|
||||
then: function (f, r) { r(sentinel); }
|
||||
};
|
||||
});
|
||||
|
||||
promise2.then(null, function onPromise2Rejected(reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("`promise1` is rejected, and `returnedPromise` is:", function () {
|
||||
testRejected(sentinel, function (returnedPromise, done) {
|
||||
var promise1 = rejected(dummy);
|
||||
var promise2 = promise1.then(null, function onRejected() {
|
||||
return returnedPromise;
|
||||
});
|
||||
|
||||
promise2.then(null, function onPromise2Rejected(reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
specify("a pseudo-promise", function (done) {
|
||||
var promise1 = rejected(dummy);
|
||||
var promise2 = promise1.then(null, function onRejected() {
|
||||
return {
|
||||
then: function (f, r) { r(sentinel); }
|
||||
};
|
||||
});
|
||||
|
||||
promise2.then(null, function onPromise2Rejected(reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("3.2.6.4: If `onFulfilled` is not a function and `promise1` is fulfilled, `promise2` must be fulfilled " +
|
||||
"with the same value.", function () {
|
||||
|
||||
function testNonFunction(nonFunction, stringRepresentation) {
|
||||
describe("`onFulfilled` is " + stringRepresentation, function () {
|
||||
testFulfilled(sentinel, function (promise1, done) {
|
||||
var promise2 = promise1.then(nonFunction);
|
||||
|
||||
promise2.then(function onPromise2Fulfilled(value) {
|
||||
assert.strictEqual(value, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
testNonFunction(undefined, "`undefined`");
|
||||
testNonFunction(null, "`null`");
|
||||
testNonFunction(false, "`false`");
|
||||
testNonFunction(5, "`5`");
|
||||
testNonFunction({}, "an object");
|
||||
testNonFunction([function () { return other; }], "an array containing a function");
|
||||
});
|
||||
|
||||
describe("3.2.6.5: If `onRejected` is not a function and `promise1` is rejected, `promise2` must be rejected " +
|
||||
"with the same reason.", function () {
|
||||
|
||||
function testNonFunction(nonFunction, stringRepresentation) {
|
||||
describe("`onRejected` is " + stringRepresentation, function () {
|
||||
testRejected(sentinel, function (promise1, done) {
|
||||
var promise2 = promise1.then(null, nonFunction);
|
||||
|
||||
promise2.then(null, function onPromise2Rejected(reason) {
|
||||
assert.strictEqual(reason, sentinel);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
testNonFunction(undefined, "`undefined`");
|
||||
testNonFunction(null, "`null`");
|
||||
testNonFunction(false, "`false`");
|
||||
testNonFunction(5, "`5`");
|
||||
testNonFunction({}, "an object");
|
||||
testNonFunction([function () { return other; }], "an array containing a function");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,112 @@
|
|||
"use strict";
|
||||
/*
|
||||
Based on When.js tests
|
||||
|
||||
Open Source Initiative OSI - The MIT License
|
||||
|
||||
http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
Copyright (c) 2011 Brian Cavalier
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*/
|
||||
var assert = require("assert");
|
||||
var testUtils = require("./helpers/util.js");
|
||||
var sentinel = {};
|
||||
var other = {};
|
||||
var RangeError = Promise.RangeError;
|
||||
|
||||
describe("Promise.any-test", function () {
|
||||
|
||||
specify("should reject on empty input array", function() {
|
||||
var a = [];
|
||||
return Promise.any(a)
|
||||
.caught(RangeError, testUtils.returnToken)
|
||||
.then(testUtils.assertToken);
|
||||
});
|
||||
|
||||
specify("should resolve with an input value", function() {
|
||||
var input = [1, 2, 3];
|
||||
return Promise.any(input).then(
|
||||
function(result) {
|
||||
assert(testUtils.contains(input, result));
|
||||
}, assert.fail
|
||||
);
|
||||
});
|
||||
|
||||
specify("should resolve with a promised input value", function() {
|
||||
var input = [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)];
|
||||
return Promise.any(input).then(
|
||||
function(result) {
|
||||
assert(testUtils.contains([1, 2, 3], result));
|
||||
}, assert.fail
|
||||
);
|
||||
});
|
||||
|
||||
specify("should reject with all rejected input values if all inputs are rejected", function() {
|
||||
var input = [Promise.reject(1), Promise.reject(2), Promise.reject(3)];
|
||||
var promise = Promise.any(input);
|
||||
|
||||
return promise.then(
|
||||
assert.fail,
|
||||
function(result) {
|
||||
//Cannot use deep equality in IE8 because non-enumerable properties are not
|
||||
//supported
|
||||
assert(result[0] === 1);
|
||||
assert(result[1] === 2);
|
||||
assert(result[2] === 3);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
specify("should accept a promise for an array", function() {
|
||||
var expected, input;
|
||||
|
||||
expected = [1, 2, 3];
|
||||
input = Promise.resolve(expected);
|
||||
|
||||
return Promise.any(input).then(
|
||||
function(result) {
|
||||
assert.notDeepEqual(expected.indexOf(result), -1);
|
||||
}, assert.fail
|
||||
);
|
||||
});
|
||||
|
||||
specify("should allow zero handlers", function() {
|
||||
var input = [1, 2, 3];
|
||||
return Promise.any(input).then(
|
||||
function(result) {
|
||||
assert(testUtils.contains(input, result));
|
||||
}, assert.fail
|
||||
);
|
||||
});
|
||||
|
||||
specify("should resolve to empty array when input promise does not resolve to array", function() {
|
||||
return Promise.any(Promise.resolve(1))
|
||||
.caught(TypeError, testUtils.returnToken)
|
||||
.then(testUtils.assertToken);
|
||||
});
|
||||
|
||||
specify("should reject when given immediately rejected promise", function() {
|
||||
var err = new Error();
|
||||
return Promise.any(Promise.reject(err)).then(assert.fail, function(e) {
|
||||
assert.strictEqual(err, e);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,231 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testUtils = require("./helpers/util.js");
|
||||
|
||||
|
||||
function assertErrorHasLongTraces(e) {
|
||||
assert(e.stack.indexOf("From previous event:") > -1);
|
||||
}
|
||||
|
||||
function testCollection(name, a1, a2, a3) {
|
||||
|
||||
function getPromise(obj, val) {
|
||||
return obj === void 0
|
||||
? Promise.resolve(val)[name](a1, a2, a3)
|
||||
: Promise[name](val, a1, a2, a3);
|
||||
}
|
||||
|
||||
function thenable(obj) {
|
||||
var o = {
|
||||
then: function(f) {
|
||||
setTimeout(function(){
|
||||
f(3);
|
||||
}, 1);
|
||||
}
|
||||
}
|
||||
specify("thenable for non-collection value", function() {
|
||||
return getPromise(obj, o)
|
||||
.then(assert.fail)
|
||||
.caught(Promise.TypeError, testUtils.returnToken)
|
||||
.then(testUtils.assertToken)
|
||||
});
|
||||
};
|
||||
|
||||
function immediate(obj) {
|
||||
specify("immediate for non-collection value", function(){
|
||||
return getPromise(obj, 3)
|
||||
.then(assert.fail)
|
||||
.caught(Promise.TypeError, testUtils.returnToken)
|
||||
.then(testUtils.assertToken)
|
||||
});
|
||||
}
|
||||
|
||||
function promise(obj) {
|
||||
var d = Promise.defer();
|
||||
setTimeout(function(){
|
||||
d.resolve(3);
|
||||
}, 1);
|
||||
specify("promise for non-collection value", function() {
|
||||
return getPromise(obj, d.promise)
|
||||
.then(assert.fail)
|
||||
.caught(Promise.TypeError, testUtils.returnToken)
|
||||
.then(testUtils.assertToken)
|
||||
});
|
||||
}
|
||||
|
||||
describe("When passing non-collection argument to Promise."+name + "() it should reject", function() {
|
||||
immediate(Promise);
|
||||
thenable(Promise);
|
||||
promise(Promise);
|
||||
});
|
||||
|
||||
describe("When calling ."+name + "() on a promise that resolves to a non-collection it should reject", function() {
|
||||
immediate();
|
||||
thenable();
|
||||
promise();
|
||||
});
|
||||
}
|
||||
|
||||
if (Promise.hasLongStackTraces()) {
|
||||
|
||||
|
||||
describe("runtime API misuse should result in rejections", function(){
|
||||
specify("returning promises circularly", function() {
|
||||
var d = Promise.defer();
|
||||
var p = d.promise;
|
||||
|
||||
var c = p.then(function(){
|
||||
return c;
|
||||
});
|
||||
d.fulfill(3);
|
||||
return c.then(assert.fail, function(e){
|
||||
assert(e instanceof Promise.TypeError);
|
||||
});
|
||||
});
|
||||
|
||||
specify("using illegal catchfilter", function() {
|
||||
|
||||
var d = Promise.defer();
|
||||
var p = d.promise;
|
||||
d.fulfill(3);
|
||||
return p.caught(null, function(){
|
||||
|
||||
}).then(assert.fail, function(e){
|
||||
assert(e instanceof Promise.TypeError);
|
||||
});
|
||||
});
|
||||
|
||||
specify("non-function to map", function() {
|
||||
|
||||
return Promise.map([], []).then(assert.fail, function(e){
|
||||
assert(e instanceof Promise.TypeError);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
specify("non-function to map inside then", function() {
|
||||
|
||||
return Promise.resolve().then(function(){
|
||||
return Promise.map([], []);
|
||||
}).then(assert.fail, function(e){
|
||||
assert(e instanceof Promise.TypeError);
|
||||
assertErrorHasLongTraces(e);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
specify("non-function to reduce", function() {
|
||||
|
||||
return Promise.reduce([], []).then(assert.fail, function(e){
|
||||
assert(e instanceof Promise.TypeError);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
specify("non-function to reduce inside then", function() {
|
||||
|
||||
return Promise.resolve().then(function(){
|
||||
return Promise.reduce([], []);
|
||||
}).then(assert.fail, function(e){
|
||||
assert(e instanceof Promise.TypeError);
|
||||
assertErrorHasLongTraces(e);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
specify("non-integer to some", function() {
|
||||
|
||||
return Promise.some([], "asd").then(assert.fail, function(e){
|
||||
assert(e instanceof Promise.TypeError);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
specify("non-integer to some inside then", function() {
|
||||
|
||||
return Promise.resolve().then(function(){
|
||||
return Promise.some([], "asd")
|
||||
}).then(assert.fail, function(e){
|
||||
assert(e instanceof Promise.TypeError);
|
||||
assertErrorHasLongTraces(e);
|
||||
});
|
||||
});
|
||||
|
||||
specify("non-array to all", function() {
|
||||
|
||||
Promise.all(3, 3).then(assert.fail, function(e){
|
||||
assert(e instanceof Promise.TypeError);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
specify("non-array to all inside then", function() {
|
||||
|
||||
return Promise.resolve().then(function(){
|
||||
return Promise.all(3, 3);
|
||||
}).then(assert.fail, function(e) {
|
||||
assert(e instanceof Promise.TypeError);
|
||||
assertErrorHasLongTraces(e);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe("static API misuse should just throw right away", function(){
|
||||
|
||||
specify("non-function to promise constructor", function() {
|
||||
try {
|
||||
new Promise();
|
||||
assert.fail();
|
||||
}
|
||||
catch (e) {
|
||||
assert(e instanceof Promise.TypeError);
|
||||
}
|
||||
});
|
||||
|
||||
specify("non-function to coroutine", function() {
|
||||
try {
|
||||
Promise.coroutine();
|
||||
assert.fail();
|
||||
}
|
||||
catch (e) {
|
||||
assert(e instanceof Promise.TypeError);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
specify("non-object to promisifyAll", function() {
|
||||
try {
|
||||
Promise.promisifyAll();
|
||||
assert.fail();
|
||||
}
|
||||
catch (e) {
|
||||
assert(e instanceof Promise.TypeError);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
specify("non-function to promisify", function() {
|
||||
try {
|
||||
Promise.promisify();
|
||||
assert.fail();
|
||||
}
|
||||
catch (e) {
|
||||
assert(e instanceof Promise.TypeError);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
testCollection("race");
|
||||
testCollection("all");
|
||||
testCollection("settle");
|
||||
testCollection("any");
|
||||
testCollection("some", 1);
|
||||
testCollection("map", function(){});
|
||||
testCollection("reduce", function(){});
|
||||
testCollection("filter", function(){});
|
||||
testCollection("props", function(){});
|
||||
}
|
|
@ -0,0 +1,245 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testUtils = require("./helpers/util.js");
|
||||
|
||||
|
||||
describe("Async requirement", function() {
|
||||
|
||||
var arr = [];
|
||||
|
||||
function a() {
|
||||
arr.push(1);
|
||||
}
|
||||
|
||||
function b() {
|
||||
arr.push(2);
|
||||
}
|
||||
|
||||
function c() {
|
||||
arr.push(3);
|
||||
}
|
||||
|
||||
|
||||
function assertArr() {
|
||||
assert.deepEqual(arr, [1,2,3]);
|
||||
arr.length = 0;
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
arr = [];
|
||||
});
|
||||
|
||||
specify("Basic", function() {
|
||||
var p = new Promise(function(resolve) {
|
||||
resolve();
|
||||
});
|
||||
a();
|
||||
p.then(c);
|
||||
b();
|
||||
return p.then(assertArr);
|
||||
});
|
||||
|
||||
specify("Resolve-Before-Then", function() {
|
||||
var resolveP;
|
||||
var p = new Promise(function(resolve) {
|
||||
resolveP = resolve;
|
||||
});
|
||||
|
||||
a();
|
||||
resolveP();
|
||||
p.then(c);
|
||||
b();
|
||||
return p.then(assertArr);
|
||||
});
|
||||
|
||||
specify("Resolve-After-Then", function() {
|
||||
var resolveP;
|
||||
var p = new Promise(function(resolve) {
|
||||
resolveP = resolve;
|
||||
});
|
||||
|
||||
a();
|
||||
p.then(c);
|
||||
resolveP();
|
||||
b();
|
||||
return p.then(assertArr);
|
||||
});
|
||||
|
||||
specify("Then-Inside-Then", function() {
|
||||
var fulfilledP = Promise.resolve();
|
||||
return fulfilledP.then(function() {
|
||||
a();
|
||||
var ret = fulfilledP.then(c).then(assertArr);
|
||||
b();
|
||||
return ret;
|
||||
});
|
||||
});
|
||||
|
||||
if (typeof Error.captureStackTrace === "function") {
|
||||
describe("Should not grow the stack and cause eventually stack overflow.", function(){
|
||||
var lim;
|
||||
beforeEach(function() {
|
||||
lim = Error.stackTraceLimit;
|
||||
Error.stackTraceLimit = 10000;
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
Error.stackTraceLimit = lim;
|
||||
});
|
||||
|
||||
function assertStackIsNotGrowing(stack) {
|
||||
assert(stack.split("\n").length > 5);
|
||||
assert(stack.split("\n").length < 15);
|
||||
}
|
||||
|
||||
specify("Already fulfilled.", function() {
|
||||
function test(i){
|
||||
if (i <= 0){
|
||||
return Promise.resolve(new Error().stack);
|
||||
} else {
|
||||
return Promise.resolve(i-1).then(test)
|
||||
}
|
||||
}
|
||||
return test(100).then(function(stack) {
|
||||
assertStackIsNotGrowing(stack);
|
||||
});
|
||||
});
|
||||
|
||||
specify("Already rejected", function() {
|
||||
function test(i){
|
||||
if (i <= 0){
|
||||
return Promise.reject(new Error().stack);
|
||||
} else {
|
||||
return Promise.reject(i-1).then(assert.fail, test)
|
||||
}
|
||||
}
|
||||
return test(100).then(assert.fail, function(stack) {
|
||||
assertStackIsNotGrowing(stack);
|
||||
});
|
||||
});
|
||||
|
||||
specify("Immediately fulfilled", function() {
|
||||
function test(i){
|
||||
var deferred = Promise.defer();
|
||||
if (i <= 0){
|
||||
deferred.fulfill(new Error().stack);
|
||||
return deferred.promise;
|
||||
} else {
|
||||
deferred.fulfill(i-1);
|
||||
return deferred.promise.then(test)
|
||||
}
|
||||
}
|
||||
return test(100).then(function(stack) {
|
||||
assertStackIsNotGrowing(stack);
|
||||
});
|
||||
});
|
||||
|
||||
specify("Immediately rejected", function() {
|
||||
function test(i){
|
||||
var deferred = Promise.defer();
|
||||
if (i <= 0){
|
||||
deferred.reject(new Error().stack);
|
||||
return deferred.promise;
|
||||
} else {
|
||||
deferred.reject(i-1);
|
||||
return deferred.promise.then(assert.fail, test)
|
||||
}
|
||||
}
|
||||
return test(10).then(assert.fail, function(stack) {
|
||||
assertStackIsNotGrowing(stack);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (testUtils.isRecentNode) {
|
||||
describe("Frees memory of old values in promise chains", function () {
|
||||
function getHeapUsed() {
|
||||
global.gc();
|
||||
return process.memoryUsage().heapUsed;
|
||||
}
|
||||
|
||||
var initialHeapUsed;
|
||||
|
||||
before(function () {
|
||||
if (typeof global.gc !== "function") {
|
||||
throw new Error("These tests require the --expose-gc flag");
|
||||
}
|
||||
initialHeapUsed = getHeapUsed();
|
||||
});
|
||||
|
||||
specify(".then", function () {
|
||||
return Promise.resolve()
|
||||
.then(function () {
|
||||
assert.ok(
|
||||
getHeapUsed() < initialHeapUsed * 1.1,
|
||||
"Promise.resolve uses minimal memory"
|
||||
);
|
||||
var rows = [];
|
||||
for (var i = 0; i < 1e6; i++) {
|
||||
rows.push(["Example " + i, i, i * 2]);
|
||||
}
|
||||
return rows;
|
||||
})
|
||||
.then(function (rows) {
|
||||
assert.ok(
|
||||
getHeapUsed() > initialHeapUsed * 12,
|
||||
"large array uses a large amount of memory"
|
||||
);
|
||||
return { len: rows.length };
|
||||
})
|
||||
.then(function (x) {
|
||||
// work around cancellation retaining previous result
|
||||
return x;
|
||||
})
|
||||
.then(function (summaryResult) {
|
||||
assert.ok(
|
||||
getHeapUsed() < initialHeapUsed * 1.1,
|
||||
"memory used by large array is freed"
|
||||
);
|
||||
assert.strictEqual(summaryResult.len, 1e6, "result");
|
||||
});
|
||||
});
|
||||
|
||||
specify(".catch", function () {
|
||||
return Promise.reject(new Error("error 1"))
|
||||
.catch(function () {
|
||||
assert.ok(
|
||||
getHeapUsed() < initialHeapUsed * 1.1,
|
||||
"Promise.reject uses minimal memory"
|
||||
);
|
||||
var rows = [];
|
||||
for (var i = 0; i < 1e6; i++) {
|
||||
rows.push(["Example " + i, i, i * 2]);
|
||||
}
|
||||
var error = new Error("error 2");
|
||||
error.result = rows;
|
||||
throw error;
|
||||
})
|
||||
.catch(function (err) {
|
||||
assert.ok(
|
||||
getHeapUsed() > initialHeapUsed * 12,
|
||||
"large array uses a large amount of memory"
|
||||
);
|
||||
var rows = err.result;
|
||||
var error = new Error("error 3");
|
||||
error.result = { len: rows.length };
|
||||
throw error;
|
||||
})
|
||||
.catch(function (err) {
|
||||
// work around cancellation retaining previous result
|
||||
throw err;
|
||||
})
|
||||
.catch(function (err) {
|
||||
assert.ok(
|
||||
getHeapUsed() < initialHeapUsed * 1.1,
|
||||
"memory used by large array is freed"
|
||||
);
|
||||
var summaryResult = err.result;
|
||||
assert.strictEqual(summaryResult.len, 1e6, "result");
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
|
@ -0,0 +1,145 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
|
||||
var getContextFn = Promise._getContext;
|
||||
Promise.config({ asyncHooks: true });
|
||||
var supportsAsync = Promise._getContext !== getContextFn;
|
||||
Promise.config({ asyncHooks: false });
|
||||
if (supportsAsync) {
|
||||
runTests();
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
var async_hooks = require('async_hooks');
|
||||
|
||||
var tree = new Set();
|
||||
var hook = async_hooks.createHook({
|
||||
init: function(asyncId, type, triggerId) {
|
||||
if (tree.has(triggerId)) {
|
||||
tree.add(asyncId);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var currentId = async_hooks.executionAsyncId;
|
||||
|
||||
function getAsyncPromise() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
setTimeout(function() {
|
||||
setTimeout(resolve, 1);
|
||||
}, 1);
|
||||
});
|
||||
}
|
||||
|
||||
describe("async_hooks", function() {
|
||||
beforeEach(function() {
|
||||
Promise.config({ asyncHooks: true });
|
||||
})
|
||||
afterEach(function() {
|
||||
tree.clear();
|
||||
hook.disable();
|
||||
Promise.config({ asyncHooks: false });
|
||||
});
|
||||
|
||||
it('should preserve async context when using fromNode', function() {
|
||||
hook.enable()
|
||||
tree.add(currentId());
|
||||
|
||||
return new Promise(function(resolve) {
|
||||
var globalResolve;
|
||||
setImmediate(function() {
|
||||
hook.enable()
|
||||
tree.add(currentId());
|
||||
resolve(
|
||||
new Promise(function(resolve) { globalResolve = resolve; })
|
||||
.then(function() {
|
||||
assert.ok(tree.has(currentId()));
|
||||
})
|
||||
);
|
||||
})
|
||||
|
||||
setTimeout(function() {
|
||||
globalResolve();
|
||||
}, 10);
|
||||
})
|
||||
});
|
||||
|
||||
it('should preserve async context when using .map', function() {
|
||||
hook.enable()
|
||||
tree.add(currentId());
|
||||
var d1 = getAsyncPromise();
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
resolve(Promise.map([d1, null, Promise.resolve(1), Promise.delay(1)], function() {
|
||||
return currentId();
|
||||
}).then(function(asyncIds) {
|
||||
for (var i = 0; i < asyncIds.length; ++i) {
|
||||
assert.ok(tree.has(asyncIds[i]));
|
||||
}
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
it('should preserve async context when using .filter', function() {
|
||||
hook.enable()
|
||||
tree.add(currentId());
|
||||
var d1 = getAsyncPromise();
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
resolve(Promise.filter([d1, null, Promise.resolve(1), Promise.delay(1)], function() {
|
||||
assert.ok(tree.has(currentId()));
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
it('should preserve async context when using .reduce', function() {
|
||||
hook.enable()
|
||||
tree.add(currentId());
|
||||
var d1 = getAsyncPromise();
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
resolve(Promise.reduce([d1, null, Promise.resolve(1), Promise.delay(1)], function() {
|
||||
assert.ok(tree.has(currentId()));
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
it('should preserve async context when using .join', function() {
|
||||
hook.enable()
|
||||
tree.add(currentId());
|
||||
var d1 = getAsyncPromise();
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
resolve(Promise.join(d1, Promise.delay(1), function() {
|
||||
assert.ok(tree.has(currentId()));
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
it('should preserve async context when using .each', function() {
|
||||
hook.enable()
|
||||
tree.add(currentId());
|
||||
var d1 = getAsyncPromise();
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
resolve(Promise.each([d1, null, Promise.resolve(1), Promise.delay(1)], function() {
|
||||
assert.ok(tree.has(currentId()));
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to disable AsyncResource usage', function() {
|
||||
Promise.config({ asyncHooks: false });
|
||||
hook.enable()
|
||||
tree.add(currentId());
|
||||
var d1 = getAsyncPromise();
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
resolve(d1.then(function() {
|
||||
assert.ok(!tree.has(currentId()));
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,107 @@
|
|||
"use strict";
|
||||
var assert = require("assert");
|
||||
var testUtils = require("./helpers/util.js");
|
||||
var isNodeJS = testUtils.isNodeJS;
|
||||
var OldPromise = require("./helpers/bluebird0_7_0.js");
|
||||
|
||||
if (isNodeJS) {
|
||||
var Promise1 = testUtils.addDeferred(require("../../js/debug/promise.js")());
|
||||
var Promise2 = testUtils.addDeferred(require("../../js/debug/promise.js")());
|
||||
|
||||
var err1 = new Error();
|
||||
var err2 = new Error();
|
||||
|
||||
describe("Separate instances of bluebird", function() {
|
||||
|
||||
specify("Should have identical Error types", function() {
|
||||
assert(Promise1.CancellationError === Promise2.CancellationError);
|
||||
assert(Promise1.RejectionError === Promise2.RejectionError);
|
||||
assert(Promise1.TimeoutError === Promise2.TimeoutError);
|
||||
});
|
||||
|
||||
specify("Should not be identical", function() {
|
||||
assert(Promise1.onPossiblyUnhandledRejection !==
|
||||
Promise2.onPossiblyUnhandledRejection);
|
||||
assert(Promise1 !== Promise2);
|
||||
});
|
||||
|
||||
specify("Should have different unhandled rejection handlers", function() {
|
||||
var spy1 = testUtils.getSpy();
|
||||
var spy2 = testUtils.getSpy();
|
||||
|
||||
Promise1.onPossiblyUnhandledRejection(spy1(function(e, promise) {
|
||||
assert(promise instanceof Promise1);
|
||||
assert(!(promise instanceof Promise2));
|
||||
assert(e === err1);
|
||||
}));
|
||||
|
||||
Promise2.onPossiblyUnhandledRejection(spy2(function(e, promise) {
|
||||
assert(promise instanceof Promise2);
|
||||
assert(!(promise instanceof Promise1));
|
||||
assert(e === err2);
|
||||
}));
|
||||
assert(Promise1.onPossiblyUnhandledRejection !==
|
||||
Promise2.onPossiblyUnhandledRejection);
|
||||
|
||||
var d1 = Promise1.defer();
|
||||
var d2 = Promise2.defer();
|
||||
|
||||
d1.promise.then(function(){
|
||||
throw err1;
|
||||
});
|
||||
|
||||
d2.promise.then(function(){
|
||||
throw err2;
|
||||
});
|
||||
|
||||
setTimeout(function(){
|
||||
d1.fulfill();
|
||||
d2.fulfill();
|
||||
setTimeout(function() {
|
||||
Promise1._unhandledRejectionCheck();
|
||||
Promise2._unhandledRejectionCheck();
|
||||
}, 100);
|
||||
}, 1);
|
||||
return Promise.all([spy1.promise, spy2.promise]);
|
||||
});
|
||||
|
||||
specify("Should use fast cast", function() {
|
||||
var a = Promise1.defer();
|
||||
var b = Promise2.cast(a.promise);
|
||||
assert(a.promise._receiver0 === b);
|
||||
});
|
||||
|
||||
specify("Should use fast cast with very old version", function() {
|
||||
var a = OldPromise.pending();
|
||||
var b = Promise1.cast(a.promise);
|
||||
assert(a.promise._receiver0 === b);
|
||||
});
|
||||
|
||||
specify("Should return 2 from very old promise", function() {
|
||||
return Promise1.resolve().then(
|
||||
function(){ return OldPromise.cast(0).then(function(){return 2});
|
||||
}).then(function(two){
|
||||
assert.equal(two, 2);
|
||||
});
|
||||
});
|
||||
|
||||
specify("Should reject primitive from fast cast", function() {
|
||||
var a = OldPromise.pending();
|
||||
var b = Promise.resolve(a.promise);
|
||||
a.reject(1);
|
||||
return b.then(assert.fail, function(e) {
|
||||
assert.strictEqual(e, 1);
|
||||
});
|
||||
});
|
||||
specify("Should reject object from fast cast", function() {
|
||||
var err = new Error();
|
||||
var a = OldPromise.pending();
|
||||
var b = Promise.resolve(a.promise);
|
||||
a.reject(err);
|
||||
return b.then(assert.fail, function(e) {
|
||||
assert.strictEqual(e, err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testUtils = require("./helpers/util.js");
|
||||
|
||||
|
||||
var c = {
|
||||
val: 3,
|
||||
method: function() {
|
||||
return [].slice.call(arguments).concat(this.val);
|
||||
}
|
||||
};
|
||||
|
||||
describe("call", function() {
|
||||
specify("0 args", function() {
|
||||
return Promise.resolve(c).call("method").then(function(res) {
|
||||
assert.deepEqual([3], res);
|
||||
});
|
||||
});
|
||||
specify("1 args", function() {
|
||||
return Promise.resolve(c).call("method", 1).then(function(res) {
|
||||
assert.deepEqual([1, 3], res);
|
||||
});
|
||||
});
|
||||
specify("2 args", function() {
|
||||
return Promise.resolve(c).call("method", 1, 2).then(function(res) {
|
||||
assert.deepEqual([1, 2, 3], res);
|
||||
});
|
||||
});
|
||||
specify("3 args", function() {
|
||||
return Promise.resolve(c).call("method", 1, 2, 3).then(function(res) {
|
||||
assert.deepEqual([1, 2, 3, 3], res);
|
||||
});
|
||||
});
|
||||
specify("10 args", function() {
|
||||
return Promise.resolve(c).call("method", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10).then(function(res) {
|
||||
assert.deepEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 3], res);
|
||||
});
|
||||
});
|
||||
specify("method not found", function() {
|
||||
var promises = [
|
||||
Promise.resolve([]).call("abc").then(assert.fail, testUtils.noop),
|
||||
Promise.resolve([]).call("abc", 1, 2, 3, 4, 5, 6, 7).then(assert.fail, testUtils.noop),
|
||||
Promise.resolve([]).call("abc ").then(assert.fail, testUtils.noop),
|
||||
Promise.resolve(null).call("abc", 1, 2, 3, 4, 5, 6, 7).then(assert.fail, testUtils.noop),
|
||||
Promise.resolve(null).call("abc").then(assert.fail, testUtils.noop),
|
||||
Promise.resolve(null).call("abc ").then(assert.fail, testUtils.noop)
|
||||
];
|
||||
|
||||
return Promise.all(promises).then(function(errors) {
|
||||
for (var i = 0; i < errors.length; ++i) {
|
||||
var message = errors[i].message || errors[i].toString();
|
||||
assert(message.indexOf("has no method") >= 0);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,431 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testUtils = require("./helpers/util.js");
|
||||
|
||||
var CustomError = function(){};
|
||||
|
||||
CustomError.prototype = new Error();
|
||||
|
||||
var predicateFilter = function(e) {
|
||||
return (/invalid/).test(e.message);
|
||||
}
|
||||
|
||||
function BadError(msg) {
|
||||
this.message = msg;
|
||||
return this;
|
||||
}
|
||||
|
||||
function predicatesUndefined(e) {
|
||||
return e === void 0;
|
||||
}
|
||||
|
||||
function predicatesPrimitiveString(e) {
|
||||
return /^asd$/.test(e);
|
||||
}
|
||||
|
||||
var token = {};
|
||||
var returnToken = function() {
|
||||
return token;
|
||||
};
|
||||
|
||||
var assertToken = function(val) {
|
||||
assert.strictEqual(token, val);
|
||||
};
|
||||
|
||||
describe("A promise handler that throws a TypeError must be caught", function() {
|
||||
|
||||
specify("in a middle.caught filter", function() {
|
||||
var a = Promise.defer();
|
||||
a.fulfill(3);
|
||||
return a.promise.then(function(){
|
||||
a.b.c.d()
|
||||
}).then(assert.fail).caught(SyntaxError, function(e){
|
||||
assert.fail();
|
||||
}).caught(Promise.TypeError, returnToken)
|
||||
.then(assertToken);
|
||||
});
|
||||
|
||||
|
||||
specify("in a generic.caught filter that comes first", function() {
|
||||
var a = Promise.defer();
|
||||
|
||||
a.fulfill(3);
|
||||
return a.promise.then(function(){
|
||||
a.b.c.d()
|
||||
}).then(assert.fail, returnToken).caught(SyntaxError, function(e){
|
||||
assert.fail();
|
||||
}).caught(Promise.TypeError, function(e){
|
||||
assert.fail();
|
||||
}).then(assertToken);
|
||||
|
||||
});
|
||||
|
||||
specify("in an explicitly generic.caught filter that comes first", function() {
|
||||
var a = Promise.defer();
|
||||
a.fulfill(3);
|
||||
|
||||
return a.promise.then(function(){
|
||||
a.b.c.d()
|
||||
})
|
||||
.then(assert.fail)
|
||||
.caught(Error, returnToken)
|
||||
.caught(SyntaxError, assert.fail)
|
||||
.caught(Promise.TypeError, assert.fail)
|
||||
.then(assertToken);
|
||||
});
|
||||
|
||||
specify("in a specific handler after thrown in generic", function() {
|
||||
var a = Promise.defer();
|
||||
a.fulfill(3);
|
||||
|
||||
return a.promise.then(function(){
|
||||
a.b.c.d()
|
||||
}).then(assert.fail, function(e){
|
||||
throw e
|
||||
}).caught(SyntaxError, assert.fail)
|
||||
.then(assert.fail)
|
||||
.caught(Promise.TypeError, returnToken)
|
||||
.then(assertToken);
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
specify("in a multi-filter handler", function() {
|
||||
var a = Promise.defer();
|
||||
a.fulfill(3);
|
||||
|
||||
return a.promise.then(function(){
|
||||
a.b.c.d()
|
||||
})
|
||||
.then(assert.fail)
|
||||
.caught(SyntaxError, TypeError, returnToken)
|
||||
.then(assertToken);
|
||||
});
|
||||
|
||||
|
||||
specify("in a specific handler after non-matching multi.caught handler", function() {
|
||||
var a = Promise.defer();
|
||||
a.fulfill(3);
|
||||
|
||||
return a.promise.then(function(){
|
||||
a.b.c.d()
|
||||
})
|
||||
.then(assert.fail)
|
||||
.caught(SyntaxError, CustomError, assert.fail)
|
||||
.caught(Promise.TypeError, returnToken)
|
||||
.then(assertToken)
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe("A promise handler that throws a custom error", function() {
|
||||
|
||||
specify("Is filtered if inheritance was done even remotely properly", function() {
|
||||
var a = Promise.defer();
|
||||
var b = new CustomError();
|
||||
a.fulfill(3);
|
||||
return a.promise.then(function(){
|
||||
throw b;
|
||||
})
|
||||
.then(assert.fail)
|
||||
.caught(SyntaxError, assert.fail)
|
||||
.caught(Promise.TypeError, assert.fail)
|
||||
.caught(CustomError, function(e){
|
||||
assert.equal(e, b);
|
||||
return token;
|
||||
})
|
||||
.then(assertToken);
|
||||
|
||||
|
||||
});
|
||||
|
||||
specify("Is filtered along with built-in errors", function() {
|
||||
var a = Promise.defer();
|
||||
var b = new CustomError();
|
||||
a.fulfill(3);
|
||||
return a.promise.then(function(){
|
||||
throw b;
|
||||
})
|
||||
.then(assert.fail)
|
||||
.caught(Promise.TypeError, SyntaxError, CustomError, returnToken)
|
||||
.caught(assert.fail)
|
||||
.then(assertToken)
|
||||
});
|
||||
|
||||
specify("Throws after matched type handler throws", function() {
|
||||
var err = new Promise.TypeError();
|
||||
var err2 = new Error();
|
||||
return Promise.reject(err).caught(Promise.TypeError, function() {
|
||||
throw err2;
|
||||
}).then(assert.fail, function(e) {
|
||||
assert.strictEqual(err2, e);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("A promise handler that throws a CustomError must be caught", function() {
|
||||
specify("in a middle.caught filter", function() {
|
||||
var a = Promise.defer();
|
||||
a.fulfill(3);
|
||||
|
||||
return a.promise.then(function(){
|
||||
throw new CustomError()
|
||||
})
|
||||
.caught(SyntaxError, assert.fail)
|
||||
.caught(CustomError, returnToken)
|
||||
.then(assertToken);
|
||||
});
|
||||
|
||||
|
||||
specify("in a generic.caught filter that comes first", function() {
|
||||
var a = Promise.defer();
|
||||
a.fulfill(3);
|
||||
|
||||
return a.promise.then(function(){
|
||||
throw new CustomError()
|
||||
}).then(assert.fail, returnToken)
|
||||
.caught(SyntaxError, assert.fail)
|
||||
.caught(CustomError, assert.fail)
|
||||
.then(assertToken)
|
||||
});
|
||||
|
||||
specify("in an explicitly generic.caught filter that comes first", function() {
|
||||
var a = Promise.defer();
|
||||
a.fulfill(3);
|
||||
|
||||
return a.promise.then(function(){
|
||||
throw new CustomError()
|
||||
})
|
||||
.caught(Error, returnToken)
|
||||
.caught(SyntaxError, assert.fail)
|
||||
.caught(CustomError, assert.fail)
|
||||
.then(assertToken);
|
||||
});
|
||||
|
||||
specify("in a specific handler after thrown in generic", function() {
|
||||
var a = Promise.defer();
|
||||
a.fulfill(3);
|
||||
|
||||
return a.promise.then(function(){
|
||||
throw new CustomError()
|
||||
}).then(assert.fail, function(e){
|
||||
throw e
|
||||
})
|
||||
.caught(SyntaxError, assert.fail)
|
||||
.caught(CustomError, returnToken)
|
||||
.then(assertToken);
|
||||
|
||||
});
|
||||
|
||||
|
||||
specify("in a multi-filter handler", function() {
|
||||
var a = Promise.defer();
|
||||
a.fulfill(3);
|
||||
|
||||
return a.promise.then(function(){
|
||||
throw new CustomError()
|
||||
})
|
||||
.caught(SyntaxError, CustomError, returnToken)
|
||||
.then(assertToken)
|
||||
|
||||
});
|
||||
|
||||
|
||||
specify("in a specific handler after non-matching multi.caught handler", function() {
|
||||
var a = Promise.defer();
|
||||
a.fulfill(3);
|
||||
|
||||
return a.promise.then(function(){
|
||||
throw new CustomError()
|
||||
})
|
||||
.caught(SyntaxError, TypeError, assert.fail)
|
||||
.caught(CustomError, returnToken)
|
||||
.then(assertToken);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("A promise handler that is caught in a filter", function() {
|
||||
|
||||
specify("is continued normally after returning a promise in filter", function() {
|
||||
var a = Promise.defer();
|
||||
var c = Promise.defer();
|
||||
var b = new CustomError();
|
||||
a.fulfill(3);
|
||||
setTimeout(function(){
|
||||
c.fulfill(3);
|
||||
}, 1);
|
||||
return a.promise.then(function(){
|
||||
throw b;
|
||||
}).caught(SyntaxError, function(e){
|
||||
assert.fail();
|
||||
}).caught(Promise.TypeError, function(e){
|
||||
assert.fail();
|
||||
}).caught(CustomError, function(e){
|
||||
assert.equal(e, b);
|
||||
return c.promise.thenReturn(token);
|
||||
}).then(assertToken, assert.fail, assert.fail);
|
||||
});
|
||||
|
||||
specify("is continued normally after returning a promise in original handler", function() {
|
||||
var a = Promise.defer();
|
||||
var c = Promise.defer();
|
||||
a.fulfill(3);
|
||||
setTimeout(function(){
|
||||
c.fulfill(3);
|
||||
}, 1);
|
||||
return a.promise.then(function(){
|
||||
return c.promise;
|
||||
}).caught(SyntaxError, function(e){
|
||||
assert.fail();
|
||||
}).caught(Promise.TypeError, function(e){
|
||||
assert.fail();
|
||||
}).caught(CustomError, function(e){
|
||||
assert.fail();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
specify("should throw type error for not passing function", function() {
|
||||
try {
|
||||
var a = Promise.reject(new Error("asd"));
|
||||
a.caught(Promise.TypeError, "string");
|
||||
throw new Error("fail");
|
||||
} catch (e) {
|
||||
if (e instanceof Promise.TypeError) {
|
||||
return true;
|
||||
} else {
|
||||
throw new Error("fail");
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("A promise handler with a predicate filter", function() {
|
||||
|
||||
specify("will catch a thrown thing matching the filter", function() {
|
||||
var a = Promise.defer();
|
||||
a.fulfill(3);
|
||||
return a.promise.then(function(){
|
||||
throw new Error("horrible invalid error string");
|
||||
}).caught(predicateFilter, returnToken)
|
||||
.then(assertToken);
|
||||
|
||||
});
|
||||
specify("will NOT catch a thrown thing not matching the filter", function() {
|
||||
var a = Promise.defer();
|
||||
a.fulfill(3);
|
||||
return a.promise.then(function(){
|
||||
throw new Error("horrible valid error string");
|
||||
}).caught(predicateFilter, function(e){
|
||||
assert.fail();
|
||||
}).then(assert.fail, function(){})
|
||||
});
|
||||
|
||||
specify("will assert.fail when a predicate is a bad error class", function() {
|
||||
var a = Promise.defer();
|
||||
a.fulfill(3);
|
||||
return a.promise.then(function(){
|
||||
throw new Error("horrible custom error");
|
||||
}).caught(BadError, function(e){
|
||||
assert.fail();
|
||||
}).then(assert.fail, returnToken)
|
||||
.then(assertToken);
|
||||
|
||||
});
|
||||
|
||||
specify("will catch a thrown undefiend", function(){
|
||||
var a = Promise.defer();
|
||||
a.fulfill(3);
|
||||
return a.promise.then(function(){
|
||||
throw void 0;
|
||||
}).caught(function(e) { return false }, function(e){
|
||||
assert.fail();
|
||||
}).caught(predicatesUndefined, returnToken)
|
||||
.then(assertToken);
|
||||
|
||||
});
|
||||
|
||||
specify("will catch a thrown string", function(){
|
||||
var a = Promise.defer();
|
||||
a.fulfill(3);
|
||||
return a.promise.then(function(){
|
||||
throw "asd";
|
||||
}).caught(function(e) { return false }, function(e){
|
||||
assert.fail();
|
||||
}).caught(predicatesPrimitiveString, returnToken)
|
||||
.then(assertToken);
|
||||
|
||||
});
|
||||
|
||||
specify("will assert.fail when a predicate throws", function() {
|
||||
var a = Promise.defer();
|
||||
a.fulfill(3);
|
||||
return a.promise.then(function(){
|
||||
throw new CustomError("error happens");
|
||||
}).then(assert.fail, function(e) { return e.f.g; }, function(e){
|
||||
assert.fail();
|
||||
}).caught(TypeError, returnToken)
|
||||
.then(assertToken);
|
||||
});
|
||||
});
|
||||
|
||||
describe("object property predicates", function() {
|
||||
specify("matches 1 property loosely", function() {
|
||||
var e = new Error();
|
||||
e.code = "3";
|
||||
return Promise.resolve()
|
||||
.then(function() {
|
||||
throw e;
|
||||
})
|
||||
.caught({code: 3}, function(err) {
|
||||
assert.equal(e, err);
|
||||
});
|
||||
});
|
||||
|
||||
specify("matches 2 properties loosely", function() {
|
||||
var e = new Error();
|
||||
e.code = "3";
|
||||
e.code2 = "3";
|
||||
return Promise.resolve()
|
||||
.then(function() {
|
||||
throw e;
|
||||
})
|
||||
.caught({code: 3, code2: 3}, function(err) {
|
||||
assert.equal(e, err);
|
||||
});
|
||||
});
|
||||
|
||||
specify("doesn't match inequal properties", function() {
|
||||
var e = new Error();
|
||||
e.code = "3";
|
||||
e.code2 = "4";
|
||||
return Promise.resolve()
|
||||
.then(function() {
|
||||
throw e;
|
||||
})
|
||||
.caught({code: 3, code2: 3}, function(err) {
|
||||
assert.fail();
|
||||
})
|
||||
.caught(function(v) {return v === e}, function() {});
|
||||
});
|
||||
|
||||
specify("doesn't match primitives even if the property matches", function() {
|
||||
var e = "string";
|
||||
var length = e.length;
|
||||
return Promise.resolve()
|
||||
.then(function() {
|
||||
throw e;
|
||||
})
|
||||
.caught({length: length}, function(err) {
|
||||
assert.fail();
|
||||
})
|
||||
.caught(function(v) {return typeof v === "string"}, function(err) {
|
||||
assert.equal(e, err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,355 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testUtils = require("./helpers/util.js");
|
||||
|
||||
|
||||
function Thenable(value, defer, reject) {
|
||||
this.value = value;
|
||||
this.defer = !!defer;
|
||||
this.reject = !!reject;
|
||||
}
|
||||
|
||||
Thenable.prototype.then = function Then$then(onFulfilled, onRejected) {
|
||||
var fn = this.reject ? onRejected : onFulfilled;
|
||||
var value = this.value;
|
||||
|
||||
if (this.defer) {
|
||||
setTimeout(function(){
|
||||
fn(value);
|
||||
}, 1)
|
||||
}
|
||||
else {
|
||||
fn(value);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
function testFulfillSync(name, cb, a1, a2, a3) {
|
||||
var thenables = [new Thenable(1), new Thenable(2), new Thenable(3)];
|
||||
|
||||
specify("Promise." + name + " thenables that fulfill synchronously", function(){
|
||||
return cb(Promise[name](thenables, a1, a2, a3));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function testFulfillAsync(name, cb, a1, a2, a3) {
|
||||
var thenables = [new Thenable(1, true), new Thenable(2, true), new Thenable(3, true)];
|
||||
|
||||
specify("Promise." + name + " thenables that fulfill asynchronously", function(){
|
||||
return cb(Promise[name](thenables, a1, a2, a3));
|
||||
});
|
||||
}
|
||||
|
||||
function testRejectSync(name, cb, a1, a2, a3) {
|
||||
var thenables = [new Thenable(1, false, true), new Thenable(2, false, true), new Thenable(3, false, true)];
|
||||
|
||||
specify("Promise." + name + " thenables that reject synchronously", function(){
|
||||
return cb(Promise[name](thenables, a1, a2, a3));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function testRejectAsync(name, cb, a1, a2, a3) {
|
||||
var thenables = [new Thenable(1, true, true), new Thenable(2, true, true), new Thenable(3, true, true)];
|
||||
|
||||
specify("Promise." + name + " thenables that reject asynchronously", function(){
|
||||
return cb(Promise[name](thenables, a1, a2, a3));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
describe("Using collection methods with thenables", function() {
|
||||
var name = "race";
|
||||
testFulfillSync(name, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert(v === 1);
|
||||
});
|
||||
});
|
||||
testFulfillAsync(name, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert(v === 1);
|
||||
});
|
||||
});
|
||||
testRejectSync(name, function(promise) {
|
||||
return promise.then(assert.fail, function(v){
|
||||
assert(v === 1);
|
||||
});
|
||||
});
|
||||
testRejectAsync(name, function(promise) {
|
||||
return promise.then(assert.fail, function(v){
|
||||
assert(v === 1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Using collection methods with thenables", function() {
|
||||
var name = "all";
|
||||
testFulfillSync(name, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert.deepEqual(v, [1,2,3]);
|
||||
});
|
||||
});
|
||||
testFulfillAsync(name, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert.deepEqual(v, [1,2,3]);
|
||||
});
|
||||
});
|
||||
testRejectSync(name, function(promise) {
|
||||
return promise.then(assert.fail, function(v){
|
||||
assert(v === 1);
|
||||
});
|
||||
});
|
||||
testRejectAsync(name, function(promise) {
|
||||
return promise.then(assert.fail, function(v){
|
||||
assert(v === 1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Using collection methods with thenables", function() {
|
||||
var name = "settle";
|
||||
testFulfillSync(name, function(promise) {
|
||||
return promise.then(function(v) {
|
||||
assert(v[0].value() === 1)
|
||||
assert(v[1].value() === 2)
|
||||
assert(v[2].value() === 3)
|
||||
});
|
||||
});
|
||||
testFulfillAsync(name, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert(v[0].value() === 1)
|
||||
assert(v[1].value() === 2)
|
||||
assert(v[2].value() === 3)
|
||||
});
|
||||
});
|
||||
testRejectSync(name, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert(v[0].error() === 1)
|
||||
assert(v[1].error() === 2)
|
||||
assert(v[2].error() === 3)
|
||||
});
|
||||
});
|
||||
testRejectAsync(name, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert(v[0].error() === 1)
|
||||
assert(v[1].error() === 2)
|
||||
assert(v[2].error() === 3)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Using collection methods with thenables", function() {
|
||||
var name = "any";
|
||||
testFulfillSync(name, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert(v === 1);
|
||||
});
|
||||
});
|
||||
testFulfillAsync(name, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert(v === 1);
|
||||
});
|
||||
});
|
||||
testRejectSync(name, function(promise) {
|
||||
return promise.then(assert.fail, function(v){
|
||||
assert(v[0] === 1);
|
||||
assert(v[1] === 2);
|
||||
assert(v[2] === 3);
|
||||
});
|
||||
});
|
||||
testRejectAsync(name, function(promise) {
|
||||
return promise.then(assert.fail, function(v){
|
||||
assert(v[0] === 1);
|
||||
assert(v[1] === 2);
|
||||
assert(v[2] === 3);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Using collection methods with thenables", function() {
|
||||
var name = "some";
|
||||
testFulfillSync(name, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert(v[0] === 1);
|
||||
});
|
||||
}, 1);
|
||||
testFulfillAsync(name, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert(v[0] === 1);
|
||||
});
|
||||
}, 1);
|
||||
testRejectSync(name, function(promise) {
|
||||
return promise.then(assert.fail, function(v){
|
||||
assert(v[0] === 1);
|
||||
assert(v[1] === 2);
|
||||
assert(v[2] === 3);
|
||||
});
|
||||
}, 1);
|
||||
testRejectAsync(name, function(promise) {
|
||||
return promise.then(assert.fail, function(v){
|
||||
assert(v[0] === 1);
|
||||
assert(v[1] === 2);
|
||||
assert(v[2] === 3);
|
||||
});
|
||||
}, 1);
|
||||
});
|
||||
|
||||
describe("Using collection methods with thenables", function() {
|
||||
var name = "join";
|
||||
testFulfillSync(name, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert(v[0][0].value === 1);
|
||||
assert(v[0][1].value === 2);
|
||||
assert(v[0][2].value === 3);
|
||||
assert(v[1] === 1);
|
||||
assert(v[2] === 2);
|
||||
assert(v[3] === 3);
|
||||
});
|
||||
}, 1, 2, 3);
|
||||
testFulfillAsync(name, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert(v[0][0].value === 1);
|
||||
assert(v[0][1].value === 2);
|
||||
assert(v[0][2].value === 3);
|
||||
assert(v[1] === 1);
|
||||
assert(v[2] === 2);
|
||||
assert(v[3] === 3);
|
||||
});
|
||||
}, 1, 2, 3);
|
||||
testRejectSync(name, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert(v[0][0].value === 1);
|
||||
assert(v[0][1].value === 2);
|
||||
assert(v[0][2].value === 3);
|
||||
assert(v[1] === 1);
|
||||
assert(v[2] === 2);
|
||||
assert(v[3] === 3);
|
||||
});
|
||||
}, 1, 2, 3);
|
||||
testRejectAsync(name, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert(v[0][0].value === 1);
|
||||
assert(v[0][1].value === 2);
|
||||
assert(v[0][2].value === 3);
|
||||
assert(v[1] === 1);
|
||||
assert(v[2] === 2);
|
||||
assert(v[3] === 3);
|
||||
});
|
||||
}, 1, 2, 3);
|
||||
});
|
||||
|
||||
function mapper(v) {
|
||||
return {
|
||||
then: function(f) {
|
||||
f(v*2);
|
||||
}
|
||||
};
|
||||
}
|
||||
function reducer(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
function filterer(v) {
|
||||
return {
|
||||
then: function(f) {
|
||||
f(v > 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
describe("Using collection methods with thenables", function() {
|
||||
var name = "map";
|
||||
testFulfillSync(name, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert.deepEqual(v, [2,4,6]);
|
||||
});
|
||||
}, mapper);
|
||||
testFulfillAsync(name, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert.deepEqual(v, [2,4,6]);
|
||||
});
|
||||
}, mapper);
|
||||
testRejectSync(name, function(promise) {
|
||||
return promise.then(assert.fail, function(v){
|
||||
assert.deepEqual(v, 1);
|
||||
});
|
||||
}, mapper);
|
||||
testRejectAsync(name, function(promise) {
|
||||
return promise.then(assert.fail, function(v){
|
||||
assert.deepEqual(v, 1);
|
||||
});
|
||||
}, mapper);
|
||||
});
|
||||
|
||||
describe("Using collection methods with thenables", function() {
|
||||
var name = "reduce";
|
||||
testFulfillSync(name, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert.deepEqual(v, 6);
|
||||
});
|
||||
}, reducer);
|
||||
testFulfillAsync(name, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert.deepEqual(v, 6);
|
||||
});
|
||||
}, reducer);
|
||||
testRejectSync(name, function(promise) {
|
||||
return promise.then(assert.fail, function(v){
|
||||
assert.deepEqual(v, 1);
|
||||
});
|
||||
}, reducer);
|
||||
testRejectAsync(name, function(promise) {
|
||||
return promise.then(assert.fail, function(v){
|
||||
assert.deepEqual(v, 1);
|
||||
});
|
||||
}, reducer);
|
||||
});
|
||||
|
||||
describe("Using collection methods with thenables", function() {
|
||||
var name = "filter";
|
||||
testFulfillSync(name, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert.deepEqual(v, [1,2,3]);
|
||||
});
|
||||
}, filterer);
|
||||
testFulfillAsync(name, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert.deepEqual(v, [1,2,3]);
|
||||
});
|
||||
}, filterer);
|
||||
testRejectSync(name, function(promise) {
|
||||
return promise.then(assert.fail, function(v){
|
||||
assert.deepEqual(v, 1);
|
||||
});
|
||||
}, filterer);
|
||||
testRejectAsync(name, function(promise) {
|
||||
return promise.then(assert.fail, function(v){
|
||||
assert.deepEqual(v, 1);
|
||||
});
|
||||
}, filterer);
|
||||
});
|
||||
|
||||
describe("Using collection methods with thenables", function() {
|
||||
var name = "props";
|
||||
testFulfillSync(name, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert.deepEqual(v, {0: 1, 1: 2, 2: 3});
|
||||
});
|
||||
}, filterer);
|
||||
testFulfillAsync(name, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert.deepEqual(v, {0: 1, 1: 2, 2: 3});
|
||||
});
|
||||
}, filterer);
|
||||
testRejectSync(name, function(promise) {
|
||||
return promise.then(assert.fail, function(v){
|
||||
assert.deepEqual(v, 1);
|
||||
});
|
||||
}, filterer);
|
||||
testRejectAsync(name, function(promise) {
|
||||
return promise.then(assert.fail, function(v){
|
||||
assert.deepEqual(v, 1);
|
||||
});
|
||||
}, filterer);
|
||||
});
|
|
@ -0,0 +1,201 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testUtils = require("./helpers/util.js");
|
||||
|
||||
|
||||
function fulfills(value, test) {
|
||||
specify("immediately-fulfilled", function() {
|
||||
return test(new Promise(function(resolve){
|
||||
resolve(value);
|
||||
}));
|
||||
});
|
||||
|
||||
specify("eventually-fulfilled", function() {
|
||||
return test(new Promise(function(resolve){
|
||||
setTimeout(function(){
|
||||
resolve(value);
|
||||
}, 1);
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
function rejects(reason, test) {
|
||||
specify("immediately-rejected", function() {
|
||||
return test(new Promise(function(resolve, reject){
|
||||
reject(reason);
|
||||
}));
|
||||
});
|
||||
|
||||
specify("eventually-rejected", function() {
|
||||
return test(new Promise(function(resolve, reject){
|
||||
setTimeout(function(){
|
||||
reject(reason);
|
||||
}, 1);
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
function testFulfilled(value, test) {
|
||||
describe("immediate value", function(){
|
||||
fulfills(value, test);
|
||||
});
|
||||
|
||||
describe("already fulfilled promise for value", function(){
|
||||
fulfills(Promise.resolve(value), test);
|
||||
});
|
||||
|
||||
describe("immediately fulfilled promise for value", function(){
|
||||
var a = Promise.defer();
|
||||
fulfills(a.promise, test);
|
||||
a.resolve(value);
|
||||
});
|
||||
|
||||
describe("eventually fulfilled promise for value", function(){
|
||||
var a = Promise.defer();
|
||||
fulfills(a.promise, test);
|
||||
setTimeout(function(){
|
||||
a.resolve(value);
|
||||
}, 1)
|
||||
|
||||
});
|
||||
|
||||
describe("synchronous thenable for value", function () {
|
||||
fulfills({
|
||||
then: function (f) {
|
||||
f(value);
|
||||
}
|
||||
}, test);
|
||||
});
|
||||
|
||||
describe("asynchronous thenable for value", function () {
|
||||
fulfills({
|
||||
then: function (f) {
|
||||
setTimeout(function () {
|
||||
f(value);
|
||||
}, 1);
|
||||
}
|
||||
}, test);
|
||||
});
|
||||
}
|
||||
|
||||
function testRejected(reason, test) {
|
||||
describe("immediate reason", function(){
|
||||
rejects(reason, test);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
describe("Promise constructor", function() {
|
||||
it("should throw type error when called as function", function() {
|
||||
try {
|
||||
Promise(function(){});
|
||||
}
|
||||
catch (e) {
|
||||
return;
|
||||
}
|
||||
assert.fail();
|
||||
});
|
||||
|
||||
it("should throw type error when passed non-function", function() {
|
||||
try {
|
||||
new Promise({});
|
||||
}
|
||||
catch (e) {
|
||||
return;
|
||||
}
|
||||
assert.fail();
|
||||
});
|
||||
|
||||
|
||||
var defaultThis = (function(){
|
||||
return this;
|
||||
})();
|
||||
|
||||
it("calls the resolver as a function", function(){
|
||||
new Promise(function() {
|
||||
assert(this === defaultThis);
|
||||
});
|
||||
});
|
||||
|
||||
it("passes arguments even if parameters are not defined", function(){
|
||||
new Promise(function() {
|
||||
assert(arguments.length === 2 || arguments.length === 3);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("should reject with any thrown error", function() {
|
||||
var e = new Error();
|
||||
return new Promise(function(){
|
||||
throw e;
|
||||
}).then(assert.fail, function(err) {
|
||||
assert(err === e)
|
||||
});
|
||||
});
|
||||
|
||||
it("should call the resolver function synchronously", function() {
|
||||
var e = new Error();
|
||||
var a = 0;
|
||||
new Promise(function(){
|
||||
a = 1;
|
||||
});
|
||||
assert(a === 1);
|
||||
});
|
||||
|
||||
|
||||
describe("resolves the promise with the given object value", function() {
|
||||
var value = {};
|
||||
testFulfilled(value, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert(v === value);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolves the promise with the given primitive value", function() {
|
||||
var value = 3;
|
||||
testFulfilled(value, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert(v === value);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolves the promise with the given undefined value", function() {
|
||||
var value = void 0;
|
||||
testFulfilled(value, function(promise) {
|
||||
return promise.then(function(v){
|
||||
assert(v === value);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("rejects the promise with the given object reason", function() {
|
||||
var reason = {};
|
||||
testRejected(reason, function(promise) {
|
||||
return promise.then(assert.fail, function(v){
|
||||
assert(v === reason);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("rejects the promise with the given primitive reason", function() {
|
||||
var reason = 3;
|
||||
testRejected(reason, function(promise) {
|
||||
return promise.then(assert.fail, function(v){
|
||||
assert(v === reason);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("rejects the promise with the given undefined reason", function() {
|
||||
var reason = void 0;
|
||||
testRejected(reason, function(promise) {
|
||||
return promise.then(assert.fail, function(v){
|
||||
assert(v === reason);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
|
@ -0,0 +1,68 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testUtils = require("./helpers/util.js");
|
||||
|
||||
var helpers = require("./helpers/testThreeCases.js");
|
||||
var TypeError = Promise.TypeError;
|
||||
|
||||
|
||||
describe("Cyclical promises should throw TypeError when", function(){
|
||||
describe("returning from fulfill", function() {
|
||||
helpers.testFulfilled(3, function(promise) {
|
||||
var self = promise.then(function() {
|
||||
return self;
|
||||
});
|
||||
|
||||
return self.then(assert.fail).caught(TypeError, testUtils.noop);
|
||||
});
|
||||
});
|
||||
|
||||
describe("returning from reject", function() {
|
||||
helpers.testRejected(3, function(promise) {
|
||||
var self = promise.then(assert.fail, function() {
|
||||
return self;
|
||||
});
|
||||
|
||||
return self.then(assert.fail).caught(TypeError, testUtils.noop);
|
||||
});
|
||||
});
|
||||
|
||||
describe("fulfill with itself when using a ", function() {
|
||||
specify("deferred", function() {
|
||||
var d = Promise.defer();
|
||||
d.fulfill(d.promise);
|
||||
return d.promise.then(assert.fail).caught(TypeError, testUtils.noop);
|
||||
});
|
||||
|
||||
specify("constructor", function() {
|
||||
var resolve;
|
||||
var p = new Promise(function(r) {
|
||||
resolve = r;
|
||||
});
|
||||
resolve(p);
|
||||
return p.then(assert.fail).caught(TypeError, testUtils.noop);
|
||||
});
|
||||
});
|
||||
|
||||
describe("reject with itself when using a ", function() {
|
||||
specify("deferred", function() {
|
||||
var d = Promise.defer();
|
||||
d.reject(d.promise);
|
||||
return d.promise.then(assert.fail).caught(function(v) {
|
||||
assert.equal(d.promise, v);
|
||||
});
|
||||
});
|
||||
|
||||
specify("constructor", function() {
|
||||
var reject;
|
||||
var p = new Promise(function(f, r) {
|
||||
reject = r;
|
||||
});
|
||||
reject(p);
|
||||
return p.then(assert.fail).caught(function(v) {
|
||||
assert.equal(p, v);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,257 @@
|
|||
"use strict";
|
||||
|
||||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testUtils = require("./helpers/util.js");
|
||||
|
||||
var helpers = require("./helpers/testThreeCases.js");
|
||||
var TypeError = Promise.TypeError;
|
||||
|
||||
function passthru(fn) {
|
||||
return function() {
|
||||
fn();
|
||||
};
|
||||
}
|
||||
|
||||
function wrap(fn, val) {
|
||||
var args = [].slice.call(arguments, 1);
|
||||
return function() {
|
||||
return fn.apply(this, args);
|
||||
}
|
||||
}
|
||||
|
||||
function returnValue(value) {
|
||||
helpers.testFulfilled(void 0, function(promise) {
|
||||
return promise.thenReturn(value).then(function(v){
|
||||
assert(v === value);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function throwValue(value) {
|
||||
helpers.testFulfilled(void 0, function(promise) {
|
||||
return promise.thenThrow(value).then(assert.fail, function(v) {
|
||||
assert(v === value);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function returnThenable(thenable, expected) {
|
||||
helpers.testFulfilled(void 0, function(promise) {
|
||||
return promise.thenReturn(thenable).then(function(v){
|
||||
assert(v === expected);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function returnThenableReject(thenable, expected) {
|
||||
helpers.testFulfilled(void 0, function(promise) {
|
||||
return promise.thenReturn(thenable).then(assert.fail, function(v){
|
||||
assert(v === expected);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe("thenReturn", function () {
|
||||
|
||||
describe("primitives", function() {
|
||||
describe("null", wrap(returnValue, null));
|
||||
describe("undefined", wrap(returnValue, void 0));
|
||||
describe("string", wrap(returnValue, "asd"));
|
||||
describe("number", wrap(returnValue, 3));
|
||||
describe("boolean", wrap(returnValue, true));
|
||||
});
|
||||
|
||||
describe("objects", function() {
|
||||
describe("plain", wrap(returnValue, {}));
|
||||
describe("function", wrap(returnValue, function(){}));
|
||||
describe("built-in function", wrap(returnValue, Array));
|
||||
describe("built-in object", wrap(returnValue, Math));
|
||||
});
|
||||
|
||||
describe("thenables", function() {
|
||||
describe("which fulfill", function() {
|
||||
describe("immediately", wrap(returnThenable, {
|
||||
then: function(f) {
|
||||
f(10);
|
||||
}
|
||||
}, 10));
|
||||
describe("eventually", wrap(returnThenable, {
|
||||
then: function(f) {
|
||||
setTimeout(function() {
|
||||
f(10);
|
||||
}, 1);
|
||||
}
|
||||
}, 10));
|
||||
});
|
||||
describe("which reject", function(){
|
||||
describe("immediately", wrap(returnThenableReject, {
|
||||
then: function(f, r) {
|
||||
r(10);
|
||||
}
|
||||
}, 10));
|
||||
describe("eventually", wrap(returnThenableReject, {
|
||||
then: function(f, r) {
|
||||
setTimeout(function() {
|
||||
r(10);
|
||||
}, 1);
|
||||
}
|
||||
}, 10));
|
||||
});
|
||||
});
|
||||
|
||||
describe("promises", function() {
|
||||
describe("which fulfill", function() {
|
||||
var d1 = Promise.defer();
|
||||
var d2 = Promise.defer();
|
||||
describe("already", wrap(returnThenable, Promise.resolve(10), 10));
|
||||
describe("immediately", wrap(returnThenable, d1.promise, 10));
|
||||
describe("eventually", wrap(returnThenable, d2.promise, 10));
|
||||
d1.fulfill(10);
|
||||
setTimeout(function(){
|
||||
d2.fulfill(10);
|
||||
}, 1);
|
||||
});
|
||||
describe("which reject", function() {
|
||||
var d1 = Promise.defer();
|
||||
var d2 = Promise.defer();
|
||||
var alreadyRejected = Promise.reject(10);
|
||||
alreadyRejected.then(assert.fail, function(){});
|
||||
describe("already", wrap(returnThenableReject, alreadyRejected, 10));
|
||||
describe("immediately", wrap(returnThenableReject, d1.promise, 10));
|
||||
describe("eventually", wrap(returnThenableReject, d2.promise, 10));
|
||||
d1.reject(10);
|
||||
setTimeout(function(){
|
||||
d2.reject(10);
|
||||
}, 1);
|
||||
|
||||
d1.promise.caught(function(){});
|
||||
d2.promise.caught(function(){});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("doesn't swallow errors", function() {
|
||||
var e = {};
|
||||
helpers.testRejected(e, function(promise){
|
||||
return promise.thenReturn(3).then(assert.fail, function(err) {
|
||||
assert(err = e);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("thenThrow", function () {
|
||||
|
||||
describe("primitives", function() {
|
||||
describe("null", wrap(throwValue, null));
|
||||
describe("undefined", wrap(throwValue, void 0));
|
||||
describe("string", wrap(throwValue, "asd"));
|
||||
describe("number", wrap(throwValue, 3));
|
||||
describe("boolean", wrap(throwValue, true));
|
||||
});
|
||||
|
||||
describe("objects", function() {
|
||||
describe("plain", wrap(throwValue, {}));
|
||||
describe("function", wrap(throwValue, function(){}));
|
||||
describe("built-in function", wrap(throwValue, Array));
|
||||
describe("built-in object", wrap(throwValue, Math));
|
||||
});
|
||||
|
||||
describe("doesn't swallow errors", function() {
|
||||
var e = {};
|
||||
helpers.testRejected(e, function(promise){
|
||||
return promise.thenThrow(3).then(assert.fail, function(err) {
|
||||
assert(err = e);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("catchReturn", function () {
|
||||
|
||||
specify("catches and returns", function() {
|
||||
return Promise.reject(3).catchReturn(1).then(function(val) {
|
||||
assert.strictEqual(1, val);
|
||||
});
|
||||
});
|
||||
|
||||
specify("doesn't catch succesful promise", function() {
|
||||
return Promise.resolve(3).catchReturn(1).then(function(val) {
|
||||
assert.strictEqual(3, val);
|
||||
});
|
||||
});
|
||||
|
||||
specify("supports 1 error type", function() {
|
||||
var e = new Error();
|
||||
e.prop = 3;
|
||||
var predicate = function(e) {return e.prop === 3};
|
||||
return Promise.reject(e)
|
||||
.catchReturn(TypeError, 1)
|
||||
.catchReturn(predicate, 2)
|
||||
.then(function(val) {
|
||||
assert.strictEqual(2, val);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("catchThrow", function () {
|
||||
|
||||
specify("catches and throws", function() {
|
||||
return Promise.reject(3).catchThrow(1).then(assert.fail, function(val) {
|
||||
assert.strictEqual(1, val);
|
||||
});
|
||||
});
|
||||
|
||||
specify("doesn't catch succesful promise", function() {
|
||||
return Promise.resolve(3).catchThrow(1).then(function(val) {
|
||||
assert.strictEqual(3, val);
|
||||
});
|
||||
});
|
||||
|
||||
specify("supports 1 error type", function() {
|
||||
var e = new Error();
|
||||
e.prop = 3;
|
||||
var predicate = function(e) {return e.prop === 3};
|
||||
return Promise.reject(e)
|
||||
.catchThrow(TypeError, 1)
|
||||
.catchThrow(predicate, 2)
|
||||
.then(assert.fail, function(val) {
|
||||
assert.strictEqual(2, val);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("gh-627", function() {
|
||||
it("can return undefined", function() {
|
||||
return Promise.bind(42)
|
||||
.thenReturn(undefined)
|
||||
.then(function (value) {
|
||||
assert.strictEqual(value, undefined);
|
||||
});
|
||||
});
|
||||
it("can throw undefined", function() {
|
||||
return Promise.bind(42)
|
||||
.thenThrow(undefined)
|
||||
.then(assert.fail, function (reason) {
|
||||
assert.strictEqual(reason, undefined);
|
||||
});
|
||||
});
|
||||
|
||||
it("can catch return undefined", function() {
|
||||
return Promise.bind(42).thenThrow(new Error())
|
||||
.catchReturn()
|
||||
.then(function (value) {
|
||||
assert.strictEqual(value, undefined);
|
||||
});
|
||||
});
|
||||
it("can catch throw undefined", function() {
|
||||
return Promise.bind(42).thenThrow(new Error())
|
||||
.catchThrow()
|
||||
.then(assert.fail, function (reason) {
|
||||
assert.strictEqual(reason, undefined);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,503 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testUtils = require("./helpers/util.js");
|
||||
|
||||
if (testUtils.isRecentNode) {
|
||||
describe("domain", function() {
|
||||
afterEach(function() {
|
||||
Promise.onPossiblyUnhandledRejection(null);
|
||||
});
|
||||
|
||||
specify("gh-148", function() {
|
||||
var called = false;
|
||||
var e = new Error("the error");
|
||||
Promise.resolve(23).then(function(){called = true});
|
||||
return testUtils.awaitDomainException(function(E) {
|
||||
assert.equal(e, E);
|
||||
assert(called);
|
||||
}, function() {
|
||||
Promise.onPossiblyUnhandledRejection(function(error) {
|
||||
throw error;
|
||||
});
|
||||
var P = new Promise(function(_, reject){reject(e);});
|
||||
});
|
||||
});
|
||||
|
||||
specify("gh-521-promisified", function() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var domain = require('domain').create();
|
||||
var data = {};
|
||||
|
||||
function callsBack(cb) {
|
||||
setTimeout(function() {
|
||||
cb(null, 1);
|
||||
}, 1);
|
||||
}
|
||||
|
||||
var promisified = Promise.promisify(callsBack);
|
||||
domain.on('error', reject);
|
||||
domain.run(function() {
|
||||
process.domain.data = data;
|
||||
resolve(promisified().then(function() {
|
||||
assert.strictEqual(process.domain.data, data);
|
||||
assert.strictEqual(process.domain, domain);
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
specify("gh-521-constructed", function() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var domain = require('domain').create();
|
||||
var data = {asd: 3};
|
||||
domain.on('error', reject);
|
||||
domain.run(function() {
|
||||
var promise = new Promise(function(resolve) {
|
||||
setTimeout(resolve, 1);
|
||||
});
|
||||
|
||||
process.domain.data = data;
|
||||
resolve(promise.then(function() {
|
||||
assert.strictEqual(process.domain.data, data);
|
||||
assert.strictEqual(process.domain, domain);
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("domain preservation" , function() {
|
||||
var Domain = require("domain");
|
||||
|
||||
function createGroupDone(limit, next) {
|
||||
|
||||
return function done(err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
if (--limit <= 0) {
|
||||
next();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
before(function () {
|
||||
var current;
|
||||
while((current = process.domain)) {
|
||||
current.exit();
|
||||
}
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
var current;
|
||||
while((current = process.domain)) {
|
||||
current.exit();
|
||||
}
|
||||
});
|
||||
|
||||
it("should preserve empty domain and this function", function(done) {
|
||||
|
||||
var deferred = new Promise.defer();
|
||||
var p = deferred.promise;
|
||||
|
||||
p.then(function shouldBeEmpty() {
|
||||
assert.equal(false, !!process.domain);
|
||||
}).bind({
|
||||
ref: 'foo'
|
||||
}).then(function shouldKeepThisAndEmptyDomain() {
|
||||
assert.equal(false, !!process.domain);
|
||||
assert.equal('foo', this.ref);
|
||||
done();
|
||||
}).caught(done);
|
||||
|
||||
deferred.resolve("ok");
|
||||
|
||||
});
|
||||
|
||||
it("should preserve empty domain, nodeify", function(done) {
|
||||
done = createGroupDone(3, done);
|
||||
|
||||
var deferred = new Promise.defer();
|
||||
var p = deferred.promise;
|
||||
|
||||
p.then(function shouldBeEmpty() {
|
||||
assert.equal(false, !!process.domain);
|
||||
done();
|
||||
}).bind({
|
||||
ref: 'foo'
|
||||
}).then(function shouldKeepThisAndEmptyDomain() {
|
||||
assert.equal(false, !!process.domain);
|
||||
assert.equal('foo', this.ref);
|
||||
done();
|
||||
}).nodeify(function shouldKeepThisAndEmptyDomain() {
|
||||
try {
|
||||
assert.equal(false, !!process.domain);
|
||||
assert.equal('foo', this.ref);
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
}).caught(done);
|
||||
|
||||
deferred.resolve("ok");
|
||||
|
||||
});
|
||||
|
||||
it("should preserve corresponding state of domain", function(done) {
|
||||
|
||||
done = createGroupDone(6, done);
|
||||
|
||||
var deferred = new Promise.defer();
|
||||
var p = deferred.promise;
|
||||
|
||||
p.then(function shouldBeEmpty() {
|
||||
assert.equal(false, !!process.domain);
|
||||
done();
|
||||
}).bind({
|
||||
ref: 'foo'
|
||||
}).then(function shouldKeepThisAndEmptyDomain() {
|
||||
assert.equal(false, !!process.domain);
|
||||
assert.equal('foo', this.ref);
|
||||
done();
|
||||
}).nodeify(function shouldKeepThisAndEmptyDomain() {
|
||||
try {
|
||||
assert.equal(false, !!process.domain);
|
||||
assert.equal('foo', this.ref);
|
||||
done();
|
||||
} catch (err) { done(err); }
|
||||
}).caught(done);
|
||||
|
||||
var domain = Domain.create();
|
||||
domain.run(function () {
|
||||
p.then(function shouldNoBeEmpty() {
|
||||
assert.equal(domain, process.domain);
|
||||
done();
|
||||
}).bind({
|
||||
ref: 'bar'
|
||||
}).then(function shouldKeepThisAndDomain() {
|
||||
assert.equal(domain, process.domain);
|
||||
assert.equal('bar', this.ref);
|
||||
done();
|
||||
}).caught(done).nodeify(function shouldKeepThisAndDomain() {
|
||||
try {
|
||||
assert.equal(domain, process.domain);
|
||||
assert.equal('bar', this.ref);
|
||||
done();
|
||||
} catch (err) { done(err); }
|
||||
});
|
||||
});
|
||||
|
||||
deferred.resolve("ok");
|
||||
|
||||
});
|
||||
|
||||
it('should preserve corresponding state of domain, complex', function(done) {
|
||||
|
||||
done = createGroupDone(9, done);
|
||||
|
||||
var deferred = new Promise.defer();
|
||||
var p = deferred.promise;
|
||||
p.then(function shouldBeEmpty() {
|
||||
assert.equal(false, !!process.domain);
|
||||
done();
|
||||
}).bind({
|
||||
ref: 'foo'
|
||||
}).then(function shouldKeepThisAndEmptyDomain() {
|
||||
assert.equal(false, !!process.domain);
|
||||
assert.equal('foo', this.ref);
|
||||
done();
|
||||
}).caught(done).nodeify(function shouldKeepThisAndEmptyDomain() {
|
||||
try {
|
||||
assert.equal(false, !!process.domain);
|
||||
assert.equal('foo', this.ref);
|
||||
done();
|
||||
}
|
||||
catch (err) { done(err); }
|
||||
}, done);
|
||||
|
||||
var domain1 = Domain.create();
|
||||
domain1.run(function () {
|
||||
p.then(function shouldNoBeEmpty() {
|
||||
assert.equal(domain1, process.domain);
|
||||
done();
|
||||
}).bind({
|
||||
ref: 'bar'
|
||||
}).then(function shouldKeepThisAndDomain() {
|
||||
assert.equal(domain1, process.domain);
|
||||
assert.equal('bar', this.ref);
|
||||
done();
|
||||
}).caught(done).nodeify(function shouldKeepThisAndDomain() {
|
||||
try {
|
||||
assert.equal(domain1, process.domain);
|
||||
assert.equal('bar', this.ref);
|
||||
done();
|
||||
}
|
||||
catch (err) { done(err); }
|
||||
}, done);
|
||||
});
|
||||
|
||||
var domain2 = Domain.create();
|
||||
domain2.run(function () {
|
||||
p.then(function shouldNoBeEmpty() {
|
||||
assert.equal(domain2, process.domain);
|
||||
done();
|
||||
}).bind({
|
||||
ref: 'qaz'
|
||||
}).then(function shouldKeepThisAndDomain() {
|
||||
assert.equal(domain2, process.domain);
|
||||
assert.equal('qaz', this.ref);
|
||||
done();
|
||||
}).caught(done).nodeify(function shouldKeepThisAndDomain() {
|
||||
try {
|
||||
assert.equal(domain2, process.domain);
|
||||
assert.equal('qaz', this.ref);
|
||||
done();
|
||||
}
|
||||
catch (err) { done(err); }
|
||||
});
|
||||
});
|
||||
|
||||
deferred.resolve("ok");
|
||||
|
||||
});
|
||||
|
||||
it('should preserve corresponding state of domain in reject', function(done) {
|
||||
|
||||
done = createGroupDone(4, done);
|
||||
|
||||
var deferred = new Promise.defer();
|
||||
var p = deferred.promise;
|
||||
|
||||
p.bind({
|
||||
ref: 'foo'
|
||||
}).caught(function shouldKeepThisAndEmptyDomain() {
|
||||
assert.equal(false, !!process.domain);
|
||||
assert.equal('foo', this.ref);
|
||||
done();
|
||||
}).caught(done).nodeify(function shouldKeepThisAndEmptyDomain() {
|
||||
try {
|
||||
assert.equal(false, !!process.domain);
|
||||
assert.equal('foo', this.ref);
|
||||
done();
|
||||
}
|
||||
catch (err) { done(err); }
|
||||
});
|
||||
|
||||
var domain = Domain.create();
|
||||
domain.run(function () {
|
||||
p.bind({
|
||||
ref: 'bar'
|
||||
}).caught(function shouldNoBeEmpty() {
|
||||
assert.equal(true, !!process.domain);
|
||||
assert.equal('bar', this.ref);
|
||||
done();
|
||||
}).caught(done).nodeify(function shouldKeepThisAndDomain(err) {
|
||||
try {
|
||||
assert.equal(true, !!process.domain);
|
||||
assert.equal('bar', this.ref);
|
||||
done();
|
||||
}
|
||||
catch (err) { done(err); }
|
||||
}).caught(done);
|
||||
});
|
||||
|
||||
deferred.reject('bad');
|
||||
|
||||
});
|
||||
|
||||
it('should preserve corresponding state of domain in reject, complex', function(done) {
|
||||
|
||||
done = createGroupDone(6, done);
|
||||
|
||||
var deferred = new Promise.defer();
|
||||
var p = deferred.promise;
|
||||
p.bind({
|
||||
ref: 'foo'
|
||||
}).caught(function shouldBeEmpty() {
|
||||
assert.equal(false, !!process.domain);
|
||||
assert.equal('foo', this.ref);
|
||||
done();
|
||||
}).caught(done).nodeify(function shouldKeepThisAndEmptyDomain() {
|
||||
try {
|
||||
assert.equal(false, !!process.domain);
|
||||
assert.equal('foo', this.ref);
|
||||
done();
|
||||
}
|
||||
catch (err) { done(err); }
|
||||
});
|
||||
|
||||
var domain1 = Domain.create();
|
||||
domain1.run(function () {
|
||||
p.bind({
|
||||
ref: 'bar'
|
||||
}).caught(function shouldNoBeEmpty() {
|
||||
assert.equal(domain1, process.domain);
|
||||
assert.equal('bar', this.ref);
|
||||
done();
|
||||
}).caught(done).nodeify(function shouldKeepThisAndDomain() {
|
||||
try {
|
||||
assert.equal(domain1, process.domain);
|
||||
assert.equal('bar', this.ref);
|
||||
done();
|
||||
}
|
||||
catch (err) { done(err); }
|
||||
});
|
||||
});
|
||||
|
||||
var domain2 = Domain.create();
|
||||
domain2.run(function () {
|
||||
p.bind({
|
||||
ref: 'qaz'
|
||||
}).caught(function shouldNoBeEmpty() {
|
||||
assert.equal(domain2, process.domain);
|
||||
assert.equal('qaz', this.ref);
|
||||
done();
|
||||
}).caught(done).nodeify(function shouldKeepThisAndDomain() {
|
||||
try {
|
||||
assert.equal(domain2, process.domain);
|
||||
assert.equal('qaz', this.ref);
|
||||
done();
|
||||
}
|
||||
catch (err) { done(err); }
|
||||
});
|
||||
});
|
||||
|
||||
deferred.reject('bad');
|
||||
|
||||
});
|
||||
|
||||
it('should preserve domain when using .join', function() {
|
||||
var domain = Domain.create();
|
||||
var d1 = new Promise(function(resolve, reject) {
|
||||
Domain.create().run(function() {
|
||||
setTimeout(resolve, 1);
|
||||
});
|
||||
});
|
||||
var d2 = new Promise(function(resolve, reject) {
|
||||
Domain.create().run(function() {
|
||||
setTimeout(resolve, 1);
|
||||
});
|
||||
});
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
domain.on("error", reject);
|
||||
domain.run(function() {
|
||||
resolve(Promise.join(d1, d2, function() {
|
||||
assert.strictEqual(domain, process.domain);
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should preserve domain when using .using', function() {
|
||||
var domain = Domain.create();
|
||||
var d1 = new Promise(function(resolve, reject) {
|
||||
Domain.create().run(function() {
|
||||
setTimeout(resolve, 1);
|
||||
});
|
||||
});
|
||||
var d2 = new Promise(function(resolve, reject) {
|
||||
Domain.create().run(function() {
|
||||
setTimeout(resolve, 1);
|
||||
});
|
||||
});
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
domain.on("error", reject);
|
||||
domain.run(function() {
|
||||
resolve(Promise.using(d1, d2, function() {
|
||||
assert.strictEqual(domain, process.domain);
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should preserve domain when using .map', function() {
|
||||
var domain = Domain.create();
|
||||
var d1 = new Promise(function(resolve, reject) {
|
||||
Domain.create().run(function() {
|
||||
setTimeout(resolve, 1);
|
||||
});
|
||||
});
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
domain.on("error", reject);
|
||||
domain.run(function() {
|
||||
resolve(Promise.map([d1, null, Promise.resolve(1), Promise.delay(1)], function() {
|
||||
return process.domain;
|
||||
}).then(function(domains) {
|
||||
assert.deepEqual([domain, domain, domain, domain], domains);
|
||||
assert.equal(process.domain, domain);
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should preserve domain when using .filter', function() {
|
||||
var domain = Domain.create();
|
||||
var d1 = new Promise(function(resolve, reject) {
|
||||
Domain.create().run(function() {
|
||||
setTimeout(resolve, 1);
|
||||
});
|
||||
});
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
domain.on("error", reject);
|
||||
domain.run(function() {
|
||||
resolve(Promise.filter([d1, null, Promise.resolve(1), Promise.delay(1)], function() {
|
||||
assert.equal(process.domain, domain);
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should preserve domain when using .reduce', function() {
|
||||
var domain = Domain.create();
|
||||
var d1 = new Promise(function(resolve, reject) {
|
||||
Domain.create().run(function() {
|
||||
setTimeout(resolve, 1);
|
||||
});
|
||||
});
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
domain.on("error", reject);
|
||||
domain.run(function() {
|
||||
resolve(Promise.reduce([d1, null, Promise.resolve(1), Promise.delay(1)], function() {
|
||||
assert.equal(process.domain, domain);
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should preserve domain when using .each', function() {
|
||||
var domain = Domain.create();
|
||||
var d1 = new Promise(function(resolve, reject) {
|
||||
Domain.create().run(function() {
|
||||
setTimeout(resolve, 1);
|
||||
});
|
||||
});
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
domain.on("error", reject);
|
||||
domain.run(function() {
|
||||
resolve(Promise.each([d1, null, Promise.resolve(1), Promise.delay(1)], function() {
|
||||
assert.equal(process.domain, domain);
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should not crash with already rejected promise", function() {
|
||||
return new Promise(function(resolve) {
|
||||
Domain.create().run(function() {
|
||||
Promise.resolve(1).timeout(200).then(function() {
|
||||
resolve();
|
||||
})
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
"use strict";
|
||||
var assert = require("assert");
|
||||
var testUtils = require("./helpers/util.js");
|
||||
var isNodeJS = testUtils.isNodeJS;
|
||||
|
||||
/*!
|
||||
*
|
||||
Copyright 2009–2012 Kristopher Michael Kowal. All rights reserved.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
*/
|
||||
describe("done", function () {
|
||||
var errCount = 0;
|
||||
var safeError = new Error("safe_error");
|
||||
|
||||
describe("when the promise is fulfilled", function () {
|
||||
describe("and the callback does not throw", function () {
|
||||
it("should call the callback and return nothing", function () {
|
||||
var called = false;
|
||||
var promise = Promise.resolve();
|
||||
|
||||
var returnValue = promise.done(function () {
|
||||
called = true;
|
||||
});
|
||||
|
||||
return promise.lastly(function () {
|
||||
assert.equal(called,true);
|
||||
assert.equal(returnValue,undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (isNodeJS) {
|
||||
describe("and the callback throws", function () {
|
||||
it("should rethrow that error in the next turn and return nothing", function() {
|
||||
var turn = 0;
|
||||
process.nextTick(function () {
|
||||
++turn;
|
||||
});
|
||||
|
||||
var returnValue = Promise.resolve().done(
|
||||
function () {
|
||||
throw safeError;
|
||||
}
|
||||
);
|
||||
|
||||
return testUtils.awaitProcessExit(function(e) {
|
||||
assert.equal(turn,1);
|
||||
assert.equal(returnValue,undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
describe("when the promise is rejected", function () {
|
||||
describe("and the errback handles it", function () {
|
||||
it("should call the errback and return nothing", function () {
|
||||
var called = false;
|
||||
|
||||
var promise = Promise.reject("unsafe_error");
|
||||
|
||||
var returnValue = promise.done(
|
||||
function () { },
|
||||
function () {
|
||||
called = true;
|
||||
}
|
||||
);
|
||||
|
||||
return promise.caught(function(){}).lastly(function () {
|
||||
assert.equal(called,true);
|
||||
assert.equal(returnValue,undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (isNodeJS) {
|
||||
describe("and the errback throws", function () {
|
||||
it("should rethrow that error in the next turn and return nothing", function() {
|
||||
var turn = 0;
|
||||
process.nextTick(function () {
|
||||
++turn;
|
||||
});
|
||||
|
||||
var returnValue = Promise.reject("unsafe_error").done(
|
||||
null,
|
||||
function () {
|
||||
throw safeError;
|
||||
}
|
||||
);
|
||||
return testUtils.awaitProcessExit(function(e) {
|
||||
assert.equal(turn,1);
|
||||
assert.equal(returnValue,undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("and there is no errback", function () {
|
||||
it("should throw the original error in the next turn", function() {
|
||||
var turn = 0;
|
||||
process.nextTick(function () {
|
||||
++turn;
|
||||
});
|
||||
|
||||
var returnValue = Promise.reject(safeError).done();
|
||||
return testUtils.awaitProcessExit(function(e) {
|
||||
assert.equal(turn,1);
|
||||
assert.equal(returnValue,undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,184 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testUtils = require("./helpers/util.js");
|
||||
|
||||
|
||||
function promised(val) {
|
||||
return new Promise(function(f) {
|
||||
setTimeout(function() {
|
||||
f(val);
|
||||
}, 1);
|
||||
});
|
||||
}
|
||||
|
||||
function thenabled(val, arr) {
|
||||
return {
|
||||
then: function(f){
|
||||
setTimeout(function() {
|
||||
if (arr) arr.push(val);
|
||||
f(val);
|
||||
}, 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
describe("Promise.each", function() {
|
||||
|
||||
it("should return the array's values mapped", function() {
|
||||
var a = [promised(1), promised(2), promised(3)];
|
||||
var b = [];
|
||||
return Promise.resolve(a).mapSeries(function(val) {
|
||||
b.push(3-val);
|
||||
return val + 2;
|
||||
}).then(function(ret) {
|
||||
assert.deepEqual(ret, [3,4,5]);
|
||||
assert.deepEqual(b, [2, 1, 0]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("takes value, index and length", function() {
|
||||
var a = [promised(1), promised(2), promised(3)];
|
||||
var b = [];
|
||||
return Promise.resolve(a).each(function(value, index, length) {
|
||||
b.push(value, index, length);
|
||||
}).then(function(ret) {
|
||||
assert.deepEqual(b, [1, 0, 3, 2, 1, 3, 3, 2, 3]);
|
||||
});
|
||||
});
|
||||
|
||||
it("waits for returned promise before proceeding next", function() {
|
||||
var a = [promised(1), promised(2), promised(3)];
|
||||
var b = [];
|
||||
return Promise.resolve(a).each(function(value) {
|
||||
b.push(value);
|
||||
return Promise.delay(1).then(function(){
|
||||
b.push(value*2);
|
||||
});
|
||||
}).then(function(ret) {
|
||||
assert.deepEqual(b, [1,2,2,4,3,6]);
|
||||
});
|
||||
});
|
||||
|
||||
it("waits for returned thenable before proceeding next", function() {
|
||||
var b = [1, 2, 3];
|
||||
var a = [thenabled(1), thenabled(2), thenabled(3)];
|
||||
return Promise.resolve(a).each(function(val) {
|
||||
b.push(val * 50);
|
||||
return thenabled(val * 500, b);
|
||||
}).then(function(ret) {
|
||||
assert.deepEqual(b, [1, 2, 3, 50, 500, 100, 1000, 150, 1500]);
|
||||
});
|
||||
});
|
||||
|
||||
it("doesnt iterate with an empty array", function() {
|
||||
return Promise.each([], function(val) {
|
||||
throw new Error();
|
||||
}).then(function(ret) {
|
||||
assert.deepEqual(ret, []);
|
||||
});
|
||||
});
|
||||
|
||||
it("iterates with an array of single item", function() {
|
||||
var b = [];
|
||||
return Promise.each([promised(1)], function(val) {
|
||||
b.push(val);
|
||||
return thenabled(val*2, b);
|
||||
}).then(function(ret) {
|
||||
assert.deepEqual(b, [1,2]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Promise.prototype.each", function() {
|
||||
|
||||
it("should return the array's values", function() {
|
||||
var a = [promised(1), promised(2), promised(3)];
|
||||
var b = [];
|
||||
return Promise.resolve(a).each(function(val) {
|
||||
b.push(3-val);
|
||||
return val;
|
||||
}).then(function(ret) {
|
||||
assert.deepEqual(ret, [1,2,3]);
|
||||
assert.deepEqual(b, [2, 1, 0]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("takes value, index and length", function() {
|
||||
var a = [promised(1), promised(2), promised(3)];
|
||||
var b = [];
|
||||
return Promise.resolve(a).each(function(value, index, length) {
|
||||
b.push(value, index, length);
|
||||
}).then(function(ret) {
|
||||
assert.deepEqual(b, [1, 0, 3, 2, 1, 3, 3, 2, 3]);
|
||||
});
|
||||
});
|
||||
|
||||
it("waits for returned promise before proceeding next", function() {
|
||||
var a = [promised(1), promised(2), promised(3)];
|
||||
var b = [];
|
||||
return Promise.resolve(a).each(function(value) {
|
||||
b.push(value);
|
||||
return Promise.delay(1).then(function(){
|
||||
b.push(value*2);
|
||||
});
|
||||
}).then(function(ret) {
|
||||
assert.deepEqual(b, [1,2,2,4,3,6]);
|
||||
});
|
||||
});
|
||||
|
||||
it("waits for returned thenable before proceeding next", function() {
|
||||
var b = [1, 2, 3];
|
||||
var a = [thenabled(1), thenabled(2), thenabled(3)];
|
||||
return Promise.resolve(a).each(function(val) {
|
||||
b.push(val * 50);
|
||||
return thenabled(val * 500, b);
|
||||
}).then(function(ret) {
|
||||
assert.deepEqual(b, [1, 2, 3, 50, 500, 100, 1000, 150, 1500]);
|
||||
});
|
||||
});
|
||||
|
||||
it("doesnt iterate with an empty array", function() {
|
||||
return Promise.resolve([]).each(function(val) {
|
||||
throw new Error();
|
||||
}).then(function(ret) {
|
||||
assert.deepEqual(ret, []);
|
||||
});
|
||||
});
|
||||
|
||||
it("iterates with an array of single item", function() {
|
||||
var b = [];
|
||||
return Promise.resolve([promised(1)]).each(function(val) {
|
||||
b.push(val);
|
||||
return thenabled(val*2, b);
|
||||
}).then(function(ret) {
|
||||
assert.deepEqual(b, [1,2]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("mapSeries and each", function() {
|
||||
it("is mixed", function() {
|
||||
return Promise.mapSeries([1, 2, 3], function(value) {
|
||||
return value * 2;
|
||||
}).then(function(result) {
|
||||
assert.deepEqual(result, [2, 4, 6]);
|
||||
}).then(function() {
|
||||
return Promise.each([1, 2, 3], function(value) {
|
||||
return value * 2;
|
||||
}).then(function(result) {
|
||||
assert.deepEqual(result, [1, 2, 3]);
|
||||
});
|
||||
}).thenReturn([1, 2, 3]).mapSeries(function(value) {
|
||||
return value * 2;
|
||||
}).then(function(result) {
|
||||
assert.deepEqual(result, [2, 4, 6]);
|
||||
}).thenReturn([1, 2, 3]).each(function(value) {
|
||||
return value * 2;
|
||||
}).then(function(result) {
|
||||
assert.deepEqual(result, [1, 2, 3]);
|
||||
});
|
||||
})
|
||||
});
|
|
@ -0,0 +1,184 @@
|
|||
"use strict";
|
||||
var assert = require("assert");
|
||||
var testUtils = require("./helpers/util.js");
|
||||
|
||||
describe("Promise.prototype.error", function(){
|
||||
describe("catches stuff originating from explicit rejections", function() {
|
||||
specify("using callback", function() {
|
||||
var e = new Promise.TypeError("sup");
|
||||
function callsback(a, b, c, fn) {
|
||||
fn(e);
|
||||
}
|
||||
callsback = Promise.promisify(callsback);
|
||||
|
||||
return callsback(1, 2, 3).error(function(err) {
|
||||
assert(err === e);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("does not catch stuff originating from thrown errors", function() {
|
||||
specify("using constructor", function() {
|
||||
var e = new Error("sup");
|
||||
return new Promise(function(resolve, reject) {
|
||||
throw e;
|
||||
}).error(function(err) {
|
||||
assert.fail();
|
||||
}).then(assert.fail, function(err){
|
||||
assert(err === e);
|
||||
});
|
||||
});
|
||||
specify("using thenable", function() {
|
||||
var e = new Error("sup");
|
||||
var thenable = {
|
||||
then: function(resolve, reject){
|
||||
reject(e);
|
||||
}
|
||||
};
|
||||
return Promise.cast(thenable).error(function(err) {
|
||||
console.error(err);
|
||||
assert.fail();
|
||||
}).then(assert.fail, function(err) {
|
||||
assert(err === e);
|
||||
});
|
||||
});
|
||||
specify("using callback", function() {
|
||||
var e = new Error("sup");
|
||||
function callsback(a, b, c, fn) {
|
||||
throw e;
|
||||
}
|
||||
callsback = Promise.promisify(callsback);
|
||||
|
||||
return callsback(1, 2, 3).error(function(err) {
|
||||
assert.fail();
|
||||
}).then(assert.fail, function(err){
|
||||
assert(err === e);
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
|
||||
if (testUtils.ecmaScript5) {
|
||||
describe("Weird errors", function() {
|
||||
specify("unwritable stack", function() {
|
||||
var e = new Error();
|
||||
var stack = e.stack;
|
||||
Object.defineProperty(e, "stack", {
|
||||
configurable: true,
|
||||
get: function() {return stack;},
|
||||
set: function() {throw new Error("cannot set");}
|
||||
});
|
||||
return new Promise(function(_, reject) {
|
||||
setTimeout(function() {
|
||||
reject(e);
|
||||
}, 1);
|
||||
}).caught(function(err) {
|
||||
assert.equal(e, err);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe("Error constructors", function() {
|
||||
describe("OperationalError", function() {
|
||||
it("should work without new", function() {
|
||||
var a = Promise.OperationalError("msg");
|
||||
assert.strictEqual(a.message, "msg");
|
||||
assert(a instanceof Error);
|
||||
});
|
||||
|
||||
it("should work with new", function() {
|
||||
var a = new Promise.OperationalError("msg");
|
||||
assert.strictEqual(a.message, "msg");
|
||||
assert(a instanceof Error);
|
||||
});
|
||||
|
||||
it("should retain custom properties", function() {
|
||||
var message;
|
||||
var name;
|
||||
function f(cb) {
|
||||
var err = new Error("custom message");
|
||||
message = err.message;
|
||||
name = err.name;
|
||||
err.code = "ENOENT";
|
||||
err.path = "C:\\";
|
||||
cb(err);
|
||||
}
|
||||
return Promise.promisify(f)().error(function(e) {
|
||||
assert.strictEqual(e.message, message);
|
||||
assert.strictEqual(e.name, name);
|
||||
assert(e instanceof Promise.OperationalError);
|
||||
assert.strictEqual(e.code, "ENOENT");
|
||||
assert.strictEqual(e.path, "C:\\");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("CancellationError", function() {
|
||||
it("should work without new", function() {
|
||||
var a = Promise.CancellationError("msg");
|
||||
assert.strictEqual(a.message, "msg");
|
||||
assert(a instanceof Error);
|
||||
});
|
||||
|
||||
it("should work with new", function() {
|
||||
var a = new Promise.CancellationError("msg");
|
||||
assert.strictEqual(a.message, "msg");
|
||||
assert(a instanceof Error);
|
||||
});
|
||||
});
|
||||
|
||||
describe("TimeoutError", function() {
|
||||
it("should work without new", function() {
|
||||
var a = Promise.TimeoutError("msg");
|
||||
assert.strictEqual(a.message, "msg");
|
||||
assert(a instanceof Error);
|
||||
});
|
||||
|
||||
it("should work with new", function() {
|
||||
var a = new Promise.TimeoutError("msg");
|
||||
assert.strictEqual(a.message, "msg");
|
||||
assert(a instanceof Error);
|
||||
});
|
||||
});
|
||||
|
||||
describe("AggregateError", function() {
|
||||
it("should work without new", function() {
|
||||
var a = Promise.AggregateError("msg");
|
||||
assert.strictEqual(a.message, "msg");
|
||||
assert(a instanceof Error);
|
||||
});
|
||||
|
||||
it("should work with new", function() {
|
||||
var a = new Promise.AggregateError("msg");
|
||||
assert.strictEqual(a.message, "msg");
|
||||
assert(a instanceof Error);
|
||||
});
|
||||
|
||||
if (testUtils.isNodeJS) {
|
||||
it("should stringify without circular errors", function() {
|
||||
var a = Promise.AggregateError();
|
||||
a.push(new Error("1"));
|
||||
a.push(new Error("2"));
|
||||
a.push(new Error("3"));
|
||||
a = a.toString();
|
||||
assert(a.indexOf("Error: 1") >= 0);
|
||||
assert(a.indexOf("Error: 2") >= 0);
|
||||
assert(a.indexOf("Error: 3") >= 0);
|
||||
});
|
||||
|
||||
it("should stringify with circular errors", function() {
|
||||
var a = Promise.AggregateError();
|
||||
a.push(new Error("1"));
|
||||
a.push(a);
|
||||
a.push(new Error("3"));
|
||||
a = a.toString();
|
||||
assert(a.indexOf("Error: 1") >= 0);
|
||||
assert(a.indexOf("[Circular AggregateError]") >= 0);
|
||||
assert(a.indexOf("Error: 3") >= 0);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
});
|
|
@ -0,0 +1,120 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testUtils = require("./helpers/util.js");
|
||||
|
||||
|
||||
|
||||
describe("Promise filter", function() {
|
||||
|
||||
function ThrownError() {}
|
||||
|
||||
|
||||
var arr = [1,2,3];
|
||||
|
||||
function assertArr(arr) {
|
||||
assert(arr.length === 2);
|
||||
assert(arr[0] === 1);
|
||||
assert(arr[1] === 3);
|
||||
}
|
||||
|
||||
function assertErr(e) {
|
||||
assert(e instanceof ThrownError);
|
||||
}
|
||||
|
||||
function assertFail() {
|
||||
assert.fail();
|
||||
}
|
||||
|
||||
describe("should accept eventual booleans", function() {
|
||||
specify("immediately fulfilled", function() {
|
||||
return Promise.filter(arr, function(v) {
|
||||
return new Promise(function(r){
|
||||
r(v !== 2);
|
||||
});
|
||||
}).then(assertArr);
|
||||
});
|
||||
|
||||
specify("already fulfilled", function() {
|
||||
return Promise.filter(arr, function(v) {
|
||||
return Promise.resolve(v !== 2);
|
||||
}).then(assertArr);
|
||||
});
|
||||
|
||||
specify("eventually fulfilled", function() {
|
||||
return Promise.filter(arr, function(v) {
|
||||
return new Promise(function(r){
|
||||
setTimeout(function(){
|
||||
r(v !== 2);
|
||||
}, 1);
|
||||
});
|
||||
}).then(assertArr);
|
||||
});
|
||||
|
||||
specify("immediately rejected", function() {
|
||||
return Promise.filter(arr, function(v) {
|
||||
return new Promise(function(v, r){
|
||||
r(new ThrownError());
|
||||
});
|
||||
}).then(assertFail, assertErr);
|
||||
});
|
||||
specify("already rejected", function() {
|
||||
return Promise.filter(arr, function(v) {
|
||||
return Promise.reject(new ThrownError());
|
||||
}).then(assertFail, assertErr);
|
||||
});
|
||||
specify("eventually rejected", function() {
|
||||
return Promise.filter(arr, function(v) {
|
||||
return new Promise(function(v, r){
|
||||
setTimeout(function(){
|
||||
r(new ThrownError());
|
||||
}, 1);
|
||||
});
|
||||
}).then(assertFail, assertErr);
|
||||
});
|
||||
|
||||
|
||||
specify("immediately fulfilled thenable", function() {
|
||||
return Promise.filter(arr, function(v) {
|
||||
return {
|
||||
then: function(f, r) {
|
||||
f(v !== 2);
|
||||
}
|
||||
};
|
||||
}).then(assertArr);
|
||||
});
|
||||
specify("eventually fulfilled thenable", function() {
|
||||
return Promise.filter(arr, function(v) {
|
||||
return {
|
||||
then: function(f, r) {
|
||||
setTimeout(function(){
|
||||
f(v !== 2);
|
||||
}, 1);
|
||||
}
|
||||
};
|
||||
}).then(assertArr);
|
||||
});
|
||||
|
||||
specify("immediately rejected thenable", function() {
|
||||
return Promise.filter(arr, function(v) {
|
||||
return {
|
||||
then: function(f, r) {
|
||||
r(new ThrownError());
|
||||
}
|
||||
};
|
||||
}).then(assertFail, assertErr);
|
||||
});
|
||||
specify("eventually rejected thenable", function() {
|
||||
return Promise.filter(arr, function(v) {
|
||||
return {
|
||||
then: function(f, r) {
|
||||
setTimeout(function(){
|
||||
r(new ThrownError());
|
||||
}, 1);
|
||||
}
|
||||
};
|
||||
}).then(assertFail, assertErr);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -0,0 +1,274 @@
|
|||
"use strict";
|
||||
var assert = require("assert");
|
||||
var testUtils = require("./helpers/util.js");
|
||||
/*!
|
||||
*
|
||||
Copyright 2009–2012 Kristopher Michael Kowal. All rights reserved.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
describe("finally", function () {
|
||||
|
||||
var exception1 = new Error("boo!");
|
||||
var exception2 = new Promise.TypeError("evil!");
|
||||
|
||||
describe("when nothing is passed", function() {
|
||||
it("should do nothing", function() {
|
||||
return Promise.resolve("foo")
|
||||
.lastly()
|
||||
.lastly()
|
||||
.lastly()
|
||||
.lastly()
|
||||
.then(function(val){
|
||||
assert(val === "foo");
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
describe("when the promise is fulfilled", function () {
|
||||
|
||||
it("should call the callback", function() {
|
||||
var called = false;
|
||||
|
||||
return Promise.resolve("foo")
|
||||
.lastly(function () {
|
||||
called = true;
|
||||
})
|
||||
.then(function () {
|
||||
assert.equal(called,true);
|
||||
});
|
||||
});
|
||||
|
||||
it("should fulfill with the original value", function() {
|
||||
return Promise.resolve("foo")
|
||||
.lastly(function () {
|
||||
return "bar";
|
||||
})
|
||||
.then(function (result) {
|
||||
assert.equal(result,"foo");
|
||||
});
|
||||
});
|
||||
|
||||
describe("when the callback returns a promise", function () {
|
||||
|
||||
describe("that is fulfilled", function () {
|
||||
it("should fulfill with the original reason after that promise resolves", function() {
|
||||
var promise = Promise.delay(1);
|
||||
|
||||
return Promise.resolve("foo")
|
||||
.lastly(function () {
|
||||
return promise;
|
||||
})
|
||||
.then(function (result) {
|
||||
assert.equal(promise.isPending(),false);
|
||||
assert.equal(result,"foo");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("that is rejected", function () {
|
||||
it("should reject with this new rejection reason", function() {
|
||||
return Promise.resolve("foo")
|
||||
.lastly(function () {
|
||||
return Promise.reject(exception1);
|
||||
})
|
||||
.then(function () {
|
||||
assert.equal(false,true);
|
||||
},
|
||||
function (exception) {
|
||||
assert.equal(exception,exception1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("when the callback throws an exception", function () {
|
||||
it("should reject with this new exception", function() {
|
||||
return Promise.resolve("foo")
|
||||
.lastly(function () {
|
||||
throw exception1;
|
||||
})
|
||||
.then(function () {
|
||||
assert.equal(false,true);
|
||||
},
|
||||
function (exception) {
|
||||
assert.equal(exception,exception1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("when the promise is rejected", function () {
|
||||
|
||||
it("should call the callback", function() {
|
||||
var called = false;
|
||||
|
||||
return Promise.reject(exception1)
|
||||
.lastly(function () {
|
||||
called = true;
|
||||
})
|
||||
.then(function () {
|
||||
assert.fail();
|
||||
}, function () {
|
||||
assert.equal(called,true);
|
||||
});
|
||||
});
|
||||
|
||||
it("should reject with the original reason", function() {
|
||||
return Promise.reject(exception1)
|
||||
.lastly(function () {
|
||||
return "bar";
|
||||
})
|
||||
.then(function () {
|
||||
assert.equal(false,true);
|
||||
},
|
||||
function (exception) {
|
||||
assert.equal(exception,exception1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when the callback returns a promise", function () {
|
||||
|
||||
describe("that is fulfilled", function () {
|
||||
it("should reject with the original reason after that promise resolves", function() {
|
||||
var promise = Promise.delay(1);
|
||||
|
||||
return Promise.reject(exception1)
|
||||
.lastly(function () {
|
||||
return promise;
|
||||
})
|
||||
.then(function () {
|
||||
assert.equal(false,true);
|
||||
},
|
||||
function (exception) {
|
||||
assert.equal(exception,exception1);
|
||||
assert.equal(promise.isPending(),false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("that is rejected", function () {
|
||||
it("should reject with the new reason", function() {
|
||||
return Promise.reject(exception1)
|
||||
.lastly(function () {
|
||||
return Promise.reject(exception2);
|
||||
})
|
||||
.then(function () {
|
||||
assert.equal(false,true);
|
||||
},
|
||||
function (exception) {
|
||||
assert.equal(exception,exception2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("when the callback throws an exception", function () {
|
||||
it("should reject with this new exception", function() {
|
||||
return Promise.reject(exception1)
|
||||
.lastly(function () {
|
||||
throw exception2;
|
||||
})
|
||||
.then(function () {
|
||||
assert.equal(false,true);
|
||||
},
|
||||
function (exception) {
|
||||
assert.equal(exception,exception2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("when the callback returns a thenable", function () {
|
||||
|
||||
describe("that will fulfill", function () {
|
||||
it("should reject with the original reason after that", function() {
|
||||
var promise = {
|
||||
then: function(fn) {
|
||||
setTimeout(function(){
|
||||
fn(15);
|
||||
}, 1);
|
||||
}
|
||||
};
|
||||
|
||||
return Promise.reject(exception1)
|
||||
.lastly(function () {
|
||||
return promise;
|
||||
})
|
||||
.then(function () {
|
||||
assert.equal(false,true);
|
||||
},
|
||||
function (exception) {
|
||||
assert.equal(exception,exception1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("that is rejected", function () {
|
||||
it("should reject with the new reason", function() {
|
||||
var promise = {
|
||||
then: function(f, fn) {
|
||||
setTimeout(function(){
|
||||
fn(exception2);
|
||||
}, 1);
|
||||
}
|
||||
};
|
||||
|
||||
return Promise.reject(exception1)
|
||||
.lastly(function () {
|
||||
return promise;
|
||||
})
|
||||
.then(function () {
|
||||
assert.equal(false,true);
|
||||
},
|
||||
function (exception) {
|
||||
assert.equal(exception,exception2);
|
||||
});
|
||||
});
|
||||
it("should reject with the new primitive reason", function() {
|
||||
var primitive = 3;
|
||||
var promise = {
|
||||
then: function(f, fn) {
|
||||
setTimeout(function(){
|
||||
fn(primitive);
|
||||
}, 1);
|
||||
}
|
||||
};
|
||||
|
||||
return Promise.reject(exception1)
|
||||
.lastly(function () {
|
||||
return promise;
|
||||
})
|
||||
.then(function () {
|
||||
assert.equal(false,true);
|
||||
},
|
||||
function (exception) {
|
||||
assert.strictEqual(exception, primitive);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
});
|
|
@ -0,0 +1,185 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testUtils = require("./helpers/util.js");
|
||||
|
||||
|
||||
describe("Using deferreds", function() {
|
||||
describe("a promise A that is following a promise B", function() {
|
||||
specify("Must not react to fulfill/reject/ that don't come from promise B", function() {
|
||||
var deferred = Promise.defer();
|
||||
var promiseA = deferred.promise;
|
||||
var promiseB = Promise.defer().promise;
|
||||
var called = 0;
|
||||
function incrementCalled() {
|
||||
called++;
|
||||
}
|
||||
|
||||
promiseA.then(
|
||||
incrementCalled,
|
||||
incrementCalled
|
||||
);
|
||||
deferred.fulfill(promiseB);
|
||||
|
||||
deferred.fulfill(1);
|
||||
deferred.reject(1);
|
||||
return Promise.delay(1).then(function() {
|
||||
assert.equal(0, called);
|
||||
assert.equal(promiseA.isPending(), true);
|
||||
assert.equal(promiseB.isPending(), true);
|
||||
});
|
||||
});
|
||||
|
||||
specify("Must not start following another promise C", function() {
|
||||
var deferred = Promise.defer();
|
||||
var promiseA = deferred.promise;
|
||||
var promiseB = Promise.defer().promise;
|
||||
var deferredC = Promise.defer();
|
||||
var promiseC = deferredC.promise;
|
||||
var called = 0;
|
||||
function incrementCalled() {
|
||||
called++;
|
||||
}
|
||||
|
||||
|
||||
promiseA.then(
|
||||
incrementCalled,
|
||||
incrementCalled
|
||||
);
|
||||
deferred.fulfill(promiseB);
|
||||
deferred.fulfill(promiseC);
|
||||
|
||||
deferredC.fulfill(1);
|
||||
deferredC.reject(1);
|
||||
|
||||
return promiseC.then(function() {
|
||||
assert.equal(called, 0);
|
||||
assert.equal(promiseA.isPending(), true);
|
||||
assert.equal(promiseB.isPending(), true);
|
||||
assert.equal(promiseC.isPending(), false);
|
||||
});
|
||||
});
|
||||
|
||||
specify("Must react to fulfill/reject that come from promise B", function() {
|
||||
var deferred = Promise.defer();
|
||||
var promiseA = deferred.promise;
|
||||
var deferredFollowee = Promise.defer();
|
||||
var promiseB = deferredFollowee.promise;
|
||||
var called = 0;
|
||||
function incrementCalled() {
|
||||
called++;
|
||||
}
|
||||
var c = 0;
|
||||
|
||||
var ret = promiseA.then(function(v){
|
||||
c++;
|
||||
assert.equal(c, 1);
|
||||
assert.equal(called, 0);
|
||||
}, incrementCalled);
|
||||
|
||||
deferred.fulfill(promiseB);
|
||||
|
||||
|
||||
deferredFollowee.fulfill(1);
|
||||
deferredFollowee.reject(1);
|
||||
return ret;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Using static immediate methods", function() {
|
||||
describe("a promise A that is following a promise B", function() {
|
||||
specify("Should be instantly fulfilled with Bs fulfillment value if B was fulfilled", function() {
|
||||
var val = {};
|
||||
var B = Promise.resolve(val);
|
||||
var A = Promise.resolve(B);
|
||||
assert.equal(A.value(), val);
|
||||
assert.equal(A.value(), B.value());
|
||||
});
|
||||
|
||||
specify("Should be instantly fulfilled with Bs parent fulfillment value if B was fulfilled with a parent", function() {
|
||||
var val = {};
|
||||
var parent = Promise.resolve(val);
|
||||
var B = Promise.resolve(parent);
|
||||
var A = Promise.resolve(B);
|
||||
assert.equal(A.value(), val);
|
||||
assert.equal(A.value(), B.value());
|
||||
assert.equal(A.value(), parent.value());
|
||||
});
|
||||
});
|
||||
|
||||
describe("Rejecting a promise A with promise B", function(){
|
||||
specify("Should reject promise A with B as reason ", function() {
|
||||
var val = {};
|
||||
var B = Promise.resolve(val);
|
||||
var A = Promise.reject(B);
|
||||
assert.equal(A.reason(), B);
|
||||
A.then(assert.fail, function(){});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Using constructor", function() {
|
||||
describe("a promise A that is following a promise B", function() {
|
||||
specify("Must not react to fulfill/reject that don't come from promise B", function() {
|
||||
var resolveA;
|
||||
var rejectA;
|
||||
var promiseA = new Promise(function() {
|
||||
resolveA = arguments[0];
|
||||
rejectA = arguments[1];
|
||||
});
|
||||
var promiseB = new Promise(function(){});
|
||||
var called = 0;
|
||||
function incrementCalled() {
|
||||
called++;
|
||||
}
|
||||
|
||||
promiseA.then(
|
||||
incrementCalled,
|
||||
incrementCalled
|
||||
);
|
||||
|
||||
resolveA(promiseB);
|
||||
resolveA(1);
|
||||
rejectA(1);
|
||||
return Promise.delay(1).then(function() {
|
||||
assert.equal(0, called);
|
||||
assert.equal(promiseA.isPending(), true);
|
||||
assert.equal(promiseB.isPending(), true);
|
||||
});
|
||||
});
|
||||
|
||||
specify("Must not start following another promise C", function() {
|
||||
var resolveA;
|
||||
var promiseA = new Promise(function(){
|
||||
resolveA = arguments[0];
|
||||
});
|
||||
var promiseB = new Promise(function(){});
|
||||
var resolveC, rejectC;
|
||||
var promiseC = new Promise(function(){
|
||||
resolveC = arguments[0];
|
||||
rejectC = arguments[1];
|
||||
});
|
||||
var called = 0;
|
||||
function incrementCalled() {
|
||||
called++;
|
||||
}
|
||||
|
||||
promiseA.then(
|
||||
incrementCalled,
|
||||
incrementCalled,
|
||||
incrementCalled
|
||||
);
|
||||
resolveA(promiseB);
|
||||
resolveA(promiseC);
|
||||
resolveC(1);
|
||||
rejectC(1);
|
||||
return promiseC.then(function() {
|
||||
assert.equal(called, 0);
|
||||
assert.equal(promiseA.isPending(), true);
|
||||
assert.equal(promiseB.isPending(), true);
|
||||
assert.equal(promiseC.isPending(), false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,754 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testUtils = require("./helpers/util.js");
|
||||
var assertLongTrace = require("./helpers/assert_long_trace.js");
|
||||
var awaitLateQueue = testUtils.awaitLateQueue;
|
||||
|
||||
function get(arg) {
|
||||
return {
|
||||
then: function(ful, rej) {
|
||||
ful(arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function fail(arg) {
|
||||
return {
|
||||
then: function(ful, rej) {
|
||||
rej(arg)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Promise.coroutine.addYieldHandler(function(yieldedValue) {
|
||||
if (Array.isArray(yieldedValue)) return Promise.all(yieldedValue);
|
||||
});
|
||||
|
||||
var error = new Error("asd");
|
||||
|
||||
describe("yielding", function() {
|
||||
|
||||
specify("non-promise should throw", function() {
|
||||
return Promise.coroutine(function*(){
|
||||
|
||||
var a = yield {};
|
||||
assert.fail();
|
||||
return 4;
|
||||
|
||||
})().then(assert.fail).caught(function(e){
|
||||
assert(e instanceof TypeError);
|
||||
});
|
||||
});
|
||||
|
||||
specify("an array should implicitly Promise.all them", function() {
|
||||
var a = Promise.defer();
|
||||
var ap = a.promise;
|
||||
var b = Promise.defer();
|
||||
var bp = b.promise;
|
||||
var c = Promise.defer();
|
||||
var cp = c.promise;
|
||||
|
||||
|
||||
setTimeout(function(){
|
||||
a.fulfill(1);
|
||||
b.fulfill(2);
|
||||
c.fulfill(3);
|
||||
}, 1);
|
||||
return Promise.coroutine(function*(){
|
||||
return yield [ap, bp, cp];
|
||||
})().then(function(r) {
|
||||
//.spread will also implicitly use .all() so that cannot be used here
|
||||
var a = r[0]; var b = r[1]; var c = r[2];
|
||||
assert(a === 1);
|
||||
assert(b === 2);
|
||||
assert(c === 3);
|
||||
});
|
||||
});
|
||||
|
||||
specify("non-promise should throw but be catchable", function() {
|
||||
|
||||
return Promise.coroutine(function*(){
|
||||
try {
|
||||
var a = yield {};
|
||||
assert.fail();
|
||||
}
|
||||
catch (e){
|
||||
assert(e instanceof TypeError);
|
||||
return 4;
|
||||
}
|
||||
|
||||
})().then(function(val){
|
||||
assert.equal(val, 4);
|
||||
});
|
||||
});
|
||||
|
||||
specify("yielding a function should not call the function", function() {
|
||||
let functionWasCalled = false;
|
||||
return Promise.coroutine(function*(){
|
||||
try {
|
||||
yield (function() {functionWasCalled = true;});
|
||||
}
|
||||
catch(e){
|
||||
assert(e instanceof TypeError);
|
||||
assert.equal(functionWasCalled, false);
|
||||
return 4;
|
||||
}
|
||||
})().then(function(val){
|
||||
assert.equal(val, 4);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("thenables", function(){
|
||||
|
||||
specify("when they fulfill, the yielded value should be that fulfilled value", function(){
|
||||
|
||||
return Promise.coroutine(function*(){
|
||||
|
||||
var a = yield get(3);
|
||||
assert.equal(a, 3);
|
||||
return 4;
|
||||
|
||||
})().then(function(arg){
|
||||
assert.equal(arg, 4);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
specify("when they reject, and the generator doesn't have try.caught, it should immediately reject the promise", function(){
|
||||
|
||||
return Promise.coroutine(function*(){
|
||||
var a = yield fail(error);
|
||||
assert.fail();
|
||||
|
||||
})().then(assert.fail).then(assert.fail, function(e){
|
||||
assert.equal(e, error);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
specify("when they reject, and the generator has try.caught, it should continue working normally", function(){
|
||||
|
||||
return Promise.coroutine(function*(){
|
||||
try {
|
||||
var a = yield fail(error);
|
||||
}
|
||||
catch (e) {
|
||||
return e;
|
||||
}
|
||||
assert.fail();
|
||||
|
||||
})().then(function(v){
|
||||
assert.equal(v, error);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
specify("when they fulfill but then throw, it should become rejection", function(){
|
||||
|
||||
return Promise.coroutine(function*(){
|
||||
var a = yield get(3);
|
||||
assert.equal(a, 3);
|
||||
throw error;
|
||||
})().then(assert.fail, function(e){
|
||||
assert.equal(e, error);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("yield loop", function(){
|
||||
|
||||
specify("should work", function(){
|
||||
return Promise.coroutine(function* () {
|
||||
var a = [1,2,3,4,5];
|
||||
|
||||
for (var i = 0, len = a.length; i < len; ++i) {
|
||||
a[i] = yield get(a[i] * 2);
|
||||
}
|
||||
|
||||
return a;
|
||||
})().then(function(arr){
|
||||
assert.deepEqual([2,4,6,8,10], arr);
|
||||
});
|
||||
});
|
||||
|
||||
specify("inside yield should work", function(){
|
||||
return Promise.coroutine(function *() {
|
||||
var a = [1,2,3,4,5];
|
||||
|
||||
return yield Promise.all(a.map(function(v){
|
||||
return Promise.coroutine(function *() {
|
||||
return yield get(v*2);
|
||||
})();
|
||||
}));
|
||||
})().then(function(arr){
|
||||
assert.deepEqual([2,4,6,8,10], arr);
|
||||
});
|
||||
});
|
||||
|
||||
specify("with simple map should work", function(){
|
||||
return Promise.coroutine(function *() {
|
||||
var a = [1,2,3,4,5];
|
||||
|
||||
return yield Promise.map(a, function(v){
|
||||
return Promise.cast(get(v*2));
|
||||
});
|
||||
})().then(function(arr){
|
||||
assert.deepEqual([2,4,6,8,10], arr);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe("Promise.coroutine", function() {
|
||||
describe("thenables", function() {
|
||||
specify("when they fulfill, the yielded value should be that fulfilled value", function(){
|
||||
|
||||
return Promise.coroutine(function*(){
|
||||
|
||||
var a = yield get(3);
|
||||
assert.equal(a, 3);
|
||||
return 4;
|
||||
|
||||
})().then(function(arg){
|
||||
assert.equal(arg, 4);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
specify("when they reject, and the generator doesn't have try.caught, it should immediately reject the promise", function(){
|
||||
|
||||
return Promise.coroutine(function*(){
|
||||
var a = yield fail(error);
|
||||
assert.fail();
|
||||
|
||||
})().then(assert.fail).then(assert.fail, function(e){
|
||||
assert.equal(e, error);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
specify("when they reject, and the generator has try.caught, it should continue working normally", function(){
|
||||
|
||||
return Promise.coroutine(function*(){
|
||||
try {
|
||||
var a = yield fail(error);
|
||||
}
|
||||
catch (e) {
|
||||
return e;
|
||||
}
|
||||
assert.fail();
|
||||
|
||||
})().then(function(v){
|
||||
assert.equal(v, error);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
specify("when they fulfill but then throw, it should become rejection", function(){
|
||||
|
||||
return Promise.coroutine(function*(){
|
||||
var a = yield get(3);
|
||||
assert.equal(a, 3);
|
||||
throw error;
|
||||
})().then(assert.fail).then(assert.fail, function(e){
|
||||
assert.equal(e, error);
|
||||
});
|
||||
});
|
||||
|
||||
specify("when they are already fulfilled, the yielded value should be returned asynchronously", function(){
|
||||
var value;
|
||||
|
||||
var promise = Promise.coroutine(function*(){
|
||||
yield Promise.resolve();
|
||||
value = 2;
|
||||
})();
|
||||
|
||||
value = 1;
|
||||
|
||||
return promise.then(function(){
|
||||
assert.equal(value, 2);
|
||||
});
|
||||
});
|
||||
|
||||
specify("when they are already rejected, the yielded reason should be thrown asynchronously", function(){
|
||||
var value;
|
||||
|
||||
var promise = Promise.coroutine(function*(){
|
||||
try {
|
||||
yield Promise.reject();
|
||||
}
|
||||
catch (e) {
|
||||
value = 2;
|
||||
}
|
||||
})();
|
||||
|
||||
value = 1;
|
||||
|
||||
return promise.then(function(){
|
||||
assert.equal(value, 2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("yield loop", function(){
|
||||
|
||||
specify("should work", function(){
|
||||
return Promise.coroutine(function* () {
|
||||
var a = [1,2,3,4,5];
|
||||
|
||||
for (var i = 0, len = a.length; i < len; ++i) {
|
||||
a[i] = yield get(a[i] * 2);
|
||||
}
|
||||
|
||||
return a;
|
||||
})().then(function(arr){
|
||||
assert.deepEqual([2,4,6,8,10], arr);
|
||||
});
|
||||
});
|
||||
|
||||
specify("inside yield should work", function(){
|
||||
return Promise.coroutine(function *() {
|
||||
var a = [1,2,3,4,5];
|
||||
|
||||
return yield Promise.all(a.map(function(v){
|
||||
return Promise.coroutine(function *() {
|
||||
return yield get(v*2);
|
||||
})();
|
||||
}));
|
||||
})().then(function(arr){
|
||||
assert.deepEqual([2,4,6,8,10], arr);
|
||||
});
|
||||
});
|
||||
|
||||
specify("with simple map should work", function(){
|
||||
return Promise.coroutine(function *() {
|
||||
var a = [1,2,3,4,5];
|
||||
|
||||
return yield Promise.map(a, function(v){
|
||||
return Promise.cast(get(v*2));
|
||||
});
|
||||
})().then(function(arr){
|
||||
assert.deepEqual([2,4,6,8,10], arr);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("when using coroutine as a method", function(){
|
||||
|
||||
function MyClass() {
|
||||
this.goblins = 3;
|
||||
}
|
||||
|
||||
MyClass.prototype.spawnGoblins = Promise.coroutine(function* () {
|
||||
this.goblins = yield get(this.goblins+1);
|
||||
});
|
||||
|
||||
|
||||
specify("generator function's receiver should be the instance too", function() {
|
||||
var a = new MyClass();
|
||||
var b = new MyClass();
|
||||
|
||||
return Promise.join(a.spawnGoblins().then(function(){
|
||||
return a.spawnGoblins()
|
||||
}), b.spawnGoblins()).then(function(){
|
||||
assert.equal(a.goblins, 5);
|
||||
assert.equal(b.goblins, 4);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Spawn", function() {
|
||||
it("should work", function() {
|
||||
return Promise.spawn(function*() {
|
||||
return yield Promise.resolve(1);
|
||||
}).then(function(value) {
|
||||
assert.strictEqual(value, 1);
|
||||
});
|
||||
});
|
||||
it("should return rejected promise when passed non function", function() {
|
||||
return Promise.spawn({}).then(assert.fail, function(err) {
|
||||
assert(err instanceof Promise.TypeError);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("custom yield handlers", function() {
|
||||
specify("should work with timers", function() {
|
||||
var n = 0;
|
||||
Promise.coroutine.addYieldHandler(function(v) {
|
||||
if (typeof v === "number") {
|
||||
n = 1;
|
||||
return Promise.resolve(n);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return Promise.coroutine(function*() {
|
||||
return yield 50;
|
||||
})().then(function(value) {
|
||||
assert.equal(value, 1);
|
||||
assert.equal(n, 1);
|
||||
});
|
||||
});
|
||||
|
||||
var _ = (function() {
|
||||
var promise = null;
|
||||
Promise.coroutine.addYieldHandler(function(v) {
|
||||
if (v === void 0 && promise != null) {
|
||||
return promise;
|
||||
}
|
||||
promise = null;
|
||||
});
|
||||
return function() {
|
||||
var cb;
|
||||
promise = Promise.fromNode(function(callback) {
|
||||
cb = callback;
|
||||
});
|
||||
return cb;
|
||||
};
|
||||
})();
|
||||
|
||||
specify("Should work with callbacks", function(){
|
||||
var callbackApiFunction = function(a, b, c, cb) {
|
||||
setTimeout(function(){
|
||||
cb(null, [a, b, c]);
|
||||
}, 1);
|
||||
};
|
||||
|
||||
return Promise.coroutine(function*() {
|
||||
return yield callbackApiFunction(1, 2, 3, _());
|
||||
})().then(function(result) {
|
||||
assert(result.length === 3);
|
||||
assert(result[0] === 1);
|
||||
assert(result[1] === 2);
|
||||
assert(result[2] === 3);
|
||||
});
|
||||
});
|
||||
|
||||
specify("should work with thunks", function(){
|
||||
Promise.coroutine.addYieldHandler(function(v) {
|
||||
if (typeof v === "function") {
|
||||
var cb;
|
||||
var promise = Promise.fromNode(function(callback) {
|
||||
cb = callback;
|
||||
});
|
||||
try { v(cb); } catch (e) { cb(e); }
|
||||
return promise;
|
||||
}
|
||||
});
|
||||
|
||||
var thunk = function(a) {
|
||||
return function(callback) {
|
||||
setTimeout(function(){
|
||||
callback(null, a*a);
|
||||
}, 1);
|
||||
};
|
||||
};
|
||||
|
||||
return Promise.coroutine(function*() {
|
||||
return yield thunk(4);
|
||||
})().then(function(result) {
|
||||
assert(result === 16);
|
||||
});
|
||||
});
|
||||
|
||||
specify("individual yield handler", function() {
|
||||
var dummy = {};
|
||||
var yieldHandler = function(value) {
|
||||
if (value === dummy) return Promise.resolve(3);
|
||||
};
|
||||
var coro = Promise.coroutine(function* () {
|
||||
return yield dummy;
|
||||
}, {yieldHandler: yieldHandler});
|
||||
|
||||
return coro().then(function(result) {
|
||||
assert(result === 3);
|
||||
});
|
||||
});
|
||||
|
||||
specify("yield handler that throws", function() {
|
||||
var dummy = {};
|
||||
var unreached = false;
|
||||
var err = new Error();
|
||||
var yieldHandler = function(value) {
|
||||
if (value === dummy) throw err;
|
||||
};
|
||||
|
||||
var coro = Promise.coroutine(function* () {
|
||||
yield dummy;
|
||||
unreached = true;
|
||||
}, {yieldHandler: yieldHandler});
|
||||
|
||||
return coro().then(assert.fail, function(e) {
|
||||
assert.strictEqual(e, err);
|
||||
assert(!unreached);
|
||||
});
|
||||
});
|
||||
|
||||
specify("yield handler is not a function", function() {
|
||||
try {
|
||||
Promise.coroutine.addYieldHandler({});
|
||||
} catch (e) {
|
||||
assert(e instanceof Promise.TypeError);
|
||||
return;
|
||||
}
|
||||
assert.fail();
|
||||
});
|
||||
});
|
||||
|
||||
if (Promise.hasLongStackTraces()) {
|
||||
describe("Long stack traces with coroutines as context", function() {
|
||||
it("1 level", function() {
|
||||
return Promise.coroutine(function* () {
|
||||
yield Promise.delay(10);
|
||||
throw new Error();
|
||||
})().then(assert.fail, function(e) {
|
||||
assertLongTrace(e, 1+1, [2]);
|
||||
});
|
||||
});
|
||||
it("4 levels", function() {
|
||||
var secondLevel = Promise.coroutine(function* () {
|
||||
yield thirdLevel();
|
||||
});
|
||||
var thirdLevel = Promise.coroutine(function* () {
|
||||
yield fourthLevel();
|
||||
});
|
||||
var fourthLevel = Promise.coroutine(function* () {
|
||||
throw new Error();
|
||||
});
|
||||
|
||||
return Promise.coroutine(function* () {
|
||||
yield secondLevel();
|
||||
})().then(assert.fail, function(e) {
|
||||
assertLongTrace(e, 4+1, [2, 2, 2, 2]);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe("Cancellation with generators", function() {
|
||||
specify("input immediately cancelled", function() {
|
||||
var cancelled = 0;
|
||||
var finalled = 0;
|
||||
var unreached = 0;
|
||||
|
||||
var p = new Promise(function(_, __, onCancel) {});
|
||||
p.cancel();
|
||||
|
||||
var asyncFunction = Promise.coroutine(function* () {
|
||||
try {
|
||||
yield p;
|
||||
unreached++;
|
||||
} catch(e) {
|
||||
if (e === Promise.coroutine.returnSentinel) throw e;
|
||||
unreached++;
|
||||
} finally {
|
||||
yield Promise.resolve();
|
||||
finalled++;
|
||||
}
|
||||
unreached++;
|
||||
});
|
||||
|
||||
var resolve, reject;
|
||||
var result = new Promise(function() {
|
||||
resolve = arguments[0];
|
||||
reject = arguments[1];
|
||||
});
|
||||
|
||||
asyncFunction()
|
||||
.then(reject, function(e) {
|
||||
if(!(e instanceof Promise.CancellationError)) reject(new Error());
|
||||
})
|
||||
.lastly(function() {
|
||||
finalled++;
|
||||
resolve();
|
||||
});
|
||||
|
||||
return result.then(function() {
|
||||
return awaitLateQueue(function() {
|
||||
assert.equal(2, finalled);
|
||||
assert.equal(0, cancelled);
|
||||
assert.equal(0, unreached);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
specify("input eventually cancelled", function() {
|
||||
var cancelled = 0;
|
||||
var finalled = 0;
|
||||
var unreached = 0;
|
||||
|
||||
var p = new Promise(function(_, __, onCancel) {});
|
||||
var asyncFunction = Promise.coroutine(function* () {
|
||||
try {
|
||||
yield p;
|
||||
unreached++;
|
||||
} catch(e) {
|
||||
if (e === Promise.coroutine.returnSentinel) throw e;
|
||||
unreached++;
|
||||
} finally {
|
||||
yield Promise.resolve();
|
||||
finalled++;
|
||||
}
|
||||
unreached++;
|
||||
});
|
||||
|
||||
var resolve, reject;
|
||||
var result = new Promise(function() {
|
||||
resolve = arguments[0];
|
||||
reject = arguments[1];
|
||||
});
|
||||
|
||||
asyncFunction()
|
||||
.then(reject, reject)
|
||||
.lastly(function() {
|
||||
finalled++;
|
||||
resolve();
|
||||
});
|
||||
|
||||
Promise.delay(1).then(function() {
|
||||
p.cancel();
|
||||
});
|
||||
|
||||
return result.then(function() {
|
||||
return awaitLateQueue(function() {
|
||||
assert.equal(2, finalled);
|
||||
assert.equal(0, cancelled);
|
||||
assert.equal(0, unreached);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
specify("output immediately cancelled", function() {
|
||||
var cancelled = 0;
|
||||
var finalled = 0;
|
||||
var unreached = 0;
|
||||
|
||||
var p = new Promise(function(_, __, onCancel) {
|
||||
onCancel(function() {
|
||||
cancelled++;
|
||||
});
|
||||
}).lastly(function() {
|
||||
finalled++;
|
||||
});
|
||||
|
||||
var asyncFunction = Promise.coroutine(function* () {
|
||||
try {
|
||||
yield p;
|
||||
unreached++;
|
||||
} catch(e) {
|
||||
if (e === Promise.coroutine.returnSentinel) throw e;
|
||||
unreached++;
|
||||
} finally {
|
||||
yield Promise.resolve()
|
||||
finalled++;
|
||||
}
|
||||
unreached++;
|
||||
});
|
||||
|
||||
var resolve, reject;
|
||||
var result = new Promise(function() {
|
||||
resolve = arguments[0];
|
||||
reject = arguments[1];
|
||||
});
|
||||
|
||||
var output = asyncFunction()
|
||||
.then(reject, reject)
|
||||
.lastly(function() {
|
||||
finalled++;
|
||||
resolve();
|
||||
});
|
||||
|
||||
output.cancel();
|
||||
|
||||
return result.then(function() {
|
||||
return awaitLateQueue(function() {
|
||||
assert.equal(3, finalled);
|
||||
assert.equal(1, cancelled);
|
||||
assert.equal(0, unreached);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
specify("output eventually cancelled", function() {
|
||||
var cancelled = 0;
|
||||
var finalled = 0;
|
||||
var unreached = 0;
|
||||
|
||||
var p = new Promise(function(_, __, onCancel) {
|
||||
onCancel(function() {
|
||||
cancelled++;
|
||||
});
|
||||
}).lastly(function() {
|
||||
finalled++;
|
||||
});
|
||||
|
||||
var asyncFunction = Promise.coroutine(function* () {
|
||||
try {
|
||||
yield p;
|
||||
unreached++;
|
||||
} catch(e) {
|
||||
if (e === Promise.coroutine.returnSentinel) throw e;
|
||||
unreached++;
|
||||
} finally {
|
||||
yield Promise.resolve()
|
||||
finalled++;
|
||||
}
|
||||
unreached++;
|
||||
});
|
||||
|
||||
var resolve, reject;
|
||||
var result = new Promise(function() {
|
||||
resolve = arguments[0];
|
||||
reject = arguments[1];
|
||||
});
|
||||
|
||||
var output = asyncFunction()
|
||||
.then(reject, reject)
|
||||
.lastly(function() {
|
||||
finalled++;
|
||||
resolve();
|
||||
});
|
||||
|
||||
Promise.delay(1).then(function() {
|
||||
output.cancel();
|
||||
});
|
||||
|
||||
return result.then(function() {
|
||||
return awaitLateQueue(function() {
|
||||
assert.equal(3, finalled);
|
||||
assert.equal(1, cancelled);
|
||||
assert.equal(0, unreached);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
specify("finally block runs before finally handler", function(done) {
|
||||
var finallyBlockCalled = false;
|
||||
var asyncFn = Promise.coroutine(function* () {
|
||||
try {
|
||||
yield Promise.delay(100);
|
||||
} finally {
|
||||
yield Promise.delay(100);
|
||||
finallyBlockCalled = true;
|
||||
}
|
||||
});
|
||||
var p = asyncFn();
|
||||
Promise.resolve().then(function() {
|
||||
p.cancel();
|
||||
});
|
||||
p.finally(function() {
|
||||
assert.ok(finallyBlockCalled, "finally block should have been called before finally handler");
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,83 @@
|
|||
"use strict";
|
||||
var assert = require("assert");
|
||||
var testUtils = require("./helpers/util.js");
|
||||
var join = Promise.join;
|
||||
|
||||
describe("indexed getter", function() {
|
||||
var p = Promise.resolve([0, 1, 2, 3, 4, 5, 7, 5,10]);
|
||||
specify("gets positive index", function() {
|
||||
var first = p.get(0);
|
||||
var fourth = p.get(3);
|
||||
var last = p.get(8);
|
||||
|
||||
return join(first, fourth, last, function(a, b, c) {
|
||||
assert(a === 0);
|
||||
assert(b === 3);
|
||||
assert(c === 10);
|
||||
});
|
||||
});
|
||||
|
||||
specify("gets negative index", function() {
|
||||
var last = p.get(-1);
|
||||
var first = p.get(-20);
|
||||
|
||||
return join(last, first, function(a, b) {
|
||||
assert.equal(a, 10);
|
||||
assert.equal(b, 0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("identifier getter", function() {
|
||||
var p = Promise.resolve(new RegExp("", ""));
|
||||
specify("gets property", function() {
|
||||
var ci = p.get("ignoreCase");
|
||||
var g = p.get("global");
|
||||
var lastIndex = p.get("lastIndex");
|
||||
var multiline = p.get("multiline");
|
||||
|
||||
return join(ci, g, lastIndex, multiline, function(ci, g, lastIndex, multiline) {
|
||||
assert(ci === false);
|
||||
assert(g === false);
|
||||
assert(lastIndex === 0);
|
||||
assert(multiline === false);
|
||||
});
|
||||
});
|
||||
|
||||
specify("gets same property", function() {
|
||||
var o = {o: 1};
|
||||
var o2 = {o: 2};
|
||||
o = Promise.resolve(o).get("o");
|
||||
o2 = Promise.resolve(o2).get("o");
|
||||
return join(o, o2, function(one, two) {
|
||||
assert.strictEqual(1, one);
|
||||
assert.strictEqual(2, two);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("non identifier getters", function() {
|
||||
var p = Promise.resolve({"-": "val"});
|
||||
specify("get property", function() {
|
||||
return p.get("-").then(function(val) {
|
||||
assert(val === "val");
|
||||
});
|
||||
});
|
||||
|
||||
specify.skip("overflow cache", function() {
|
||||
var a = new Array(1024);
|
||||
var o = {};
|
||||
for (var i = 0; i < a.length; ++i) {
|
||||
a[i] = "get" + i;
|
||||
o["get" + i] = i*2;
|
||||
}
|
||||
var b = Promise.map(a, function(item, index) {
|
||||
return Promise.resolve(o).get(a[index]);
|
||||
}).filter(function(value, index) {
|
||||
return value === index * 2;
|
||||
}).then(function(values) {
|
||||
assert.strictEqual(values.length, a.length);
|
||||
});
|
||||
return b;
|
||||
});
|
||||
});
|
|
@ -0,0 +1,30 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var testUtils = require("./helpers/util.js");
|
||||
|
||||
describe("Promise.getNewLibraryCopy", function() {
|
||||
it("should return an independent copy of Bluebird library", function() {
|
||||
var Promise2 = Promise.getNewLibraryCopy();
|
||||
Promise2.x = 123;
|
||||
|
||||
assert.equal(typeof Promise2.prototype.then, "function");
|
||||
assert.notEqual(Promise2, Promise);
|
||||
|
||||
assert.equal(Promise2.x, 123);
|
||||
assert.notEqual(Promise.x, 123);
|
||||
});
|
||||
it("should return copy of Bluebird library with its own getNewLibraryCopy method", function() {
|
||||
var Promise2 = Promise.getNewLibraryCopy();
|
||||
var Promise3 = Promise2.getNewLibraryCopy();
|
||||
Promise3.x = 123;
|
||||
|
||||
assert.equal(typeof Promise3.prototype.then, "function");
|
||||
assert.notEqual(Promise3, Promise);
|
||||
assert.notEqual(Promise3, Promise2);
|
||||
|
||||
assert.equal(Promise3.x, 123);
|
||||
assert.notEqual(Promise.x, 123);
|
||||
assert.notEqual(Promise2.x, 123);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,21 @@
|
|||
"use strict";
|
||||
|
||||
|
||||
Promise.longStackTraces();
|
||||
var assert = require("assert");
|
||||
var testUtils = require("./helpers/util.js");
|
||||
var isNodeJS = testUtils.isNodeJS;
|
||||
|
||||
|
||||
if (isNodeJS) {
|
||||
describe("github276 - stack trace cleaner", function(){
|
||||
specify("message with newline and a$_b should not be removed", function(){
|
||||
return Promise.resolve(1).then(function() {
|
||||
throw new Error("Blah\n a$_b");
|
||||
}).then(assert.fail, function(e) {
|
||||
var msg = e.stack.split('\n')[1]
|
||||
assert(msg.indexOf('a$_b') >= 0, 'message should contain a$_b');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
var Promise = adapter;
|
||||
|
||||
function defer() {
|
||||
var resolve, reject;
|
||||
var promise = new Promise(function() {
|
||||
resolve = arguments[0];
|
||||
reject = arguments[1];
|
||||
});
|
||||
return {
|
||||
resolve: resolve,
|
||||
reject: reject,
|
||||
promise: promise
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
describe("github-364", function() {
|
||||
specify("resolve between thens", function(done) {
|
||||
var calls = 0;
|
||||
var def = defer();
|
||||
|
||||
def.promise.then(function() {
|
||||
calls++
|
||||
});
|
||||
def.resolve();
|
||||
def.promise.then(function() {
|
||||
calls++
|
||||
}).then(function() {
|
||||
calls++
|
||||
}).then(function() {
|
||||
Promise.delay(11).then(function() {
|
||||
assert.equal(calls, 3);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue