├── .editorconfig
├── .gitignore
├── .npmignore
├── .jshintignore
├── monitor
├── README.md
├── console.js
├── error.js
├── ConsoleReporter.js
└── PromiseMonitor.js
├── test
├── browser
│ └── index.html
├── monitor
│ ├── lift-node.js
│ ├── delay-handled.js
│ ├── index.html
│ ├── PromiseMonitor-test.js
│ ├── all.js
│ ├── map.js
│ ├── done.js
│ ├── unhandled-begets-unhandled.js
│ ├── developer-error.js
│ ├── unhandled-forever.js
│ ├── multiple-escapes.js
│ ├── unhandledRejectionApi-test.js
│ ├── unhandled-handled-later.js
│ └── deep-chain.js
├── buster.js
├── promises-aplus-adapter.js
├── unhandledRejection-test.js
├── else-test.js
├── browsers.json
├── unfold
│ └── list-test.js
├── reject-test.js
├── format-test.js
├── isPromiseLike-test.js
├── join-test.js
├── parallel-test.js
├── fold-test.js
├── cycle-test.js
├── pipeline-test.js
├── delay-test.js
├── sequence-test.js
├── any-test.js
├── cancelable-test.js
├── settle-test.js
├── inspect-test.js
├── race-test.js
├── filter-test.js
├── liftAll-test.js
├── timeout-test.js
├── some-test.js
├── globalRejectionEvents-test.js
├── poll-test.js
├── with-test.js
├── all-test.js
├── map-test.js
├── guard-test.js
├── when-test.js
├── resolve-test.js
├── iterate-test.js
├── keys-test.js
├── flow-test.js
└── sauce.js
├── es6-shim
├── README.md
└── Promise.browserify-es6.js
├── node
└── function.js
├── unfold.js
├── .travis.yml
├── lib
├── Promise.js
├── decorators
│ ├── inspect.js
│ ├── progress.js
│ ├── fold.js
│ ├── with.js
│ ├── timed.js
│ ├── unhandledRejection.js
│ ├── iterate.js
│ └── flow.js
├── TimeoutError.js
├── liftAll.js
├── state.js
├── apply.js
├── format.js
├── Scheduler.js
└── env.js
├── .jshintrc
├── benchmark
├── index.html
├── map.js
├── run.js
└── promise.js
├── monitor.js
├── delay.js
├── bower.json
├── timeout.js
├── unfold
└── list.js
├── parallel.js
├── LICENSE.txt
├── sequence.js
├── CONTRIBUTING.md
├── pipeline.js
├── cancelable.js
├── guard.js
├── generator.js
├── keys.js
├── poll.js
├── docs
├── installation.md
├── es6-promise-shim.md
└── debug-api.md
├── package.json
├── README.md
└── function.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = tab
5 | end_of_line = LF
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | experiments/
3 | node_modules/
4 | build/when.js
5 | dist/
6 | test/browser/*.js
7 | bower_components/
8 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | test/
2 | benchmark/
3 | experiments/
4 | docs/
5 | build/
6 | *.md
7 | .*
8 | *~
9 | bower.json
10 | bower_components/
--------------------------------------------------------------------------------
/.jshintignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .git/
3 | .idea/
4 | experiments/
5 | test/monitor/
6 | test/browser/
7 | es6-shim/
8 | build/when.js
9 | bower_components/
10 | dist/
11 |
--------------------------------------------------------------------------------
/monitor/README.md:
--------------------------------------------------------------------------------
1 | # Promise monitoring and debugging
2 |
3 | This dir contains experimental new promise monitoring and debugging utilities for when.js. See [the docs](../docs/api.md#debugging-promises).
4 |
--------------------------------------------------------------------------------
/test/browser/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | when.js browser tests
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/test/monitor/lift-node.js:
--------------------------------------------------------------------------------
1 | //require('../../monitor/console');
2 | var node = require('../../node');
3 |
4 | function test(cb) {
5 | throw new Error('fail');
6 | // cb(new Error('fail'));
7 | }
8 |
9 | var f = node.lift(test);
10 |
11 | f();
--------------------------------------------------------------------------------
/es6-shim/README.md:
--------------------------------------------------------------------------------
1 | # ES6 Promise shim
2 |
3 | Promise.js in this dir contains a complete ES6 Promise shim built on when.js that adds a global `Promise` in browser, AMD, Node, and other CommonJS environments.
4 |
5 | [Go to the full documentation](../docs/es6-promise-shim.md)
--------------------------------------------------------------------------------
/test/buster.js:
--------------------------------------------------------------------------------
1 | exports.node = {
2 | environment: 'node',
3 | rootPath: '../',
4 | tests: [
5 | 'test/**/*-test.js'
6 | ]
7 | };
8 |
9 | exports.browser = {
10 | environment: 'browser',
11 | rootPath: '../',
12 | tests: [
13 | 'test/browser/tests.js'
14 | ],
15 | testbed: 'test/browser/index.html'
16 | };
17 |
--------------------------------------------------------------------------------
/test/promises-aplus-adapter.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict';
3 |
4 | if(typeof exports === 'object') {
5 |
6 | var when = require('../when');
7 |
8 | // Silence potentially unhandled rejections
9 | when.Promise.onPotentiallyUnhandledRejection = function() {};
10 |
11 | exports.resolved = when.resolve;
12 | exports.rejected = when.reject;
13 | exports.deferred = when.defer;
14 | }
15 | })();
16 |
--------------------------------------------------------------------------------
/node/function.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2013 original author or authors */
2 |
3 | /**
4 | * @author Brian Cavalier
5 | */
6 | (function(define) { 'use strict';
7 | define(function(require) {
8 |
9 | // DEPRECATED: Use when/node instead
10 | return require('../node');
11 |
12 | });
13 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
14 |
--------------------------------------------------------------------------------
/unfold.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright B Cavalier & J Hann */
2 |
3 | /**
4 | * unfold
5 | * @author: brian@hovercraftstudios.com
6 | */
7 | (function(define) {
8 | define(function(require) {
9 |
10 | /**
11 | * @deprecated Use when.unfold
12 | */
13 | return require('./when').unfold;
14 |
15 | });
16 | })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } );
17 |
18 |
--------------------------------------------------------------------------------
/test/monitor/delay-handled.js:
--------------------------------------------------------------------------------
1 | (function(define) { 'use strict';
2 | define(function(require) {
3 |
4 | var when = require('../../when');
5 | var async = require('../../lib/env').asap;
6 |
7 | var p = when.reject(new Error('TEST FAILED, should not see this'));
8 |
9 | async(function() {
10 | p.catch(function(){});
11 | });
12 | });
13 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
14 |
15 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - '0.10'
4 | - '0.12'
5 | - '4'
6 | - '5'
7 | sudo: false
8 | script: npm run ci
9 | branches:
10 | only:
11 | - dev
12 | - master
13 | addons:
14 | apt:
15 | sources:
16 | - ubuntu-toolchain-r-test
17 | packages:
18 | - g++-4.8
19 | env:
20 | global:
21 | - SAUCE_USERNAME="cujojs-when"
22 | - SAUCE_ACCESS_KEY="e5d3d1a5-bc49-4607-8a7e-702a512c7f60"
23 | - CXX=g++-4.8
24 |
--------------------------------------------------------------------------------
/test/monitor/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/monitor/console.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 | /** @author Brian Cavalier */
3 | /** @author John Hann */
4 |
5 | (function(define) { 'use strict';
6 | define(function(require) {
7 |
8 | var monitor = require('../monitor');
9 | var Promise = require('../when').Promise;
10 |
11 | return monitor(Promise);
12 |
13 | });
14 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
15 |
--------------------------------------------------------------------------------
/lib/Promise.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 | /** @author Brian Cavalier */
3 | /** @author John Hann */
4 |
5 | (function(define) { 'use strict';
6 | define(function (require) {
7 |
8 | var makePromise = require('./makePromise');
9 | var Scheduler = require('./Scheduler');
10 | var async = require('./env').asap;
11 |
12 | return makePromise({
13 | scheduler: new Scheduler(async)
14 | });
15 |
16 | });
17 | })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); });
18 |
--------------------------------------------------------------------------------
/es6-shim/Promise.browserify-es6.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 | /** @author Brian Cavalier */
3 | /** @author John Hann */
4 |
5 | /**
6 | * ES6 global Promise shim
7 | */
8 | var unhandledRejections = require('../lib/decorators/unhandledRejection');
9 | var PromiseConstructor = unhandledRejections(require('../lib/Promise'));
10 |
11 | module.exports = typeof global != 'undefined' ? (global.Promise = PromiseConstructor)
12 | : typeof self != 'undefined' ? (self.Promise = PromiseConstructor)
13 | : PromiseConstructor;
14 |
--------------------------------------------------------------------------------
/test/monitor/PromiseMonitor-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 | var fail = buster.referee.fail;
4 |
5 | var Promise = require('../../lib/Promise');
6 | var PromiseMonitor = require('../../monitor/PromiseMonitor');
7 |
8 | buster.testCase('when/monitor/PromiseMonitor', {
9 |
10 | 'should call reporter.configurePromiseMonitor with self': function() {
11 | var spy = this.spy();
12 | var m = new PromiseMonitor({
13 | configurePromiseMonitor: spy
14 | });
15 |
16 | assert.calledOnceWith(spy, m);
17 | }
18 | });
19 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "browser": true,
3 | "node": true,
4 |
5 | "predef": [
6 | "define",
7 | "module",
8 | "system"
9 | ],
10 |
11 | "boss": true,
12 | "curly": true,
13 | "elision": true,
14 | "eqnull": true,
15 | "expr": true,
16 | "globalstrict": false,
17 | "laxbreak": true,
18 | "newcap": true,
19 | "noarg": true,
20 | "noempty": true,
21 | "nonew": true,
22 | "quotmark": "single",
23 | "smarttabs": true,
24 | "strict": false,
25 | "sub": true,
26 | "trailing": true,
27 | "undef": true,
28 | "unused": true,
29 |
30 | "maxdepth": 3,
31 | "maxcomplexity": 5
32 | }
--------------------------------------------------------------------------------
/lib/decorators/inspect.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 | /** @author Brian Cavalier */
3 | /** @author John Hann */
4 |
5 | (function(define) { 'use strict';
6 | define(function(require) {
7 |
8 | var inspect = require('../state').inspect;
9 |
10 | return function inspection(Promise) {
11 |
12 | Promise.prototype.inspect = function() {
13 | return inspect(Promise._handler(this));
14 | };
15 |
16 | return Promise;
17 | };
18 |
19 | });
20 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
21 |
--------------------------------------------------------------------------------
/benchmark/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/test/unhandledRejection-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var unhandledRejection = require('../lib/decorators/unhandledRejection');
3 |
4 | buster.testCase('unhandledRejection', {
5 |
6 | 'should not fail if JSON.stringify throws': function() {
7 | var fixture = unhandledRejection({});
8 | var circle = { self: void 0 };
9 | circle.self = circle;
10 |
11 | buster.refute.exception(function() {
12 | fixture.onPotentiallyUnhandledRejection({
13 | id: 'JSON.stringify circular ref test',
14 | handled: false,
15 | value: circle
16 | });
17 | });
18 | }
19 |
20 | });
21 |
--------------------------------------------------------------------------------
/monitor.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 | /** @author Brian Cavalier */
3 | /** @author John Hann */
4 |
5 | (function(define) { 'use strict';
6 | define(function(require) {
7 |
8 | var PromiseMonitor = require('./monitor/PromiseMonitor');
9 | var ConsoleReporter = require('./monitor/ConsoleReporter');
10 |
11 | var promiseMonitor = new PromiseMonitor(new ConsoleReporter());
12 |
13 | return function(Promise) {
14 | return promiseMonitor.monitor(Promise);
15 | };
16 | });
17 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
18 |
--------------------------------------------------------------------------------
/test/monitor/all.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 |
3 | /**
4 | * Licensed under the MIT License at:
5 | * http://www.opensource.org/licenses/mit-license.php
6 | *
7 | * @author: Brian Cavalier
8 | * @author: John Hann
9 | */
10 |
11 | (function(define) { 'use strict';
12 | define(function(require) {
13 |
14 | // require('../../monitor/console');
15 |
16 | var when = require('../../when');
17 |
18 | var p = when.reject(new Error('fail1'));
19 |
20 | when.all([p]);
21 |
22 | });
23 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
24 |
25 |
--------------------------------------------------------------------------------
/delay.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2011-2013 original author or authors */
2 |
3 | /**
4 | * delay.js
5 | *
6 | * Helper that returns a promise that resolves after a delay.
7 | *
8 | * @author Brian Cavalier
9 | * @author John Hann
10 | */
11 |
12 | (function(define) {
13 | define(function(require) {
14 |
15 | var when = require('./when');
16 |
17 | /**
18 | * @deprecated Use when(value).delay(ms)
19 | */
20 | return function delay(msec, value) {
21 | return when(value).delay(msec);
22 | };
23 |
24 | });
25 | })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); });
26 |
27 |
28 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "when",
3 | "main": "when.js",
4 | "moduleType": ["amd", "node"],
5 | "description": "A lightweight Promises/A+ and when() implementation, plus other async goodies.",
6 | "keywords": ["Promises/A+", "promises-aplus", "promise", "promises", "deferred", "deferreds", "when", "async", "asynchronous", "cujo"],
7 | "homepage": "https://github.com/cujojs/when",
8 | "authors": [
9 | "Brian Cavalier "
10 | ],
11 | "license": "MIT",
12 | "ignore": [
13 | "**/.*",
14 | "**/*.md",
15 | "docs",
16 | "benchmark",
17 | "node_modules",
18 | "bower_components",
19 | "test",
20 | "build"
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/lib/decorators/progress.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 | /** @author Brian Cavalier */
3 | /** @author John Hann */
4 |
5 | (function(define) { 'use strict';
6 | define(function() {
7 |
8 | return function progress(Promise) {
9 |
10 | /**
11 | * @deprecated
12 | * Register a progress handler for this promise
13 | * @param {function} onProgress
14 | * @returns {Promise}
15 | */
16 | Promise.prototype.progress = function(onProgress) {
17 | return this.then(void 0, void 0, onProgress);
18 | };
19 |
20 | return Promise;
21 | };
22 |
23 | });
24 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
25 |
--------------------------------------------------------------------------------
/test/else-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 |
4 | var when = require('../when');
5 |
6 | var input = {};
7 | var sentinel = { value: 'sentinel' };
8 |
9 | buster.testCase('promise.else', {
10 | 'should resolve normally if previous promise doesn\'t fail': function () {
11 |
12 | return when.resolve(input)
13 | ['else'](sentinel)
14 | .then(function (val) {
15 | assert.same(val, input);
16 | });
17 | },
18 |
19 | 'should resolve with else value if previous promise fails': function () {
20 |
21 | return when.reject(input)
22 | ['else'](sentinel)
23 | .then(function (val) {
24 | assert.same(val, sentinel);
25 | });
26 | }
27 | });
28 |
--------------------------------------------------------------------------------
/timeout.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2011-2013 original author or authors */
2 |
3 | /**
4 | * timeout.js
5 | *
6 | * Helper that returns a promise that rejects after a specified timeout,
7 | * if not explicitly resolved or rejected before that.
8 | *
9 | * @author Brian Cavalier
10 | * @author John Hann
11 | */
12 |
13 | (function(define) {
14 | define(function(require) {
15 |
16 | var when = require('./when');
17 |
18 | /**
19 | * @deprecated Use when(trigger).timeout(ms)
20 | */
21 | return function timeout(msec, trigger) {
22 | return when(trigger).timeout(msec);
23 | };
24 | });
25 | })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); });
26 |
27 |
28 |
--------------------------------------------------------------------------------
/lib/decorators/fold.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 | /** @author Brian Cavalier */
3 | /** @author John Hann */
4 | /** @author Jeff Escalante */
5 |
6 | (function(define) { 'use strict';
7 | define(function() {
8 |
9 | return function fold(Promise) {
10 |
11 | Promise.prototype.fold = function(f, z) {
12 | var promise = this._beget();
13 |
14 | this._handler.fold(function(z, x, to) {
15 | Promise._handler(z).fold(function(x, z, to) {
16 | to.resolve(f.call(this, z, x));
17 | }, x, this, to);
18 | }, z, promise._handler.receiver, promise._handler);
19 |
20 | return promise;
21 | };
22 |
23 | return Promise;
24 | };
25 |
26 | });
27 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
28 |
--------------------------------------------------------------------------------
/test/monitor/map.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 |
3 | /**
4 | * Licensed under the MIT License at:
5 | * http://www.opensource.org/licenses/mit-license.php
6 | *
7 | * @author: Brian Cavalier
8 | * @author: John Hann
9 | */
10 |
11 | (function(define) { 'use strict';
12 | define(function(require) {
13 |
14 | // require('../../monitor/console');
15 |
16 | var when = require('../../when');
17 |
18 | var p = when.reject(new Error('fail1'));
19 |
20 | // when.map(p, function(x){return x;});
21 | when.map([p], function(x){return x;});
22 | // when.map([123], fail);
23 |
24 | function fail(x){
25 | throw new Error('map failed');
26 | }
27 |
28 | });
29 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
30 |
31 |
--------------------------------------------------------------------------------
/test/monitor/done.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 |
3 | /**
4 | * Licensed under the MIT License at:
5 | * http://www.opensource.org/licenses/mit-license.php
6 | *
7 | * @author: Brian Cavalier
8 | * @author: John Hann
9 | */
10 |
11 | (function(define) { 'use strict';
12 | define(function(require) {
13 |
14 | // require('../../monitor/console');
15 | var Promise = require('../../when').Promise;
16 |
17 | Promise.resolve(123)
18 | .then(function(x) {
19 | // throw x;
20 | throw new Error(x);
21 | // return Promise.reject(x);
22 | // foo();
23 | // throw new TypeError(x);
24 | })
25 | // .then(void 0, function() { console.log(123);})
26 | .done(console.log);
27 |
28 | });
29 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
30 |
31 |
32 |
--------------------------------------------------------------------------------
/lib/TimeoutError.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 | /** @author Brian Cavalier */
3 | /** @author John Hann */
4 |
5 | (function(define) { 'use strict';
6 | define(function() {
7 |
8 | /**
9 | * Custom error type for promises rejected by promise.timeout
10 | * @param {string} message
11 | * @constructor
12 | */
13 | function TimeoutError (message) {
14 | Error.call(this);
15 | this.message = message;
16 | this.name = TimeoutError.name;
17 | if (typeof Error.captureStackTrace === 'function') {
18 | Error.captureStackTrace(this, TimeoutError);
19 | }
20 | }
21 |
22 | TimeoutError.prototype = Object.create(Error.prototype);
23 | TimeoutError.prototype.constructor = TimeoutError;
24 |
25 | return TimeoutError;
26 | });
27 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
--------------------------------------------------------------------------------
/lib/liftAll.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 | /** @author Brian Cavalier */
3 | /** @author John Hann */
4 |
5 | (function(define) { 'use strict';
6 | define(function() {
7 |
8 | return function liftAll(liftOne, combine, dst, src) {
9 | if(typeof combine === 'undefined') {
10 | combine = defaultCombine;
11 | }
12 |
13 | return Object.keys(src).reduce(function(dst, key) {
14 | var f = src[key];
15 | return typeof f === 'function' ? combine(dst, liftOne(f), key) : dst;
16 | }, typeof dst === 'undefined' ? defaultDst(src) : dst);
17 | };
18 |
19 | function defaultCombine(o, f, k) {
20 | o[k] = f;
21 | return o;
22 | }
23 |
24 | function defaultDst(src) {
25 | return typeof src === 'function' ? src.bind() : Object.create(src);
26 | }
27 | });
28 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
29 |
--------------------------------------------------------------------------------
/test/monitor/unhandled-begets-unhandled.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 |
3 | /**
4 | * Licensed under the MIT License at:
5 | * http://www.opensource.org/licenses/mit-license.php
6 | *
7 | * @author: Brian Cavalier
8 | * @author: John Hann
9 | */
10 |
11 | (function(define) { 'use strict';
12 | define(function(require) {
13 |
14 | // require('../../monitor/console');
15 |
16 | var Promise = require('../../when').Promise;
17 | // var Promise = require('../../es6-shim/Promise');
18 |
19 | var p = new Promise.reject(new Error('first error'));
20 |
21 | setTimeout(function() {
22 | // console.log('***Begetting new unhandled error now***');
23 | p['catch'](function() {
24 | throw new Error('unhandled-begets-unhandled');
25 | });
26 | }, 2000);
27 |
28 | });
29 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
30 |
--------------------------------------------------------------------------------
/test/monitor/developer-error.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 |
3 | /**
4 | * Licensed under the MIT License at:
5 | * http://www.opensource.org/licenses/mit-license.php
6 | *
7 | * @author: Brian Cavalier
8 | * @author: John Hann
9 | */
10 |
11 | (function(define) { 'use strict';
12 | define(function(require) {
13 |
14 | // require('../../monitor/console');
15 |
16 | var Promise = require('../../when').Promise;
17 |
18 | var p = Promise.resolve(123);
19 |
20 | p.then(function() {
21 | oops();
22 | });
23 |
24 | function infiniteRecursion() {
25 | infiniteRecursion();
26 | }
27 |
28 | p.then(infiniteRecursion);
29 |
30 | var notAFunction = {};
31 | function tryToCallNotAFunction() {
32 | notAFunction();
33 | }
34 |
35 | p.then(tryToCallNotAFunction);
36 | });
37 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
38 |
39 |
--------------------------------------------------------------------------------
/test/monitor/unhandled-forever.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 |
3 | /**
4 | * Licensed under the MIT License at:
5 | * http://www.opensource.org/licenses/mit-license.php
6 | *
7 | * @author: Brian Cavalier
8 | * @author: John Hann
9 | */
10 |
11 | (function(define) { 'use strict';
12 | define(function(require) {
13 |
14 | // require('../../monitor/console');
15 |
16 | var Promise = require('../../when').Promise;
17 |
18 | function f1() {
19 | return new Promise(function(_, reject) {
20 | reject(new Error('unhandled-forever'));
21 | });
22 | }
23 |
24 | function f2(p) {
25 | return p.then(function() {});
26 | }
27 |
28 | function f3(p) {
29 | return p.then(function() {});
30 | }
31 |
32 | // f1();
33 | // f2(f1());
34 | f3(f2(f1()));
35 | });
36 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
37 |
38 |
--------------------------------------------------------------------------------
/test/monitor/multiple-escapes.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 |
3 | /**
4 | * Licensed under the MIT License at:
5 | * http://www.opensource.org/licenses/mit-license.php
6 | *
7 | * @author: Brian Cavalier
8 | * @author: John Hann
9 | */
10 |
11 | (function(define) { 'use strict';
12 | define(function(require) {
13 |
14 | // require('../../monitor/console');
15 |
16 | var Promise = require('../../when').Promise;
17 |
18 | var i = 1;
19 | var p = new Promise(function(_, reject) {
20 | setTimeout(reject.bind(null, new Error(i++)), 1);
21 | });
22 |
23 | var p = new Promise(function(_, reject) {
24 | setTimeout(reject.bind(null, new Error(i++)), 1);
25 | });
26 |
27 | var p = new Promise(function(_, reject) {
28 | setTimeout(reject.bind(null, new Error(i++)), 1);
29 | });
30 |
31 | });
32 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
33 |
34 |
--------------------------------------------------------------------------------
/lib/state.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 | /** @author Brian Cavalier */
3 | /** @author John Hann */
4 |
5 | (function(define) { 'use strict';
6 | define(function() {
7 |
8 | return {
9 | pending: toPendingState,
10 | fulfilled: toFulfilledState,
11 | rejected: toRejectedState,
12 | inspect: inspect
13 | };
14 |
15 | function toPendingState() {
16 | return { state: 'pending' };
17 | }
18 |
19 | function toRejectedState(e) {
20 | return { state: 'rejected', reason: e };
21 | }
22 |
23 | function toFulfilledState(x) {
24 | return { state: 'fulfilled', value: x };
25 | }
26 |
27 | function inspect(handler) {
28 | var state = handler.state();
29 | return state === 0 ? toPendingState()
30 | : state > 0 ? toFulfilledState(handler.value)
31 | : toRejectedState(handler.value);
32 | }
33 |
34 | });
35 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
36 |
--------------------------------------------------------------------------------
/test/browsers.json:
--------------------------------------------------------------------------------
1 | [
2 | // we don't really care about the platform, but without it the browser may fail to resolve
3 | { browserName: 'chrome', platform: 'Windows 8.1' },
4 | { browserName: 'firefox', platform: 'Windows 8.1' },
5 | { browserName: 'internet explorer', version: '11', platform: 'Windows 8.1' },
6 | { browserName: 'internet explorer', version: '10', platform: 'Windows 8' },
7 | { browserName: 'internet explorer', version: '9', platform: 'Windows 7' },
8 | { browserName: 'opera', version: '12', platform: 'Windows 7' },
9 | { browserName: 'opera', version: '11', platform: 'Windows 7' },
10 | { browserName: 'safari', version: '7', platform: 'OS X 10.9' },
11 | { browserName: 'safari', version: '6', platform: 'OS X 10.8' },
12 | { browserName: 'ipad', version: '7.1', platform: 'OS X 10.9' },
13 | { browserName: 'ipad', version: '7', platform: 'OS X 10.9' }
14 | ]
--------------------------------------------------------------------------------
/test/monitor/unhandledRejectionApi-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 | var fail = buster.referee.fail;
4 |
5 | var Promise = require('../../lib/Promise');
6 |
7 | function replace(target, method, replacement) {
8 | var tmp = target[method];
9 | target[method] = function() {
10 | target[method] = tmp;
11 | return replacement.apply(this, arguments);
12 | };
13 | }
14 |
15 | buster.testCase('when/unhandledRejectionApi', {
16 |
17 | 'reject should trigger report': function(done) {
18 | replace(Promise, 'onPotentiallyUnhandledRejection', function () {
19 | assert(true);
20 | done();
21 | });
22 |
23 | new Promise(function (_, reject) {
24 | reject();
25 | });
26 | },
27 |
28 | 'Promise.reject should trigger report': function(done) {
29 | replace(Promise, 'onPotentiallyUnhandledRejection', function () {
30 | assert(true);
31 | done();
32 | });
33 |
34 | Promise.reject();
35 | }
36 | });
37 |
--------------------------------------------------------------------------------
/test/unfold/list-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 |
4 | var list = require('../../unfold/list');
5 |
6 | var sentinel = {};
7 |
8 | function noop() {}
9 |
10 | buster.testCase('when/unfold/list', {
11 |
12 | 'should produce an empty list when proceed returns truthy immediately': function(done) {
13 | function condition() {
14 | return true;
15 | }
16 |
17 | list(noop, condition, sentinel).then(
18 | function(value) {
19 | assert.equals(value, []);
20 | }
21 | ).ensure(done);
22 | },
23 |
24 | 'should produce a list of N elements': function(done) {
25 | var len = 3;
26 |
27 | function condition(i) {
28 | return i == len;
29 | }
30 |
31 | function generate(x) {
32 | return [x, x+1];
33 | }
34 |
35 | list(generate, condition, 0).then(
36 | function(result) {
37 | assert.equals(result.length, len);
38 | assert.equals(result, [0, 1, 2]);
39 | }
40 | ).ensure(done);
41 | }
42 | });
43 |
--------------------------------------------------------------------------------
/benchmark/map.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 | /** @author Brian Cavalier */
3 | /** @author John Hann */
4 |
5 | (function(define) { 'use strict';
6 | define(function(require) {
7 |
8 | var when, tests, run;
9 |
10 | when = require('../when');
11 | run = require('./run');
12 |
13 | tests = [
14 | { name: 'map 100', fn: map(100), defer: true },
15 | { name: 'map 1k', fn: map(1e3), defer: true }
16 | ];
17 |
18 | run(tests);
19 |
20 | //
21 | // Benchmark tests
22 | //
23 |
24 | function map(n) {
25 | return function(deferred) {
26 |
27 | var input = [];
28 | for(var i = 0; i < n; i++) {
29 | input.push(when(i));
30 | }
31 |
32 | when.map(input, addOne).then(function() {
33 | deferred.resolve();
34 | });
35 |
36 | };
37 | }
38 |
39 | //
40 | // Promise helpers
41 | //
42 |
43 | function addOne(x) {
44 | return x + 1;
45 | }
46 |
47 | });
48 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
49 |
--------------------------------------------------------------------------------
/test/monitor/unhandled-handled-later.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 |
3 | /**
4 | * Licensed under the MIT License at:
5 | * http://www.opensource.org/licenses/mit-license.php
6 | *
7 | * @author: Brian Cavalier
8 | * @author: John Hann
9 | */
10 |
11 | (function(define) { 'use strict';
12 | define(function(require) {
13 |
14 | // require('../../monitor/console');
15 |
16 | var Promise = require('../../when').Promise;
17 | // var Promise = require('bluebird');
18 |
19 | function run() {
20 | var p = new Promise(function(_, reject) {
21 | reject(new Error('unhandled-handled-later'));
22 | });
23 |
24 | setTimeout(function() {
25 | // console.log('***Handling error now***');
26 | p['catch'](function() { /* handled by squelching */ });
27 | }, 1000);
28 | }
29 |
30 | run();
31 | // run();
32 | // run();
33 | // run();
34 | // run();
35 | // run();
36 | // run();
37 |
38 | });
39 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
40 |
41 |
--------------------------------------------------------------------------------
/unfold/list.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright B Cavalier & J Hann */
2 |
3 | (function(define) {
4 | define(function(require) {
5 |
6 | var unfold = require('../when').unfold;
7 |
8 | /**
9 | * @deprecated
10 | * Given a seed and generator, produces an Array. Effectively the
11 | * dual (opposite) of when.reduce()
12 | * @param {function} generator function that generates a value (or promise
13 | * for a value) to be placed in the resulting array
14 | * @param {function} condition given a seed, must return truthy if the unfold
15 | * should continue, or falsey if it should terminate
16 | * @param {*|Promise} seed any value or promise
17 | * @return {Promise} resulting array
18 | */
19 | return function list(generator, condition, seed) {
20 | var result = [];
21 |
22 | return unfold(generator, condition, append, seed)['yield'](result);
23 |
24 | function append(value, newSeed) {
25 | result.push(value);
26 | return newSeed;
27 | }
28 | };
29 |
30 | });
31 | })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); });
32 |
33 |
--------------------------------------------------------------------------------
/test/reject-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 | var fail = buster.referee.fail;
4 |
5 | var when = require('../when');
6 |
7 | buster.testCase('when.reject', {
8 |
9 | 'should reject an immediate value': function(done) {
10 | var expected = 123;
11 |
12 | when.reject(expected).then(
13 | fail,
14 | function(value) {
15 | assert.equals(value, expected);
16 | }
17 | ).ensure(done);
18 | },
19 |
20 | 'should reject a resolved promise': function(done) {
21 | var expected, d;
22 |
23 | expected = 123;
24 | d = when.defer();
25 | d.resolve(expected);
26 |
27 | when.reject(d.promise).then(
28 | fail,
29 | function(value) {
30 | assert.same(value, d.promise);
31 | }
32 | ).ensure(done);
33 | },
34 |
35 | 'should reject a rejected promise': function(done) {
36 | var expected, d;
37 |
38 | expected = 123;
39 | d = when.defer();
40 | d.reject(expected);
41 |
42 | when.reject(d.promise).then(
43 | fail,
44 | function(value) {
45 | assert.equals(value, d.promise);
46 | }
47 | ).ensure(done);
48 | }
49 | });
50 |
--------------------------------------------------------------------------------
/parallel.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2011-2013 original author or authors */
2 |
3 | /**
4 | * parallel.js
5 | *
6 | * Run a set of task functions in parallel. All tasks will
7 | * receive the same args
8 | *
9 | * @author Brian Cavalier
10 | * @author John Hann
11 | */
12 |
13 | (function(define) {
14 | define(function(require) {
15 |
16 | var when = require('./when');
17 | var all = when.Promise.all;
18 | var slice = Array.prototype.slice;
19 |
20 | /**
21 | * Run array of tasks in parallel
22 | * @param tasks {Array|Promise} array or promiseForArray of task functions
23 | * @param [args] {*} arguments to be passed to all tasks
24 | * @return {Promise} promise for array containing the
25 | * result of each task in the array position corresponding
26 | * to position of the task in the tasks array
27 | */
28 | return function parallel(tasks /*, args... */) {
29 | return all(slice.call(arguments, 1)).then(function(args) {
30 | return when.map(tasks, function(task) {
31 | return task.apply(void 0, args);
32 | });
33 | });
34 | };
35 |
36 | });
37 | })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); });
38 |
39 |
40 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Open Source Initiative OSI - The MIT License
2 |
3 | http://www.opensource.org/licenses/mit-license.php
4 |
5 | Copyright (c) 2011 Brian Cavalier
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining
8 | a copy of this software and associated documentation files (the
9 | "Software"), to deal in the Software without restriction, including
10 | without limitation the rights to use, copy, modify, merge, publish,
11 | distribute, sublicense, and/or sell copies of the Software, and to
12 | permit persons to whom the Software is furnished to do so, subject to
13 | the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be
16 | included in all copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/test/format-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 |
4 | var format = require('../lib/format');
5 |
6 | buster.testCase('format', {
7 |
8 | 'formatError': {
9 | 'should format null as string': function() {
10 | var s = format.formatError(null);
11 | assert.equals(typeof s, 'string');
12 | },
13 |
14 | 'should format undefined as string': function() {
15 | var s = format.formatError(void 0);
16 | assert.equals(typeof s, 'string');
17 | },
18 |
19 | 'should be the contents of the stack property of an error': function() {
20 | var expected = 'ok';
21 | var e = new Error();
22 | e.stack = expected;
23 | var s = format.formatError(e);
24 | assert.equals(s, expected);
25 | }
26 |
27 | },
28 |
29 | 'formatObject': {
30 | 'should JSON.stringify a plain object': function() {
31 | var o = {foo: 'bar'};
32 | var s = format.formatObject(o);
33 | assert.equals(s, JSON.stringify(o));
34 | }
35 | },
36 |
37 | 'tryStringify': {
38 | 'should return default value when JSON.stringify fails': function() {
39 | var o = { circle: null };
40 | o.circle = o;
41 |
42 | var sentinel = {};
43 | assert.same(sentinel, format.tryStringify(o, sentinel));
44 | }
45 | }
46 | });
47 |
--------------------------------------------------------------------------------
/test/isPromiseLike-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 |
3 | var when = require('../when');
4 |
5 | var fakePromise = {
6 | then:function () {}
7 | };
8 |
9 | function assertIsPromiseLike(it) {
10 | buster.assert(when.isPromiseLike(it));
11 | }
12 |
13 | function refuteIsPromiseLike(it) {
14 | buster.refute(when.isPromiseLike(it));
15 | }
16 |
17 | buster.testCase('when.isPromiseLike', {
18 |
19 | 'should return true for trusted': function() {
20 | assertIsPromiseLike(when.resolve());
21 | },
22 |
23 | 'should return true for promise': function() {
24 | assertIsPromiseLike(fakePromise);
25 | },
26 |
27 | 'should return false for non-promise': function() {
28 | /*jshint -W009, -W010, -W053 */
29 | var inputs = [
30 | 1,
31 | 0,
32 | 'not a promise',
33 | true,
34 | false,
35 | void 0,
36 | null,
37 | '',
38 | /foo/,
39 | {},
40 | new Object(),
41 | new RegExp('foo'),
42 | new Date(),
43 | new Boolean(),
44 | [],
45 | new Array()
46 | ];
47 |
48 | for(var i = inputs.length - 1; i >= 0; --i) {
49 | refuteIsPromiseLike(inputs[i]);
50 | }
51 | },
52 |
53 | 'should return true for delegated promise': function() {
54 | function T() {}
55 |
56 | T.prototype = fakePromise;
57 | assertIsPromiseLike(new T());
58 | }
59 | });
60 |
--------------------------------------------------------------------------------
/sequence.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2011-2013 original author or authors */
2 |
3 | /**
4 | * sequence.js
5 | *
6 | * Run a set of task functions in sequence. All tasks will
7 | * receive the same args.
8 | *
9 | * @author Brian Cavalier
10 | * @author John Hann
11 | */
12 |
13 | (function(define) {
14 | define(function(require) {
15 |
16 | var when = require('./when');
17 | var all = when.Promise.all;
18 | var slice = Array.prototype.slice;
19 |
20 | /**
21 | * Run array of tasks in sequence with no overlap
22 | * @param tasks {Array|Promise} array or promiseForArray of task functions
23 | * @param [args] {*} arguments to be passed to all tasks
24 | * @return {Promise} promise for an array containing
25 | * the result of each task in the array position corresponding
26 | * to position of the task in the tasks array
27 | */
28 | return function sequence(tasks /*, args... */) {
29 | var results = [];
30 |
31 | return all(slice.call(arguments, 1)).then(function(args) {
32 | return when.reduce(tasks, function(results, task) {
33 | return when(task.apply(void 0, args), addResult);
34 | }, results);
35 | });
36 |
37 | function addResult(result) {
38 | results.push(result);
39 | return results;
40 | }
41 | };
42 |
43 | });
44 | })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); });
45 |
46 |
47 |
--------------------------------------------------------------------------------
/lib/apply.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 | /** @author Brian Cavalier */
3 | /** @author John Hann */
4 |
5 | (function(define) { 'use strict';
6 | define(function() {
7 |
8 | makeApply.tryCatchResolve = tryCatchResolve;
9 |
10 | return makeApply;
11 |
12 | function makeApply(Promise, call) {
13 | if(arguments.length < 2) {
14 | call = tryCatchResolve;
15 | }
16 |
17 | return apply;
18 |
19 | function apply(f, thisArg, args) {
20 | var p = Promise._defer();
21 | var l = args.length;
22 | var params = new Array(l);
23 | callAndResolve({ f:f, thisArg:thisArg, args:args, params:params, i:l-1, call:call }, p._handler);
24 |
25 | return p;
26 | }
27 |
28 | function callAndResolve(c, h) {
29 | if(c.i < 0) {
30 | return call(c.f, c.thisArg, c.params, h);
31 | }
32 |
33 | var handler = Promise._handler(c.args[c.i]);
34 | handler.fold(callAndResolveNext, c, void 0, h);
35 | }
36 |
37 | function callAndResolveNext(c, x, h) {
38 | c.params[c.i] = x;
39 | c.i -= 1;
40 | callAndResolve(c, h);
41 | }
42 | }
43 |
44 | function tryCatchResolve(f, thisArg, args, resolver) {
45 | try {
46 | resolver.resolve(f.apply(thisArg, args));
47 | } catch(e) {
48 | resolver.reject(e);
49 | }
50 | }
51 |
52 | });
53 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
54 |
55 |
56 |
--------------------------------------------------------------------------------
/test/join-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 | var fail = buster.referee.fail;
4 |
5 | var when, resolved, rejected;
6 |
7 | when = require('../when');
8 | resolved = when.resolve;
9 | rejected = when.reject;
10 |
11 | buster.testCase('when.join', {
12 |
13 | 'should resolve empty input': function(done) {
14 | return when.join().then(
15 | function(result) {
16 | assert.equals(result, []);
17 | },
18 | fail
19 | ).ensure(done);
20 | },
21 |
22 | 'should join values': function(done) {
23 | when.join(1, 2, 3).then(
24 | function(results) {
25 | assert.equals(results, [1, 2, 3]);
26 | },
27 | fail
28 | ).ensure(done);
29 | },
30 |
31 | 'should join promises array': function(done) {
32 | when.join(resolved(1), resolved(2), resolved(3)).then(
33 | function(results) {
34 | assert.equals(results, [1, 2, 3]);
35 | },
36 | fail
37 | ).ensure(done);
38 | },
39 |
40 | 'should join mixed array': function(done) {
41 | when.join(resolved(1), 2, resolved(3), 4).then(
42 | function(results) {
43 | assert.equals(results, [1, 2, 3, 4]);
44 | },
45 | fail
46 | ).ensure(done);
47 | },
48 |
49 | 'should reject if any input promise rejects': function(done) {
50 | when.join(resolved(1), rejected(2), resolved(3)).then(
51 | fail,
52 | function(failed) {
53 | assert.equals(failed, 2);
54 | }
55 | ).ensure(done);
56 | }
57 |
58 | });
59 |
--------------------------------------------------------------------------------
/lib/decorators/with.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 | /** @author Brian Cavalier */
3 | /** @author John Hann */
4 |
5 | (function(define) { 'use strict';
6 | define(function() {
7 |
8 | return function addWith(Promise) {
9 | /**
10 | * Returns a promise whose handlers will be called with `this` set to
11 | * the supplied receiver. Subsequent promises derived from the
12 | * returned promise will also have their handlers called with receiver
13 | * as `this`. Calling `with` with undefined or no arguments will return
14 | * a promise whose handlers will again be called in the usual Promises/A+
15 | * way (no `this`) thus safely undoing any previous `with` in the
16 | * promise chain.
17 | *
18 | * WARNING: Promises returned from `with`/`withThis` are NOT Promises/A+
19 | * compliant, specifically violating 2.2.5 (http://promisesaplus.com/#point-41)
20 | *
21 | * @param {object} receiver `this` value for all handlers attached to
22 | * the returned promise.
23 | * @returns {Promise}
24 | */
25 | Promise.prototype['with'] = Promise.prototype.withThis = function(receiver) {
26 | var p = this._beget();
27 | var child = p._handler;
28 | child.receiver = receiver;
29 | this._handler.chain(child, receiver);
30 | return p;
31 | };
32 |
33 | return Promise;
34 | };
35 |
36 | });
37 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
38 |
39 |
--------------------------------------------------------------------------------
/test/monitor/deep-chain.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 |
3 | /**
4 | * Licensed under the MIT License at:
5 | * http://www.opensource.org/licenses/mit-license.php
6 | *
7 | * @author: Brian Cavalier
8 | * @author: John Hann
9 | */
10 |
11 | (function(define) { 'use strict';
12 | define(function(require) {
13 |
14 | // require('../../monitor/console');
15 | var Promise = require('../../when').Promise;
16 |
17 | function f1() {
18 | return Promise.resolve(123);
19 | }
20 |
21 | console.log('*** Creating deep promise rejection chain ***');
22 | var p = f1();
23 |
24 | p = p.then(ok);
25 |
26 | p = p.then(ok);
27 |
28 | // Cause an unhandled rejection deep in the promise chain
29 | // It's unhandled because after this statement, p is a
30 | // rejected promise but has no onRejected handler
31 | // This should be logged
32 | p = p.then(reject);
33 |
34 | // Some time later, handle the rejection
35 | // When this happens, p suddenly becomes handled (obviously!),
36 | // and this will be logged as well.
37 | setTimeout(function() {
38 | console.log('*** handling rejection ***');
39 | // p.done();
40 | p.catch(ok);
41 | }, 1337);
42 |
43 | function ok(x) {
44 | return x;
45 | }
46 |
47 | function reject(x) {
48 | return Promise.reject(new Error('error originates here'));
49 | }
50 | });
51 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
52 |
53 |
--------------------------------------------------------------------------------
/test/parallel-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 |
4 | var when = require('../when');
5 | var parallel = require('../parallel');
6 |
7 | function createTask(y) {
8 | return function() {
9 | return y;
10 | };
11 | }
12 |
13 | function expectArgs(expected) {
14 | return function() {
15 | var args = Array.prototype.slice.call(arguments);
16 | assert.equals(args, expected);
17 | };
18 | }
19 |
20 | buster.testCase('when/parallel', {
21 |
22 | 'should execute all tasks': function() {
23 | return parallel([createTask(1), createTask(2), createTask(3)]).then(
24 | function(result) {
25 | assert.equals(result, [1, 2, 3]);
26 | }
27 | );
28 | },
29 |
30 | 'should resolve to empty array when no tasks supplied': function() {
31 | return parallel([], 1, 2, 3).then(
32 | function(result) {
33 | assert.equals(result, []);
34 | }
35 | );
36 | },
37 |
38 | 'should pass args to all tasks': function(done) {
39 | var expected, tasks;
40 |
41 | expected = [1, 2, 3];
42 | tasks = [expectArgs(expected), expectArgs(expected), expectArgs(expected)];
43 |
44 | parallel.apply(void 0, [tasks].concat(expected)).ensure(done);
45 | },
46 |
47 | 'should accept promises for args': function(done) {
48 | var expected, tasks;
49 |
50 | expected = [1, 2, 3];
51 | tasks = [expectArgs(expected), expectArgs(expected), expectArgs(expected)];
52 |
53 | parallel.apply(void 0, [tasks].concat(expected.map(when))).ensure(done);
54 | }
55 | });
56 |
--------------------------------------------------------------------------------
/test/fold-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 | var when = require('../when');
4 | var sentinel = { value: 'sentinel' };
5 | var other = { value: 'other' };
6 |
7 | function noop() {}
8 |
9 | buster.testCase('promise.fold', {
10 |
11 | 'should pass value and arg': function() {
12 | return when.resolve(other).fold(function(a, b) {
13 | assert.same(a, sentinel);
14 | assert.same(b, other);
15 | }, sentinel);
16 | },
17 |
18 | 'should pairwise combine two promises': function() {
19 | return when.resolve(1).fold(function sum(x, y) {
20 | return x + y;
21 | }, when.resolve(2)).then(function(x){
22 | assert.equals(x, 3);
23 | });
24 | },
25 |
26 | 'should reject if combine throws': function() {
27 | return when.resolve(1).fold(function() {
28 | throw sentinel;
29 | }, 2)['catch'](function(e){
30 | assert.same(e, sentinel);
31 | });
32 | },
33 |
34 | 'should reject if combine returns rejection': function() {
35 | return when.resolve(1).fold(when.reject, sentinel)['catch'](function(e){
36 | assert.same(e, sentinel);
37 | });
38 | },
39 |
40 | 'should reject and not call combine': {
41 | 'if promise rejects': function() {
42 | return when.reject(sentinel).fold(noop, 2)['catch'](function(e){
43 | assert.same(e, sentinel);
44 | });
45 | },
46 |
47 | 'if arg rejects': function() {
48 | return when.resolve(1).fold(noop, when.reject(sentinel))
49 | ['catch'](function(e){
50 | assert.same(e, sentinel);
51 | });
52 | }
53 | }
54 |
55 | });
56 |
--------------------------------------------------------------------------------
/test/cycle-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 |
4 | var CorePromise = require('../lib/Promise');
5 |
6 | function assertCycle(p) {
7 | return p.then(buster.referee.fail, function(e) {
8 | assert(e instanceof TypeError);
9 | });
10 | }
11 |
12 | buster.testCase('cycle detection', {
13 |
14 | 'should detect self-cycles': {
15 | 'when resolving': function() {
16 | /*global setTimeout*/
17 | var p = new CorePromise(function(resolve) {
18 | setTimeout(function() {
19 | resolve(p);
20 | }, 0);
21 | });
22 |
23 | return assertCycle(p);
24 | },
25 |
26 | 'when returning from handler': function() {
27 | var p = CorePromise.resolve();
28 | p = p.then(function() {
29 | return p;
30 | });
31 |
32 | return assertCycle(p);
33 | },
34 |
35 | 'when returning resolved from handler': function() {
36 | var p = CorePromise.resolve();
37 | p = p.then(function() {
38 | return CorePromise.resolve(p);
39 | });
40 |
41 | return assertCycle(p);
42 | }
43 | },
44 |
45 | 'should detect long cycles': function() {
46 | var p1 = new CorePromise(function(resolve) {
47 | setTimeout(function() {
48 | resolve(p2);
49 | }, 0);
50 | });
51 |
52 | var p2 = new CorePromise(function(resolve) {
53 | setTimeout(function() {
54 | resolve(p3);
55 | }, 0);
56 | });
57 |
58 | var p3 = new CorePromise(function(resolve) {
59 | setTimeout(function() {
60 | resolve(p1);
61 | }, 0);
62 | });
63 |
64 | return assertCycle(p3);
65 | }
66 | });
67 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Thank you for helping out with when.js! We really appreciate you investing your time in the project. Below, find information and guides on the best way to contribute.
4 |
5 | Opening Issues
6 | --------------
7 |
8 | No software is truly without bugs, and if you find one we would love it if you let us know so we can patch it up for you. When opening an issue, make sure to use a clear, short title along with a thorough description of the problem so we can best understand it. It's extremely helpful if you provide concrete steps on how to replicate the issue so that we can isolate it and figure it out more quickly.
9 |
10 | Pull Requests
11 | -------------
12 |
13 | There's nothing better than a great pull request. To ensure that yours gets accepted as quickly and smoothly as possible, make sure the following steps have been taken:
14 |
15 | - Good clean commit messages. [This guide](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) should help.
16 | - A thorough description of what your code does in the description field
17 | - Tests written for any features that have been added.
18 |
19 | Running the Tests
20 | -----------------
21 |
22 | #### Node
23 |
24 | Note that when.js includes the [Promises/A+ Test Suite](https://github.com/promises-aplus/promise-tests). Running unit tests in Node will run both when.js's own test suite, and the Promises/A+ Test Suite.
25 |
26 | 1. `npm install`
27 | 2. `npm test`
28 |
29 | #### Browsers
30 |
31 | 1. `npm install`
32 | 2. `npm start` - starts buster server & prints a url
33 | 3. Point browsers at /capture, e.g. `localhost:1111/capture`
34 | 4. `npm run test-browser`
35 |
--------------------------------------------------------------------------------
/pipeline.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2011-2013 original author or authors */
2 |
3 | /**
4 | * pipeline.js
5 | *
6 | * Run a set of task functions in sequence, passing the result
7 | * of the previous as an argument to the next. Like a shell
8 | * pipeline, e.g. `cat file.txt | grep 'foo' | sed -e 's/foo/bar/g'
9 | *
10 | * @author Brian Cavalier
11 | * @author John Hann
12 | */
13 |
14 | (function(define) {
15 | define(function(require) {
16 |
17 | var when = require('./when');
18 | var all = when.Promise.all;
19 | var slice = Array.prototype.slice;
20 |
21 | /**
22 | * Run array of tasks in a pipeline where the next
23 | * tasks receives the result of the previous. The first task
24 | * will receive the initialArgs as its argument list.
25 | * @param tasks {Array|Promise} array or promise for array of task functions
26 | * @param [initialArgs...] {*} arguments to be passed to the first task
27 | * @return {Promise} promise for return value of the final task
28 | */
29 | return function pipeline(tasks /* initialArgs... */) {
30 | // Self-optimizing function to run first task with multiple
31 | // args using apply, but subsequence tasks via direct invocation
32 | var runTask = function(args, task) {
33 | runTask = function(arg, task) {
34 | return task(arg);
35 | };
36 |
37 | return task.apply(null, args);
38 | };
39 |
40 | return all(slice.call(arguments, 1)).then(function(args) {
41 | return when.reduce(tasks, function(arg, task) {
42 | return runTask(arg, task);
43 | }, args);
44 | });
45 | };
46 |
47 | });
48 | })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); });
49 |
50 |
51 |
--------------------------------------------------------------------------------
/test/pipeline-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 |
4 | var when = require('../when');
5 | var pipeline = require('../pipeline');
6 |
7 | function createTask(y) {
8 | return function(x) {
9 | return x + y;
10 | };
11 | }
12 |
13 | buster.testCase('when/pipeline', {
14 |
15 | 'should execute tasks in order': function() {
16 | return pipeline([createTask('b'), createTask('c'), createTask('d')], 'a').then(
17 | function(result) {
18 | assert.equals(result, 'abcd');
19 | }
20 | );
21 | },
22 |
23 | 'should resolve to initial args when no tasks supplied': function() {
24 | return pipeline([], 'a', 'b').then(
25 | function(result) {
26 | assert.equals(result, ['a', 'b']);
27 | }
28 | );
29 | },
30 |
31 | 'should resolve to empty array when no tasks and no args supplied': function() {
32 | return pipeline([]).then(
33 | function(result) {
34 | assert.equals(result, []);
35 | }
36 | );
37 | },
38 |
39 | 'should pass args to initial task': function() {
40 | var expected, tasks;
41 |
42 | expected = [1, 2, 3];
43 | tasks = [this.spy()];
44 |
45 | return pipeline.apply(null, [tasks].concat(expected)).then(
46 | function() {
47 | assert.calledOnceWith.apply(assert, tasks.concat(expected));
48 | }
49 | );
50 | },
51 |
52 | 'should allow initial args to be promises': function() {
53 | var expected, tasks;
54 |
55 | expected = [1, 2, 3];
56 | tasks = [this.spy()];
57 |
58 | return pipeline.apply(null, [tasks].concat([when(1), when(2), when(3)])).then(
59 | function() {
60 | assert.calledOnceWith.apply(assert, tasks.concat(expected));
61 | }
62 | );
63 | }
64 | });
65 |
--------------------------------------------------------------------------------
/lib/format.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 | /** @author Brian Cavalier */
3 | /** @author John Hann */
4 |
5 | (function(define) { 'use strict';
6 | define(function() {
7 |
8 | return {
9 | formatError: formatError,
10 | formatObject: formatObject,
11 | tryStringify: tryStringify
12 | };
13 |
14 | /**
15 | * Format an error into a string. If e is an Error and has a stack property,
16 | * it's returned. Otherwise, e is formatted using formatObject, with a
17 | * warning added about e not being a proper Error.
18 | * @param {*} e
19 | * @returns {String} formatted string, suitable for output to developers
20 | */
21 | function formatError(e) {
22 | var s = typeof e === 'object' && e !== null && (e.stack || e.message) ? e.stack || e.message : formatObject(e);
23 | return e instanceof Error ? s : s + ' (WARNING: non-Error used)';
24 | }
25 |
26 | /**
27 | * Format an object, detecting "plain" objects and running them through
28 | * JSON.stringify if possible.
29 | * @param {Object} o
30 | * @returns {string}
31 | */
32 | function formatObject(o) {
33 | var s = String(o);
34 | if(s === '[object Object]' && typeof JSON !== 'undefined') {
35 | s = tryStringify(o, s);
36 | }
37 | return s;
38 | }
39 |
40 | /**
41 | * Try to return the result of JSON.stringify(x). If that fails, return
42 | * defaultValue
43 | * @param {*} x
44 | * @param {*} defaultValue
45 | * @returns {String|*} JSON.stringify(x) or defaultValue
46 | */
47 | function tryStringify(x, defaultValue) {
48 | try {
49 | return JSON.stringify(x);
50 | } catch(e) {
51 | return defaultValue;
52 | }
53 | }
54 |
55 | });
56 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
57 |
--------------------------------------------------------------------------------
/test/delay-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 | var fail = buster.referee.fail;
4 |
5 | var when = require('../when');
6 | var delay = require('../delay');
7 |
8 | var sentinel = {};
9 |
10 | function now() {
11 | return (new Date()).getTime();
12 | }
13 |
14 |
15 | buster.testCase('when/delay', {
16 | 'should resolve after delay': function(done) {
17 | delay(0).then(
18 | function() {
19 | assert(true);
20 | },
21 | fail
22 | ).ensure(done);
23 | },
24 |
25 | 'should resolve with provided value after delay': function(done) {
26 | delay(0, sentinel).then(
27 | function(val) {
28 | assert.same(val, sentinel);
29 | done();
30 | },
31 | fail
32 | ).ensure(done);
33 | },
34 |
35 | 'should delay by the provided value': function(done) {
36 | var start = now();
37 |
38 | delay(100).then(
39 | function() {
40 | assert((now() - start) > 50);
41 | },
42 | fail
43 | ).ensure(done);
44 | },
45 |
46 | 'should resolve after input promise plus delay': function(done) {
47 | when.resolve(sentinel).delay(10).then(
48 | function(val) {
49 | assert.equals(val, sentinel);
50 | },
51 | fail
52 | ).ensure(done);
53 | },
54 |
55 | 'should not delay if rejected': function(done) {
56 | var d = when.defer();
57 | d.reject(sentinel);
58 |
59 | d.promise.delay(0).then(
60 | fail,
61 | function(val) {
62 | assert.equals(val, sentinel);
63 | }
64 | ).ensure(done);
65 | },
66 |
67 | 'should propagate progress': function(done) {
68 | var d = when.defer();
69 |
70 | d.promise.delay(0).then(null, null,
71 | function(val) {
72 | assert.same(val, sentinel);
73 | d.resolve();
74 | }
75 | ).ensure(done);
76 |
77 | d.notify(sentinel);
78 | }
79 | });
80 |
--------------------------------------------------------------------------------
/cancelable.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright B Cavalier & J Hann */
2 |
3 | /**
4 | * cancelable.js
5 | * @deprecated
6 | *
7 | * Decorator that makes a deferred "cancelable". It adds a cancel() method that
8 | * will call a special cancel handler function and then reject the deferred. The
9 | * cancel handler can be used to do resource cleanup, or anything else that should
10 | * be done before any other rejection handlers are executed.
11 | *
12 | * Usage:
13 | *
14 | * var cancelableDeferred = cancelable(when.defer(), myCancelHandler);
15 | *
16 | * @author brian@hovercraftstudios.com
17 | */
18 |
19 | (function(define) {
20 | define(function() {
21 |
22 | /**
23 | * Makes deferred cancelable, adding a cancel() method.
24 | * @deprecated
25 | *
26 | * @param deferred {Deferred} the {@link Deferred} to make cancelable
27 | * @param canceler {Function} cancel handler function to execute when this deferred
28 | * is canceled. This is guaranteed to run before all other rejection handlers.
29 | * The canceler will NOT be executed if the deferred is rejected in the standard
30 | * way, i.e. deferred.reject(). It ONLY executes if the deferred is canceled,
31 | * i.e. deferred.cancel()
32 | *
33 | * @returns deferred, with an added cancel() method.
34 | */
35 | return function(deferred, canceler) {
36 | // Add a cancel method to the deferred to reject the delegate
37 | // with the special canceled indicator.
38 | deferred.cancel = function() {
39 | try {
40 | deferred.reject(canceler(deferred));
41 | } catch(e) {
42 | deferred.reject(e);
43 | }
44 |
45 | return deferred.promise;
46 | };
47 |
48 | return deferred;
49 | };
50 |
51 | });
52 | })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(); });
53 |
54 |
55 |
--------------------------------------------------------------------------------
/test/sequence-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 |
4 | var when = require('../when');
5 | var sequence = require('../sequence');
6 |
7 | var sentinel = { value: 'sentinel' };
8 |
9 | function createTask(y) {
10 | return function() {
11 | return y;
12 | };
13 | }
14 |
15 | function expectArgs(expected) {
16 | return function() {
17 | var args = Array.prototype.slice.call(arguments);
18 | assert.equals(args, expected);
19 | };
20 | }
21 |
22 | buster.testCase('when/sequence', {
23 |
24 | 'should execute tasks in order': function() {
25 | return sequence([createTask(1), createTask(2), createTask(3)]).then(
26 | function(result) {
27 | assert.equals(result, [1, 2, 3]);
28 | }
29 | );
30 | },
31 |
32 | 'should resolve to empty array when no tasks supplied': function() {
33 | return sequence([], 1, 2, 3).then(
34 | function(result) {
35 | assert.equals(result, []);
36 | }
37 | );
38 | },
39 |
40 | 'should pass args to all tasks': function(done) {
41 | var expected, tasks;
42 |
43 | expected = [1, 2, 3];
44 | tasks = [expectArgs(expected), expectArgs(expected), expectArgs(expected)];
45 |
46 | return sequence.apply(null, [tasks].concat(expected)).ensure(done);
47 | },
48 |
49 | 'should accept promises for args': function(done) {
50 | var expected, tasks;
51 |
52 | expected = [1, 2, 3];
53 | tasks = [expectArgs(expected), expectArgs(expected), expectArgs(expected)];
54 |
55 | expected = [when(1), when(2), when(3)];
56 | return sequence.apply(null, [tasks].concat(expected)).ensure(done);
57 | },
58 |
59 | 'should reject if task throws': function() {
60 | return sequence([function () {
61 | return 1;
62 | }, function () {
63 | throw sentinel;
64 | }])['catch'](function (e) {
65 | assert.same(e, sentinel);
66 | });
67 | }
68 | });
69 |
--------------------------------------------------------------------------------
/test/any-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 | var refute = buster.refute;
4 | var fail = buster.referee.fail;
5 |
6 | var when = require('../when');
7 | var resolved = when.resolve;
8 | var rejected = when.reject;
9 |
10 | function contains(array, item) {
11 | for(var i=array.length - 1; i >= 0; --i) {
12 | if(array[i] === item) {
13 | return true;
14 | }
15 | }
16 |
17 | return false;
18 | }
19 |
20 | buster.testCase('when.any', {
21 |
22 | 'should reject with RangeError': {
23 | 'when zero inputs': function() {
24 | return when.any([])['catch'](
25 | function (e) {
26 | assert(e instanceof RangeError);
27 | });
28 | },
29 |
30 | 'when input promise does not resolve to array': function() {
31 | return when.any(when.resolve(1))['catch'](
32 | function(e) {
33 | assert(e instanceof RangeError);
34 | });
35 | }
36 | },
37 |
38 | 'should reject with all rejected input values if all inputs are rejected': function() {
39 | var input = [rejected(1), rejected(2), rejected(3)];
40 | return when.any(input)['catch'](
41 | function(result) {
42 | assert.equals(result, [1, 2, 3]);
43 | }
44 | );
45 | },
46 |
47 | 'should resolve with an input value': function() {
48 | var input = [1, 2, 3];
49 | return when.any(input).then(
50 | function(result) {
51 | assert(contains(input, result));
52 | },
53 | fail
54 | );
55 | },
56 |
57 | 'should resolve with a promised input value': function() {
58 | var input = [resolved(1), resolved(2), resolved(3)];
59 | return when.any(input).then(
60 | function(result) {
61 | assert(contains([1, 2, 3], result));
62 | }
63 | );
64 | },
65 |
66 | 'should accept a promise for an array': function() {
67 | var expected, input;
68 |
69 | expected = [1, 2, 3];
70 | input = resolved(expected);
71 |
72 | return when.any(input).then(
73 | function(result) {
74 | refute.equals(expected.indexOf(result), -1);
75 | }
76 | );
77 | }
78 |
79 | });
80 |
--------------------------------------------------------------------------------
/lib/Scheduler.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 | /** @author Brian Cavalier */
3 | /** @author John Hann */
4 |
5 | (function(define) { 'use strict';
6 | define(function() {
7 |
8 | // Credit to Twisol (https://github.com/Twisol) for suggesting
9 | // this type of extensible queue + trampoline approach for next-tick conflation.
10 |
11 | /**
12 | * Async task scheduler
13 | * @param {function} async function to schedule a single async function
14 | * @constructor
15 | */
16 | function Scheduler(async) {
17 | this._async = async;
18 | this._running = false;
19 |
20 | this._queue = this;
21 | this._queueLen = 0;
22 | this._afterQueue = {};
23 | this._afterQueueLen = 0;
24 |
25 | var self = this;
26 | this.drain = function() {
27 | self._drain();
28 | };
29 | }
30 |
31 | /**
32 | * Enqueue a task
33 | * @param {{ run:function }} task
34 | */
35 | Scheduler.prototype.enqueue = function(task) {
36 | this._queue[this._queueLen++] = task;
37 | this.run();
38 | };
39 |
40 | /**
41 | * Enqueue a task to run after the main task queue
42 | * @param {{ run:function }} task
43 | */
44 | Scheduler.prototype.afterQueue = function(task) {
45 | this._afterQueue[this._afterQueueLen++] = task;
46 | this.run();
47 | };
48 |
49 | Scheduler.prototype.run = function() {
50 | if (!this._running) {
51 | this._running = true;
52 | this._async(this.drain);
53 | }
54 | };
55 |
56 | /**
57 | * Drain the handler queue entirely, and then the after queue
58 | */
59 | Scheduler.prototype._drain = function() {
60 | var i = 0;
61 | for (; i < this._queueLen; ++i) {
62 | this._queue[i].run();
63 | this._queue[i] = void 0;
64 | }
65 |
66 | this._queueLen = 0;
67 | this._running = false;
68 |
69 | for (i = 0; i < this._afterQueueLen; ++i) {
70 | this._afterQueue[i].run();
71 | this._afterQueue[i] = void 0;
72 | }
73 |
74 | this._afterQueueLen = 0;
75 | };
76 |
77 | return Scheduler;
78 |
79 | });
80 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
81 |
--------------------------------------------------------------------------------
/monitor/error.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 | /** @author Brian Cavalier */
3 | /** @author John Hann */
4 |
5 | (function(define) { 'use strict';
6 | define(function() {
7 |
8 | var parse, captureStack, format;
9 |
10 | if(Error.captureStackTrace) {
11 | // Use Error.captureStackTrace if available
12 | parse = function(e) {
13 | return e && e.stack && e.stack.split('\n');
14 | };
15 |
16 | format = formatAsString;
17 | captureStack = Error.captureStackTrace;
18 |
19 | } else {
20 | // Otherwise, do minimal feature detection to determine
21 | // how to capture and format reasonable stacks.
22 | parse = function(e) {
23 | var stack = e && e.stack && e.stack.split('\n');
24 | if(stack && e.message) {
25 | stack.unshift(e.message);
26 | }
27 | return stack;
28 | };
29 |
30 | (function() {
31 | var e = new Error();
32 | if(typeof e.stack !== 'string') {
33 | format = formatAsString;
34 | captureStack = captureSpiderMonkeyStack;
35 | } else {
36 | format = formatAsErrorWithStack;
37 | captureStack = useStackDirectly;
38 | }
39 | }());
40 | }
41 |
42 | function captureSpiderMonkeyStack(host) {
43 | try {
44 | throw new Error();
45 | } catch(err) {
46 | host.stack = err.stack;
47 | }
48 | }
49 |
50 | function useStackDirectly(host) {
51 | host.stack = new Error().stack;
52 | }
53 |
54 | function formatAsString(longTrace) {
55 | return join(longTrace);
56 | }
57 |
58 | function formatAsErrorWithStack(longTrace) {
59 | var e = new Error();
60 | e.stack = formatAsString(longTrace);
61 | return e;
62 | }
63 |
64 | // About 5-10x faster than String.prototype.join o_O
65 | function join(a) {
66 | var sep = false;
67 | var s = '';
68 | for(var i=0; i< a.length; ++i) {
69 | if(sep) {
70 | s += '\n' + a[i];
71 | } else {
72 | s+= a[i];
73 | sep = true;
74 | }
75 | }
76 | return s;
77 | }
78 |
79 | return {
80 | parse: parse,
81 | format: format,
82 | captureStack: captureStack
83 | };
84 |
85 | });
86 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
87 |
--------------------------------------------------------------------------------
/guard.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2011-2013 original author or authors */
2 |
3 | /**
4 | * Generalized promise concurrency guard
5 | * Adapted from original concept by Sakari Jokinen (Rocket Pack, Ltd.)
6 | *
7 | * @author Brian Cavalier
8 | * @author John Hann
9 | * @contributor Sakari Jokinen
10 | */
11 | (function(define) {
12 | define(function(require) {
13 |
14 | var when = require('./when');
15 | var slice = Array.prototype.slice;
16 |
17 | guard.n = n;
18 |
19 | return guard;
20 |
21 | /**
22 | * Creates a guarded version of f that can only be entered when the supplied
23 | * condition allows.
24 | * @param {function} condition represents a critical section that may only
25 | * be entered when allowed by the condition
26 | * @param {function} f function to guard
27 | * @returns {function} guarded version of f
28 | */
29 | function guard(condition, f) {
30 | return function() {
31 | var args = slice.call(arguments);
32 |
33 | return when(condition()).withThis(this).then(function(exit) {
34 | return when(f.apply(this, args))['finally'](exit);
35 | });
36 | };
37 | }
38 |
39 | /**
40 | * Creates a condition that allows only n simultaneous executions
41 | * of a guarded function
42 | * @param {number} allowed number of allowed simultaneous executions
43 | * @returns {function} condition function which returns a promise that
44 | * fulfills when the critical section may be entered. The fulfillment
45 | * value is a function ("notifyExit") that must be called when the critical
46 | * section has been exited.
47 | */
48 | function n(allowed) {
49 | var count = 0;
50 | var waiting = [];
51 |
52 | return function enter() {
53 | return when.promise(function(resolve) {
54 | if(count < allowed) {
55 | resolve(exit);
56 | } else {
57 | waiting.push(resolve);
58 | }
59 | count += 1;
60 | });
61 | };
62 |
63 | function exit() {
64 | count = Math.max(count - 1, 0);
65 | if(waiting.length > 0) {
66 | waiting.shift()(exit);
67 | }
68 | }
69 | }
70 |
71 | });
72 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
73 |
--------------------------------------------------------------------------------
/test/cancelable-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 | var fail = buster.referee.fail;
4 |
5 | var when = require('../when');
6 | var cancelable = require('../cancelable');
7 |
8 | var sentinel = {};
9 | var other = {};
10 |
11 | buster.testCase('when/cancelable', {
12 | 'should decorate deferred with a cancel() method': function() {
13 | var c = cancelable(when.defer(), function() {});
14 | assert(typeof c.cancel == 'function');
15 | },
16 |
17 | 'should propagate a rejection when a cancelable deferred is canceled': function(done) {
18 | var c = cancelable(when.defer(), function() { return sentinel; });
19 | c.cancel();
20 |
21 | c.promise.then(
22 | fail,
23 | function(v) {
24 | assert.equals(v, sentinel);
25 | }
26 | ).ensure(done);
27 | },
28 |
29 | 'should return a promise for canceled value when canceled': function(done) {
30 | var c, promise;
31 |
32 | c = cancelable(when.defer(), function() { return sentinel; });
33 | promise = c.cancel();
34 |
35 | promise.then(
36 | fail,
37 | function(v) {
38 | assert.equals(v, sentinel);
39 | }
40 | ).ensure(done);
41 | },
42 |
43 | 'should not invoke canceler when rejected normally': function(done) {
44 | var c = cancelable(when.defer(), function() { return other; });
45 | c.reject(sentinel);
46 | c.cancel();
47 |
48 | c.promise.then(
49 | fail,
50 | function(v) {
51 | assert.equals(v, sentinel);
52 | }
53 | ).ensure(done);
54 | },
55 |
56 | 'should propagate the unaltered resolution value': function(done) {
57 | var c = cancelable(when.defer(), function() { return other; });
58 | c.resolve(sentinel);
59 | c.cancel();
60 |
61 | c.promise.then(
62 | function(val) {
63 | assert.same(val, sentinel);
64 | },
65 | function(e) {
66 | fail(e);
67 | }
68 | ).ensure(done);
69 | },
70 |
71 | 'should call progback for cancelable deferred': function(done) {
72 | var c = cancelable(when.defer());
73 |
74 | c.promise.then(null, null, function (status) {
75 | assert.same(status, sentinel);
76 | done();
77 | });
78 |
79 | c.notify(sentinel);
80 | }
81 |
82 | });
83 |
--------------------------------------------------------------------------------
/benchmark/run.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 | /** @author Brian Cavalier */
3 | /** @author John Hann */
4 |
5 | (function(define) { 'use strict';
6 | define(function(require) {
7 |
8 | var Benchmark, log, err;
9 |
10 | Benchmark = require('benchmark');
11 | log = console.log.bind(console);
12 | err = console.error.bind(console);
13 |
14 | //
15 | // Simple multi-benchmark runner
16 | //
17 | return function run(tests) {
18 | var skipped = [];
19 |
20 | tests.reduce(function (suite, test) {
21 | var skip = shouldSkip(test);
22 | if(skip) {
23 | skipped.push(pad(test.name, 24) + ' ' + skip);
24 | return suite;
25 | }
26 |
27 | test.onError = err;
28 | test.onComplete = function (event) {
29 | var result, t;
30 |
31 | t = event.currentTarget;
32 |
33 | result = pad(t.name, 24)
34 | + pad(t.hz.toFixed(2) + ' op/s', 18)
35 | + pad((1000 * t.stats.mean).toFixed(2), 8)
36 | + ' ms/op \xb1 ' + t.stats.rme.toFixed(2) + '%';
37 | log(result);
38 | };
39 |
40 | return suite.add(test);
41 |
42 | }, new Benchmark.Suite())
43 | .on('start', function() {
44 | log('Platform:', Benchmark.platform.description || 'unknown');
45 | if(skipped.length) {
46 | log('------------------------------------------------');
47 | log('Skipping ' + count(skipped.length, 'benchmark'));
48 | log(skipped.join('\n'));
49 | }
50 | log('------------------------------------------------');
51 | log('Running ' + count(this.length, 'benchmark'));
52 | })
53 | .on('complete', function () {
54 | log('------------------------------------------------');
55 | }).run();
56 |
57 | };
58 |
59 | function shouldSkip(test) {
60 | return typeof test.condition === 'function'
61 | && test.condition();
62 | }
63 |
64 | function pad(str, len) {
65 | var result = str;
66 | while (result.length < len) {
67 | result = ' ' + result;
68 | }
69 | return result;
70 | }
71 |
72 | function count(n, s) {
73 | return '' + n + ' ' + (n === 1 ? s : (s + 's'));
74 | }
75 |
76 | });
77 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
78 |
--------------------------------------------------------------------------------
/lib/decorators/timed.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 | /** @author Brian Cavalier */
3 | /** @author John Hann */
4 |
5 | (function(define) { 'use strict';
6 | define(function(require) {
7 |
8 | var env = require('../env');
9 | var TimeoutError = require('../TimeoutError');
10 |
11 | function setTimeout(f, ms, x, y) {
12 | return env.setTimer(function() {
13 | f(x, y, ms);
14 | }, ms);
15 | }
16 |
17 | return function timed(Promise) {
18 | /**
19 | * Return a new promise whose fulfillment value is revealed only
20 | * after ms milliseconds
21 | * @param {number} ms milliseconds
22 | * @returns {Promise}
23 | */
24 | Promise.prototype.delay = function(ms) {
25 | var p = this._beget();
26 | this._handler.fold(handleDelay, ms, void 0, p._handler);
27 | return p;
28 | };
29 |
30 | function handleDelay(ms, x, h) {
31 | setTimeout(resolveDelay, ms, x, h);
32 | }
33 |
34 | function resolveDelay(x, h) {
35 | h.resolve(x);
36 | }
37 |
38 | /**
39 | * Return a new promise that rejects after ms milliseconds unless
40 | * this promise fulfills earlier, in which case the returned promise
41 | * fulfills with the same value.
42 | * @param {number} ms milliseconds
43 | * @param {Error|*=} reason optional rejection reason to use, defaults
44 | * to a TimeoutError if not provided
45 | * @returns {Promise}
46 | */
47 | Promise.prototype.timeout = function(ms, reason) {
48 | var p = this._beget();
49 | var h = p._handler;
50 |
51 | var t = setTimeout(onTimeout, ms, reason, p._handler);
52 |
53 | this._handler.visit(h,
54 | function onFulfill(x) {
55 | env.clearTimer(t);
56 | this.resolve(x); // this = h
57 | },
58 | function onReject(x) {
59 | env.clearTimer(t);
60 | this.reject(x); // this = h
61 | },
62 | h.notify);
63 |
64 | return p;
65 | };
66 |
67 | function onTimeout(reason, h, ms) {
68 | var e = typeof reason === 'undefined'
69 | ? new TimeoutError('timed out after ' + ms + 'ms')
70 | : reason;
71 | h.reject(e);
72 | }
73 |
74 | return Promise;
75 | };
76 |
77 | });
78 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
79 |
--------------------------------------------------------------------------------
/lib/env.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 | /** @author Brian Cavalier */
3 | /** @author John Hann */
4 |
5 | /*global process,document,setTimeout,clearTimeout,MutationObserver,WebKitMutationObserver*/
6 | (function(define) { 'use strict';
7 | define(function(require) {
8 | /*jshint maxcomplexity:6*/
9 |
10 | // Sniff "best" async scheduling option
11 | // Prefer process.nextTick or MutationObserver, then check for
12 | // setTimeout, and finally vertx, since its the only env that doesn't
13 | // have setTimeout
14 |
15 | var MutationObs;
16 | var capturedSetTimeout = typeof setTimeout !== 'undefined' && setTimeout;
17 |
18 | // Default env
19 | var setTimer = function(f, ms) { return setTimeout(f, ms); };
20 | var clearTimer = function(t) { return clearTimeout(t); };
21 | var asap = function (f) { return capturedSetTimeout(f, 0); };
22 |
23 | // Detect specific env
24 | if (isNode()) { // Node
25 | asap = function (f) { return process.nextTick(f); };
26 |
27 | } else if (MutationObs = hasMutationObserver()) { // Modern browser
28 | asap = initMutationObserver(MutationObs);
29 |
30 | } else if (!capturedSetTimeout) { // vert.x
31 | var vertxRequire = require;
32 | var vertx = vertxRequire('vertx');
33 | setTimer = function (f, ms) { return vertx.setTimer(ms, f); };
34 | clearTimer = vertx.cancelTimer;
35 | asap = vertx.runOnLoop || vertx.runOnContext;
36 | }
37 |
38 | return {
39 | setTimer: setTimer,
40 | clearTimer: clearTimer,
41 | asap: asap
42 | };
43 |
44 | function isNode () {
45 | return typeof process !== 'undefined' &&
46 | Object.prototype.toString.call(process) === '[object process]';
47 | }
48 |
49 | function hasMutationObserver () {
50 | return (typeof MutationObserver !== 'undefined' && MutationObserver) ||
51 | (typeof WebKitMutationObserver !== 'undefined' && WebKitMutationObserver);
52 | }
53 |
54 | function initMutationObserver(MutationObserver) {
55 | var scheduled;
56 | var node = document.createTextNode('');
57 | var o = new MutationObserver(run);
58 | o.observe(node, { characterData: true });
59 |
60 | function run() {
61 | var f = scheduled;
62 | scheduled = void 0;
63 | f();
64 | }
65 |
66 | var i = 0;
67 | return function (f) {
68 | scheduled = f;
69 | node.data = (i ^= 1);
70 | };
71 | }
72 | });
73 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
74 |
--------------------------------------------------------------------------------
/test/settle-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 | var refute = buster.refute;
4 | var fail = buster.referee.fail;
5 |
6 | var when = require('../when');
7 | var sentinel = {};
8 |
9 | function assertFulfilled(s, value) {
10 | assert.equals(s.state, 'fulfilled');
11 | assert.same(s.value, value);
12 | }
13 |
14 | function assertRejected(s, reason) {
15 | assert.equals(s.state, 'rejected');
16 | assert.same(s.reason, reason);
17 | }
18 |
19 | buster.testCase('when.settle', {
20 | 'should settle empty array': function() {
21 | return when.settle([]).then(function(settled) {
22 | assert.equals(settled.length, 0);
23 | });
24 | },
25 |
26 | 'should reject if promise for input array rejects': function() {
27 | return when.settle(when.reject(sentinel)).then(
28 | fail,
29 | function(reason) {
30 | assert.same(reason, sentinel);
31 | }
32 | );
33 | },
34 |
35 | 'should settle values': function() {
36 | var array = [0, 1, sentinel];
37 | return when.settle(array).then(function(settled) {
38 | assertFulfilled(settled[0], 0);
39 | assertFulfilled(settled[1], 1);
40 | assertFulfilled(settled[2], sentinel);
41 | });
42 | },
43 |
44 | 'should settle promises': function() {
45 | var array = [0, when.resolve(sentinel), when.reject(sentinel)];
46 | return when.settle(array).then(function(settled) {
47 | assertFulfilled(settled[0], 0);
48 | assertFulfilled(settled[1], sentinel);
49 | assertRejected(settled[2], sentinel);
50 | });
51 | },
52 |
53 | 'returned promise should fulfill once all inputs settle': function() {
54 | /*global setTimeout*/
55 | var array, p1, p2, resolve, reject;
56 |
57 | p1 = when.promise(function(r) { resolve = r; });
58 | p2 = when.promise(function(_, r) { reject = r; });
59 |
60 | array = [0, p1, p2];
61 |
62 | setTimeout(function() { resolve(sentinel); }, 0);
63 | setTimeout(function() { reject(sentinel); }, 0);
64 |
65 | return when.settle(array).then(function(settled) {
66 | assertFulfilled(settled[0], 0);
67 | assertFulfilled(settled[1], sentinel);
68 | assertRejected(settled[2], sentinel);
69 | });
70 | },
71 |
72 | 'should not report unhandled rejection for rejected inputs': function(done) {
73 | var P = when.Promise;
74 | var spy = P.onPotentiallyUnhandledRejection = this.spy();
75 | when.settle([when.reject()]);
76 |
77 | setTimeout(function() {
78 | refute.called(spy);
79 | done();
80 | }, 10);
81 | }
82 | });
83 |
--------------------------------------------------------------------------------
/lib/decorators/unhandledRejection.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 | /** @author Brian Cavalier */
3 | /** @author John Hann */
4 |
5 | (function(define) { 'use strict';
6 | define(function(require) {
7 |
8 | var setTimer = require('../env').setTimer;
9 | var format = require('../format');
10 |
11 | return function unhandledRejection(Promise) {
12 |
13 | var logError = noop;
14 | var logInfo = noop;
15 | var localConsole;
16 |
17 | if(typeof console !== 'undefined') {
18 | // Alias console to prevent things like uglify's drop_console option from
19 | // removing console.log/error. Unhandled rejections fall into the same
20 | // category as uncaught exceptions, and build tools shouldn't silence them.
21 | localConsole = console;
22 | logError = typeof localConsole.error !== 'undefined'
23 | ? function (e) { localConsole.error(e); }
24 | : function (e) { localConsole.log(e); };
25 |
26 | logInfo = typeof localConsole.info !== 'undefined'
27 | ? function (e) { localConsole.info(e); }
28 | : function (e) { localConsole.log(e); };
29 | }
30 |
31 | Promise.onPotentiallyUnhandledRejection = function(rejection) {
32 | enqueue(report, rejection);
33 | };
34 |
35 | Promise.onPotentiallyUnhandledRejectionHandled = function(rejection) {
36 | enqueue(unreport, rejection);
37 | };
38 |
39 | Promise.onFatalRejection = function(rejection) {
40 | enqueue(throwit, rejection.value);
41 | };
42 |
43 | var tasks = [];
44 | var reported = [];
45 | var running = null;
46 |
47 | function report(r) {
48 | if(!r.handled) {
49 | reported.push(r);
50 | logError('Potentially unhandled rejection [' + r.id + '] ' + format.formatError(r.value));
51 | }
52 | }
53 |
54 | function unreport(r) {
55 | var i = reported.indexOf(r);
56 | if(i >= 0) {
57 | reported.splice(i, 1);
58 | logInfo('Handled previous rejection [' + r.id + '] ' + format.formatObject(r.value));
59 | }
60 | }
61 |
62 | function enqueue(f, x) {
63 | tasks.push(f, x);
64 | if(running === null) {
65 | running = setTimer(flush, 0);
66 | }
67 | }
68 |
69 | function flush() {
70 | running = null;
71 | while(tasks.length > 0) {
72 | tasks.shift()(tasks.shift());
73 | }
74 | }
75 |
76 | return Promise;
77 | };
78 |
79 | function throwit(e) {
80 | throw e;
81 | }
82 |
83 | function noop() {}
84 |
85 | });
86 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
87 |
--------------------------------------------------------------------------------
/lib/decorators/iterate.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 | /** @author Brian Cavalier */
3 | /** @author John Hann */
4 |
5 | (function(define) { 'use strict';
6 | define(function() {
7 |
8 | return function generate(Promise) {
9 |
10 | var resolve = Promise.resolve;
11 |
12 | Promise.iterate = iterate;
13 | Promise.unfold = unfold;
14 |
15 | return Promise;
16 |
17 | /**
18 | * @deprecated Use github.com/cujojs/most streams and most.iterate
19 | * Generate a (potentially infinite) stream of promised values:
20 | * x, f(x), f(f(x)), etc. until condition(x) returns true
21 | * @param {function} f function to generate a new x from the previous x
22 | * @param {function} condition function that, given the current x, returns
23 | * truthy when the iterate should stop
24 | * @param {function} handler function to handle the value produced by f
25 | * @param {*|Promise} x starting value, may be a promise
26 | * @return {Promise} the result of the last call to f before
27 | * condition returns true
28 | */
29 | function iterate(f, condition, handler, x) {
30 | return unfold(function(x) {
31 | return [x, f(x)];
32 | }, condition, handler, x);
33 | }
34 |
35 | /**
36 | * @deprecated Use github.com/cujojs/most streams and most.unfold
37 | * Generate a (potentially infinite) stream of promised values
38 | * by applying handler(generator(seed)) iteratively until
39 | * condition(seed) returns true.
40 | * @param {function} unspool function that generates a [value, newSeed]
41 | * given a seed.
42 | * @param {function} condition function that, given the current seed, returns
43 | * truthy when the unfold should stop
44 | * @param {function} handler function to handle the value produced by unspool
45 | * @param x {*|Promise} starting value, may be a promise
46 | * @return {Promise} the result of the last value produced by unspool before
47 | * condition returns true
48 | */
49 | function unfold(unspool, condition, handler, x) {
50 | return resolve(x).then(function(seed) {
51 | return resolve(condition(seed)).then(function(done) {
52 | return done ? seed : resolve(unspool(seed)).spread(next);
53 | });
54 | });
55 |
56 | function next(item, newSeed) {
57 | return resolve(handler(item)).then(function() {
58 | return unfold(unspool, condition, handler, newSeed);
59 | });
60 | }
61 | }
62 | };
63 |
64 | });
65 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); }));
66 |
--------------------------------------------------------------------------------
/test/inspect-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 | var fail = buster.referee.fail;
4 |
5 | var inspect = require('../lib/decorators/inspect');
6 | var CorePromise = inspect(require('../lib/Promise'));
7 |
8 | var sentinel = { value: 'sentinel' };
9 |
10 | function assertPending(s) {
11 | assert.equals(s.state, 'pending');
12 | }
13 |
14 | function assertFulfilled(s, value) {
15 | assert.equals(s.state, 'fulfilled');
16 | assert.same(s.value, value);
17 | }
18 |
19 | function assertRejected(s, reason) {
20 | assert.equals(s.state, 'rejected');
21 | assert.same(s.reason, reason);
22 | }
23 |
24 | buster.testCase('inspect', {
25 |
26 | 'when inspecting promises': {
27 | 'should return pending state for pending promise': function() {
28 | var promise = new CorePromise(function() {});
29 |
30 | assertPending(promise.inspect());
31 | },
32 |
33 | 'should immediately return fulfilled state for fulfilled promise': function() {
34 | assertFulfilled(CorePromise.resolve(sentinel).inspect(), sentinel);
35 | },
36 |
37 | 'should return fulfilled state for fulfilled promise': function() {
38 | var promise = CorePromise.resolve(sentinel);
39 |
40 | return promise.then(function() {
41 | assertFulfilled(promise.inspect(), sentinel);
42 | });
43 | },
44 |
45 | 'should immediately return rejected state for rejected promise': function() {
46 | assertRejected(CorePromise.reject(sentinel).inspect(), sentinel);
47 | },
48 |
49 | 'should return rejected state for rejected promise': function() {
50 | var promise = CorePromise.reject(sentinel);
51 |
52 | return promise.then(fail, function() {
53 | assertRejected(promise.inspect(), sentinel);
54 | });
55 | }
56 | },
57 |
58 | 'when inspecting thenables': {
59 | 'should return pending state for pending thenable': function() {
60 | var p = CorePromise.resolve({ then: function() {} });
61 |
62 | assertPending(p.inspect());
63 | },
64 |
65 | 'should return fulfilled state for fulfilled thenable': function() {
66 | var p = CorePromise.resolve({ then: function(fulfill) { fulfill(sentinel); } });
67 |
68 | return p.then(function() {
69 | assertFulfilled(p.inspect(), sentinel);
70 | });
71 | },
72 |
73 | 'should return rejected state for rejected thenable': function() {
74 | var p = CorePromise.resolve({ then: function(_, rejected) { rejected(sentinel); } });
75 |
76 | return p.then(fail, function() {
77 | assertRejected(p.inspect(), sentinel);
78 | });
79 | }
80 | }
81 | });
82 |
83 |
--------------------------------------------------------------------------------
/test/race-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 | var fail = buster.referee.fail;
4 |
5 | var CorePromise = require('../lib/Promise');
6 |
7 | var sentinel = { value: 'sentinel' };
8 | var fulfilled = CorePromise.resolve(sentinel);
9 | var never = CorePromise.never();
10 |
11 | function delayReject(ms) {
12 | /*global setTimeout*/
13 | return new CorePromise(function(resolve, reject) {
14 | setTimeout(function() {
15 | reject(sentinel);
16 | }, ms);
17 | });
18 | }
19 |
20 | buster.testCase('CorePromise.race', {
21 | 'should return empty race for length 0': function() {
22 | assert.equals(never, CorePromise.race([]));
23 | },
24 |
25 | 'should reject with TypeError when passed a non-iterable (array in es5)': function() {
26 | return CorePromise.race(null).then(fail, function(e) {
27 | assert(e instanceof TypeError);
28 | });
29 | },
30 |
31 | 'should be identity for length 1': {
32 | 'when fulfilled with value': function() {
33 | return CorePromise.race([sentinel]).then(function(x) {
34 | assert.same(x, sentinel);
35 | });
36 | },
37 |
38 | 'when fulfilled via promise': function() {
39 | return CorePromise.race([fulfilled]).then(function(x) {
40 | assert.same(x, sentinel);
41 | });
42 | },
43 |
44 | 'when rejected': function() {
45 | var rejected = CorePromise.reject(sentinel);
46 | return CorePromise.race([rejected])
47 | .then(void 0, function(x) {
48 | assert.same(x, sentinel);
49 | });
50 | }
51 | },
52 |
53 | 'should be commutative': {
54 | 'when fulfilled': function() {
55 | return CorePromise.race([fulfilled, never]).then(function(x) {
56 | return CorePromise.race([never, fulfilled]).then(function(y) {
57 | assert.same(x, y);
58 | });
59 | });
60 | },
61 |
62 | 'when rejected': function() {
63 | var rejected = CorePromise.reject(sentinel);
64 | return CorePromise.race([rejected, never]).then(void 0, function(x) {
65 | return CorePromise.race([never, rejected]).then(void 0, function(y) {
66 | assert.same(x, y);
67 | });
68 | });
69 | }
70 | },
71 |
72 | 'should fulfill when winner fulfills': function() {
73 | return CorePromise.race([delayReject(1), delayReject(1), fulfilled])
74 | .then(function(x) {
75 | assert.same(x, sentinel);
76 | }, fail);
77 | },
78 |
79 | 'should reject when winner rejects': function() {
80 | var rejected = CorePromise.reject(sentinel);
81 | return CorePromise.race([fulfilled.delay(1), fulfilled.delay(1), rejected])
82 | .then(fail, function(x) {
83 | assert.same(x, sentinel);
84 | });
85 | }
86 | });
87 |
--------------------------------------------------------------------------------
/test/filter-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 |
4 | var when = require('../when');
5 | var sentinel = { value: 'sentinel' };
6 |
7 | function even(x) {
8 | return x % 2 === 0;
9 | }
10 |
11 | function evenPromise(x) {
12 | return when(even(x));
13 | }
14 |
15 | buster.testCase('when.filter', {
16 |
17 | 'should pass index to predicate as second param': function() {
18 | return when.filter(['a','b','c'], function(x, i) {
19 | assert(typeof i === 'number');
20 | return true;
21 | });
22 | },
23 |
24 | 'should filter input values array': function() {
25 | var input = [1, 2, 3];
26 | return when.filter(input, even).then(
27 | function(results) {
28 | assert.equals(input.filter(even), results);
29 | });
30 | },
31 |
32 | 'should filter input promises array': function() {
33 | var input = [1, 2, 3];
34 | return when.filter(input.map(when), even).then(
35 | function(results) {
36 | assert.equals(input.filter(even), results);
37 | });
38 | },
39 |
40 | 'should filter input when predicate returns a promise': function() {
41 | var input = [1,2,3];
42 | return when.filter(input, evenPromise).then(
43 | function(results) {
44 | assert.equals(input.filter(even), results);
45 | });
46 | },
47 |
48 | 'should accept a promise for an array': function() {
49 | var input = [1,2,3];
50 | return when.filter(when(input), even).then(
51 | function(results) {
52 | assert.equals(input.filter(even), results);
53 | });
54 | },
55 |
56 | 'should fulfill with empty array when input promise fulfills with non-array': function() {
57 | return when.filter(when(123), even).then(
58 | function(result) {
59 | assert.equals(result, []);
60 | });
61 | },
62 |
63 | 'should reject when input contains rejection': function() {
64 | var input = [when(1), when.reject(sentinel), 3];
65 | return when.filter(input, even)['catch'](
66 | function(e) {
67 | assert.same(e, sentinel);
68 | });
69 | },
70 |
71 | 'should reject when input is a rejected promise': function() {
72 | return when.filter(when.reject(sentinel), even)['catch'](
73 | function(e) {
74 | assert.same(e, sentinel);
75 | });
76 | },
77 |
78 | 'should match Array.prototype.filter behavior when predicate modifies array': function() {
79 | // Test to match Array.prototype.filter behavior
80 | var a = [1, 2, 3, 4];
81 | var b = a.slice();
82 | var expected = b.filter(makePredicate(b));
83 |
84 | function makePredicate(a) {
85 | return function (n, i){
86 | a[i] = 'fail';
87 | return n % 2 === 0;
88 | };
89 | }
90 |
91 | return when.filter(a, makePredicate(a)).then(function(results) {
92 | assert.equals(results, expected);
93 | });
94 | }
95 |
96 | });
97 |
--------------------------------------------------------------------------------
/test/liftAll-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 | var refute = buster.refute;
4 |
5 | var liftAll = require('../lib/liftAll');
6 |
7 | var sentinel = {};
8 |
9 |
10 | function lift(f) {
11 | return function() {
12 | return f.apply(this, arguments);
13 | };
14 | }
15 |
16 | buster.testCase('when/lib/liftAll', {
17 |
18 | 'should call lift for src own methods': function() {
19 | var src = { a: this.spy(), b: this.spy() };
20 | var dst = liftAll(lift, void 0, void 0, src);
21 |
22 | dst.a(1);
23 | dst.b(2);
24 |
25 | assert.calledOnceWith(src.a, 1);
26 | assert.calledOnceWith(src.b, 2);
27 | },
28 |
29 | 'should not call lift for non-functions': function() {
30 | var src = { a: this.spy(), c: sentinel };
31 | var dst = liftAll(lift, void 0, void 0, src);
32 |
33 | assert.same(dst.c, sentinel);
34 | },
35 |
36 | 'when dst not provided': {
37 | 'and src is an object': {
38 | 'should lift onto Object.create(src)': function() {
39 | var src = { a: this.spy(), b: sentinel };
40 | var dst = liftAll(lift, void 0, void 0, src);
41 |
42 | refute.same(src, dst);
43 | assert.isObject(dst);
44 | assert.same(dst.b, sentinel);
45 | assert(dst.hasOwnProperty('a'));
46 | refute(dst.hasOwnProperty('b'));
47 | }
48 | },
49 | 'and src is a function': {
50 | 'should lift onto a "copy" of src': function() {
51 | var src = this.spy();
52 | src.a = this.spy();
53 | var dst = liftAll(lift, void 0, void 0, src);
54 |
55 | refute.same(src, dst);
56 | assert.isFunction(dst);
57 | assert(dst.hasOwnProperty('a'));
58 |
59 | dst.a();
60 | assert.calledOnce(src.a);
61 | }
62 | }
63 | },
64 |
65 | 'when dst is provided': {
66 | 'when dst is an object': {
67 | 'should lift onto dst': function() {
68 | var src = { a: function(){}, b: sentinel };
69 | var d = {};
70 | var dst = liftAll(lift, void 0, d, src);
71 |
72 | assert.same(dst, d);
73 | }
74 | },
75 | 'when dst is a function': {
76 | 'should lift onto dst': function() {
77 | var src = { a: function(){}, b: sentinel };
78 | var d = function(){};
79 | var dst = liftAll(lift, void 0, d, src);
80 |
81 | assert.same(dst, d);
82 | }
83 | }
84 | },
85 |
86 | 'when combine is provided': {
87 | 'should call combine for all src own methods': function() {
88 | function addKey(o, f, k) {
89 | o[k+'Test'] = f;
90 | return o;
91 | }
92 |
93 | var src = { a: this.spy(), b: this.spy() };
94 | var dst = liftAll(lift, addKey, void 0, src);
95 |
96 | dst.aTest(1);
97 | assert.calledOnceWith(src.a, 1);
98 | assert.isFunction(dst.a);
99 | refute(dst.hasOwnProperty('a'));
100 |
101 | dst.bTest(2);
102 | assert.calledOnceWith(src.b, 2);
103 | assert.isFunction(dst.b);
104 | refute(dst.hasOwnProperty('b'));
105 | }
106 | }
107 |
108 | });
109 |
--------------------------------------------------------------------------------
/test/timeout-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 | var fail = buster.referee.fail;
4 |
5 | var CorePromise = require('../lib/Promise');
6 | var TimeoutError = require('../lib/TimeoutError');
7 | var timeout = require('../timeout');
8 |
9 | var sentinel = {};
10 |
11 | function FakePromise() {
12 | this.then = function() {
13 | return this;
14 | };
15 | }
16 |
17 | buster.testCase('when/timeout', {
18 | 'should reject with TimeoutError': function(done) {
19 | timeout(10, new FakePromise()).then(
20 | fail,
21 | function(e) {
22 | assert(e instanceof TimeoutError);
23 | }
24 | ).ensure(done);
25 | },
26 |
27 | 'should not timeout when rejected before timeout': function(done) {
28 | timeout(10, CorePromise.reject(sentinel)).then(
29 | fail,
30 | function(val) {
31 | assert.same(val, sentinel);
32 | }
33 | ).ensure(done);
34 | },
35 |
36 | 'should not timeout when resolved before timeout': function(done) {
37 | timeout(10, CorePromise.resolve(sentinel)).then(
38 | function(val) {
39 | assert.same(val, sentinel);
40 | },
41 | fail
42 | ).ensure(done);
43 | },
44 |
45 | 'promise.timeout': {
46 |
47 | 'should reject with TimeoutError': function() {
48 | return CorePromise.never().timeout(0).then(
49 | fail,
50 | function(e) {
51 | assert(e instanceof TimeoutError);
52 | }
53 | );
54 | },
55 |
56 | 'should pattern match': function() {
57 | return CorePromise.never().timeout(0).catch(TimeoutError, function(e) {
58 | assert(e instanceof TimeoutError);
59 | });
60 | },
61 |
62 | 'should reject after timeout with the provided reason': function() {
63 | return CorePromise.never().timeout(0, sentinel).then(
64 | fail,
65 | function(e) {
66 | assert.same(e, sentinel);
67 | }
68 | );
69 | },
70 |
71 | 'should reject after timeout with default reason when undefined': function() {
72 | return CorePromise.never().timeout(0, void 0).then(
73 | fail,
74 | function(e) {
75 | assert(e instanceof TimeoutError);
76 | }
77 | );
78 | },
79 |
80 | 'should not timeout when rejected before timeout': function() {
81 | return CorePromise.reject(sentinel).timeout(0).then(
82 | fail,
83 | function(val) {
84 | assert.same(val, sentinel);
85 | }
86 | );
87 | },
88 |
89 | 'should not timeout when resolved before timeout': function() {
90 | return CorePromise.resolve(sentinel).timeout(0).then(
91 | function(val) {
92 | assert.same(val, sentinel);
93 | }
94 | );
95 | },
96 |
97 | 'should propagate progress': function(done) {
98 | return new CorePromise(function(resolve, _, notify) {
99 | notify(sentinel);
100 | })
101 | .timeout(10)
102 | .then(void 0, void 0, function(x) {
103 | assert.same(x, sentinel);
104 | done();
105 | });
106 | }
107 |
108 | }
109 | });
110 |
--------------------------------------------------------------------------------
/test/some-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 | var fail = buster.referee.fail;
4 |
5 | var when = require('../when');
6 |
7 | function contains(array, value) {
8 | for(var i = array.length-1; i >= 0; i--) {
9 | if(array[i] === value) {
10 | return true;
11 | }
12 | }
13 |
14 | return false;
15 | }
16 |
17 | function isSubset(subset, superset) {
18 | var i, subsetLen;
19 |
20 | subsetLen = subset.length;
21 |
22 | if (subsetLen > superset.length) {
23 | return false;
24 | }
25 |
26 | for(i = 0; i number of inputs': {
39 | 'for base case of zero inputs': function() {
40 | return when.some([], 1)['catch'](
41 | function (e) {
42 | assert(e instanceof RangeError);
43 | });
44 | },
45 |
46 | 'for m inputs requesting n > m winners': function() {
47 | var input = [1,,2];
48 | return when.some(input, input.length+1)['catch'](
49 | function (e) {
50 | assert(e instanceof RangeError);
51 | });
52 | }
53 | },
54 |
55 | 'when input promise does not resolve to array': function() {
56 | return when.some(when.resolve(1), 1)['catch'](
57 | function(e) {
58 | assert(e instanceof RangeError);
59 | });
60 | }
61 | },
62 |
63 | 'should reject with all rejected input values if resolving howMany becomes impossible': function() {
64 | var input = [when.resolve(1), when.reject(2), when.reject(3)];
65 | return when.some(input, 2).then(
66 | fail,
67 | function(failed) {
68 | assert.equals(failed, [2, 3]);
69 | });
70 | },
71 |
72 | 'should resolve values array': function() {
73 | var input = [1, 2, 3];
74 | return when.some(input, 2).then(
75 | function(results) {
76 | assert(isSubset(results, input));
77 | });
78 | },
79 |
80 | 'should resolve promises array': function() {
81 | var input = [when.resolve(1), when.resolve(2), when.resolve(3)];
82 | return when.some(input, 2).then(
83 | function(results) {
84 | assert(isSubset(results, [1, 2, 3]));
85 | });
86 | },
87 |
88 | 'should resolve sparse array input': function() {
89 | var input = [, 1, , 2, 3 ];
90 | return when.some(input, 2).then(
91 | function(results) {
92 | assert(isSubset(results, input));
93 | });
94 | },
95 |
96 | 'should accept a promise for an array': function() {
97 | var expected, input;
98 |
99 | expected = [1, 2, 3];
100 | input = when.resolve(expected);
101 |
102 | return when.some(input, 2).then(
103 | function(results) {
104 | assert.equals(results.length, 2);
105 | });
106 | },
107 |
108 | 'should resolve to empty array when n is zero': function() {
109 | return when.some([1,2,3], 0).then(function(result) {
110 | assert.equals(result, []);
111 | });
112 | }
113 | });
114 |
--------------------------------------------------------------------------------
/generator.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 | /** @author Brian Cavalier */
3 | /** @author John Hann */
4 |
5 | (function(define) { 'use strict';
6 | define(function(require) {
7 |
8 | var when = require('./when');
9 | var slice = Array.prototype.slice;
10 | var Promise = when.Promise;
11 | var reject = Promise.reject;
12 |
13 | /**
14 | * Lift a generator to create a function that can suspend and
15 | * resume using the `yield` keyword to await promises.
16 | * @param {function} generator
17 | * @return {function}
18 | */
19 | function lift(generator) {
20 | return function() {
21 | return run(generator, this, arguments);
22 | };
23 | }
24 |
25 | /**
26 | * Immediately call a generator as a promise-aware coroutine
27 | * that can suspend and resume using the `yield` keyword to
28 | * await promises. Additional arguments after the first will
29 | * be passed through to the generator.
30 | * @param {function} generator
31 | * @returns {Promise} promise for the ultimate value returned
32 | * from the generator.
33 | */
34 | function call(generator /*x, y, z...*/) {
35 | /*jshint validthis:true*/
36 | return run(generator, this, slice.call(arguments, 1));
37 | }
38 |
39 | /**
40 | * Immediately apply a generator, with the supplied args array,
41 | * as a promise-aware coroutine that can suspend and resume
42 | * using the `yield` keyword to await promises.
43 | * @param {function} generator
44 | * @param {Array} args arguments with which to initialize the generator
45 | * @returns {Promise} promise for the ultimate value returned
46 | * from the generator.
47 | */
48 | function apply(generator, args) {
49 | /*jshint validthis:true*/
50 | return run(generator, this, args || []);
51 | }
52 |
53 | /**
54 | * Helper to initiate the provided generator as a coroutine
55 | * @returns {*}
56 | */
57 | function run(generator, thisArg, args) {
58 | return runNext(void 0, generator.apply(thisArg, args));
59 | }
60 |
61 | function runNext(x, iterator) {
62 | try {
63 | return handle(iterator.next(x), iterator);
64 | } catch(e) {
65 | return reject(e);
66 | }
67 | }
68 |
69 | function next(x) {
70 | /*jshint validthis:true*/
71 | return runNext(x, this);
72 | }
73 |
74 | function error(e) {
75 | /*jshint validthis:true*/
76 | try {
77 | return handle(this.throw(e), this);
78 | } catch(e) {
79 | return reject(e);
80 | }
81 | }
82 |
83 | function handle(result, iterator) {
84 | if(result.done) {
85 | return result.value;
86 | }
87 |
88 | var h = Promise._handler(result.value);
89 | if(h.state() > 0) {
90 | return runNext(h.value, iterator);
91 | }
92 |
93 | var p = Promise._defer();
94 | h.chain(p._handler, iterator, next, error);
95 | return p;
96 | }
97 |
98 | return {
99 | lift: lift,
100 | call: call,
101 | apply: apply
102 | };
103 |
104 | });
105 | }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));
106 |
--------------------------------------------------------------------------------
/test/globalRejectionEvents-test.js:
--------------------------------------------------------------------------------
1 | /*global process, window, setTimeout*/
2 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
3 |
4 | var CorePromise = require('../lib/Promise');
5 |
6 | var sentinel = { value: 'sentinel' };
7 |
8 | buster.testCase('global rejection events', {
9 |
10 | 'on Node': {
11 | 'tearDown': function() {
12 | if(typeof process === 'undefined') {
13 | return;
14 | }
15 |
16 | process.removeAllListeners('unhandledRejection');
17 | process.removeAllListeners('rejectionHandled');
18 | },
19 |
20 | 'should emit unhandledRejection': function(done) {
21 | if(typeof window !== 'undefined') {
22 | buster.assert(true);
23 | return;
24 | }
25 |
26 | function listener(e) {
27 | buster.assert.same(e, sentinel);
28 | done();
29 | }
30 |
31 | process.on('unhandledRejection', listener);
32 |
33 | CorePromise.reject(sentinel);
34 | },
35 |
36 | 'should emit rejectionHandled': function(done) {
37 | if(typeof window !== 'undefined') {
38 | buster.assert(true);
39 | return;
40 | }
41 |
42 | var r;
43 | function unhandled(e, rejection) {
44 | buster.assert.same(e, sentinel);
45 | r = rejection;
46 | }
47 |
48 | function handled(rejection) {
49 | buster.assert.same(rejection, r);
50 | done();
51 | }
52 |
53 | process.on('unhandledRejection', unhandled);
54 | process.on('rejectionHandled', handled);
55 |
56 | var p = CorePromise.reject(sentinel);
57 | setTimeout(function() {
58 | p.catch(function() {});
59 | }, 10);
60 | }
61 | },
62 |
63 | 'in Browser': {
64 | 'should emit unhandledRejection': function(done) {
65 | if(typeof window === 'undefined') {
66 | buster.assert(true);
67 | done();
68 | return;
69 | }
70 |
71 | function listener(e) {
72 | window.removeEventListener('unhandledRejection', listener, false);
73 | e.preventDefault();
74 | buster.assert.same(e.detail.reason, sentinel);
75 | done();
76 | }
77 |
78 | window.addEventListener('unhandledRejection', listener, false);
79 |
80 | CorePromise.reject(sentinel);
81 | },
82 |
83 | 'should emit rejectionHandled': function(done) {
84 | if(typeof window === 'undefined') {
85 | buster.assert(true);
86 | done();
87 | return;
88 | }
89 |
90 | var key;
91 | function unhandled(e) {
92 | window.removeEventListener('unhandledRejection', unhandled, false);
93 | buster.assert.same(e.detail.reason, sentinel);
94 | key = e.detail.key;
95 | }
96 |
97 | function handled(e) {
98 | window.removeEventListener('rejectionHandled', handled, false);
99 | buster.assert.same(e.detail.key, key);
100 | done();
101 | }
102 |
103 | window.addEventListener('unhandledRejection', unhandled, false);
104 | window.addEventListener('rejectionHandled', handled, false);
105 |
106 | var p = CorePromise.reject(sentinel);
107 | setTimeout(function() {
108 | p.catch(function() {});
109 | }, 10);
110 | }
111 | }
112 |
113 | });
114 |
115 |
--------------------------------------------------------------------------------
/monitor/ConsoleReporter.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2010-2014 original author or authors */
2 | /** @author Brian Cavalier */
3 | /** @author John Hann */
4 |
5 | (function(define) { 'use strict';
6 | define(function(require) {
7 |
8 | var error = require('./error');
9 | var unhandledRejectionsMsg = '[promises] Unhandled rejections: ';
10 | var allHandledMsg = '[promises] All previously unhandled rejections have now been handled';
11 |
12 | function ConsoleReporter() {
13 | this._previouslyReported = false;
14 | }
15 |
16 | ConsoleReporter.prototype = initDefaultLogging();
17 |
18 | ConsoleReporter.prototype.log = function(traces) {
19 | if(traces.length === 0) {
20 | if(this._previouslyReported) {
21 | this._previouslyReported = false;
22 | this.msg(allHandledMsg);
23 | }
24 | return;
25 | }
26 |
27 | this._previouslyReported = true;
28 | this.groupStart(unhandledRejectionsMsg + traces.length);
29 | try {
30 | this._log(traces);
31 | } finally {
32 | this.groupEnd();
33 | }
34 | };
35 |
36 | ConsoleReporter.prototype._log = function(traces) {
37 | for(var i=0; i 1 rejection': function(done) {
89 | /*global setTimeout*/
90 | var origOnUnhandled = CorePromise.onPotentiallyUnhandledRejection;
91 | CorePromise.onPotentiallyUnhandledRejection = function() {
92 | fail(new Error('should not report unhandled rejection'));
93 | };
94 |
95 | when.all([rejected(sentinel), resolved(123), rejected(other)])
96 | ['catch'](function(e) {
97 | assert.same(e, sentinel);
98 | setTimeout(function() {
99 | CorePromise.onPotentiallyUnhandledRejection = origOnUnhandled;
100 | done();
101 | }, 100);
102 | });
103 | },
104 |
105 | 'when array contains same rejection multiple times': function(done) {
106 | /*global setTimeout*/
107 | var origOnUnhandled = CorePromise.onPotentiallyUnhandledRejection;
108 | CorePromise.onPotentiallyUnhandledRejection = function() {
109 | fail(new Error('should not report unhandled rejection'));
110 | };
111 |
112 | var r = rejected(sentinel);
113 | when.all([r, r.then()])
114 | ['catch'](function(e) {
115 | assert.same(e, sentinel);
116 | setTimeout(function() {
117 | CorePromise.onPotentiallyUnhandledRejection = origOnUnhandled;
118 | done();
119 | }, 100);
120 | });
121 | }
122 | }
123 |
124 | });
125 |
--------------------------------------------------------------------------------
/poll.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2012-2013 original author or authors */
2 |
3 | /**
4 | * poll.js
5 | *
6 | * Helper that polls until cancelled or for a condition to become true.
7 | *
8 | * @author Scott Andrews
9 | */
10 |
11 | (function (define) { 'use strict';
12 | define(function(require) {
13 |
14 | var when = require('./when');
15 | var attempt = when['try'];
16 | var cancelable = require('./cancelable');
17 |
18 | /**
19 | * Periodically execute the task function on the msec delay. The result of
20 | * the task may be verified by watching for a condition to become true. The
21 | * returned deferred is cancellable if the polling needs to be cancelled
22 | * externally before reaching a resolved state.
23 | *
24 | * The next vote is scheduled after the results of the current vote are
25 | * verified and rejected.
26 | *
27 | * Polling may be terminated by the verifier returning a truthy value,
28 | * invoking cancel() on the returned promise, or the task function returning
29 | * a rejected promise.
30 | *
31 | * Usage:
32 | *
33 | * var count = 0;
34 | * function doSomething() { return count++ }
35 | *
36 | * // poll until cancelled
37 | * var p = poll(doSomething, 1000);
38 | * ...
39 | * p.cancel();
40 | *
41 | * // poll until condition is met
42 | * poll(doSomething, 1000, function(result) { return result > 10 })
43 | * .then(function(result) { assert result == 10 });
44 | *
45 | * // delay first vote
46 | * poll(doSomething, 1000, anyFunc, true);
47 | *
48 | * @param task {Function} function that is executed after every timeout
49 | * @param interval {number|Function} timeout in milliseconds
50 | * @param [verifier] {Function} function to evaluate the result of the vote.
51 | * May return a {Promise} or a {Boolean}. Rejecting the promise or a
52 | * falsey value will schedule the next vote.
53 | * @param [delayInitialTask] {boolean} if truthy, the first vote is scheduled
54 | * instead of immediate
55 | *
56 | * @returns {Promise}
57 | */
58 | return function poll(task, interval, verifier, delayInitialTask) {
59 | var deferred, canceled, reject;
60 |
61 | canceled = false;
62 | deferred = cancelable(when.defer(), function () { canceled = true; });
63 | reject = deferred.reject;
64 |
65 | verifier = verifier || function () { return false; };
66 |
67 | if (typeof interval !== 'function') {
68 | interval = (function (interval) {
69 | return function () { return when().delay(interval); };
70 | })(interval);
71 | }
72 |
73 | function certify(result) {
74 | deferred.resolve(result);
75 | }
76 |
77 | function schedule(result) {
78 | attempt(interval).then(vote, reject);
79 | if (result !== void 0) {
80 | deferred.notify(result);
81 | }
82 | }
83 |
84 | function vote() {
85 | if (canceled) { return; }
86 | when(task(),
87 | function (result) {
88 | when(verifier(result),
89 | function (verification) {
90 | return verification ? certify(result) : schedule(result);
91 | },
92 | function () { schedule(result); }
93 | );
94 | },
95 | reject
96 | );
97 | }
98 |
99 | if (delayInitialTask) {
100 | schedule();
101 | } else {
102 | // if task() is blocking, vote will also block
103 | vote();
104 | }
105 |
106 | // make the promise cancelable
107 | deferred.promise = Object.create(deferred.promise);
108 | deferred.promise.cancel = deferred.cancel;
109 |
110 | return deferred.promise;
111 | };
112 |
113 | });
114 | })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); });
115 |
--------------------------------------------------------------------------------
/test/map-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 | var fail = buster.referee.fail;
4 |
5 | var when = require('../when');
6 | var resolved = when.resolve;
7 | var reject = when.reject;
8 |
9 | /*global setInterval,clearInterval*/
10 |
11 | function mapper(val) {
12 | return val * 2;
13 | }
14 |
15 | function deferredMapper(val) {
16 | return when(mapper(val)).delay(Math.random()*10);
17 | }
18 |
19 | function identity(x) {
20 | return x;
21 | }
22 |
23 | buster.testCase('when.map', {
24 |
25 | 'should pass index to predicate as second param': function() {
26 | return when.map(['a','b','c'], function(x, i) {
27 | assert(typeof i === 'number');
28 | return x;
29 | });
30 | },
31 |
32 | 'should map input values array': function(done) {
33 | var input = [1, 2, 3];
34 | when.map(input, mapper).then(
35 | function(results) {
36 | assert.equals(results, [2,4,6]);
37 | },
38 | fail
39 | ).ensure(done);
40 | },
41 |
42 | 'should map input promises array': function(done) {
43 | var input = [resolved(1), resolved(2), resolved(3)];
44 | when.map(input, mapper).then(
45 | function(results) {
46 | assert.equals(results, [2,4,6]);
47 | },
48 | fail
49 | ).ensure(done);
50 | },
51 |
52 | 'should map mixed input array': function(done) {
53 | var input = [1, resolved(2), 3];
54 | when.map(input, mapper).then(
55 | function(results) {
56 | assert.equals(results, [2,4,6]);
57 | },
58 | fail
59 | ).ensure(done);
60 | },
61 |
62 | 'should map input when mapper returns a promise': function(done) {
63 | var input = [1,2,3];
64 | when.map(input, deferredMapper).then(
65 | function(results) {
66 | assert.equals(results, [2,4,6]);
67 | },
68 | fail
69 | ).ensure(done);
70 | },
71 |
72 | 'should accept a promise for an array': function(done) {
73 | when.map(resolved([1, resolved(2), 3]), mapper).then(
74 | function(result) {
75 | assert.equals(result, [2,4,6]);
76 | },
77 | fail
78 | ).ensure(done);
79 | },
80 |
81 | 'should resolve to empty array when input promise does not resolve to an array': function(done) {
82 | when.map(resolved(123), mapper).then(
83 | function(result) {
84 | assert.equals(result, []);
85 | },
86 | fail
87 | ).ensure(done);
88 | },
89 |
90 | 'should map input promises when mapper returns a promise': function(done) {
91 | var input = [resolved(1),resolved(2),resolved(3)];
92 | when.map(input, mapper).then(
93 | function(results) {
94 | assert.equals(results, [2,4,6]);
95 | },
96 | fail
97 | ).ensure(done);
98 | },
99 |
100 | 'should reject when input contains rejection': function(done) {
101 | var input = [resolved(1), reject(2), resolved(3)];
102 | when.map(input, mapper).then(
103 | fail,
104 | function(result) {
105 | assert.equals(result, 2);
106 | }
107 | ).ensure(done);
108 | },
109 |
110 | 'should propagate progress': function() {
111 | // Thanks @depeele for this test
112 | var input = [_resolver(1), _resolver(2), _resolver(3)];
113 | var ncall = 0;
114 |
115 | return when.map(input, identity).then(
116 | function() {
117 | assert.equals(ncall, 6);
118 | },
119 | fail,
120 | function() {
121 | ncall++;
122 | }
123 | );
124 |
125 | function _resolver(id) {
126 | return when.promise(function(resolve, reject, notify) {
127 | var loop = 0;
128 | var timer = setInterval(function () {
129 | notify(id);
130 | loop++;
131 | if (loop === 2) {
132 | clearInterval(timer);
133 | resolve(id);
134 | }
135 | }, 1);
136 | });
137 | }
138 | }
139 | });
140 |
--------------------------------------------------------------------------------
/docs/installation.md:
--------------------------------------------------------------------------------
1 | Getting Started
2 | ===============
3 |
4 | [CJS](http://wiki.commonjs.org/wiki/CommonJS) and [AMD](http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition) are the primary targets for `when`, but instructions for a variety of setups are provided below.
5 |
6 | As of version 3.0, when.js requires an ES5 environment. In older environments, use an ES5 shim such as [poly](https://github.com/cujojs/poly) or [es5-shim](https://github.com/es-shims/es5-shim)
7 |
8 | #### RaveJS
9 |
10 | If you're already using [RaveJS](https://github.com/RaveJS/rave), just install when.js and start coding:
11 |
12 | 1. `npm install --save when` or `bower install --save when`
13 | 1. `var when = require('when');`
14 |
15 | #### AMD
16 |
17 | 1. Get it. `bower install --save when`, or `git clone https://github.com/cujojs/when`
18 |
19 | 1. Configure your loader. Here is an example of how configuring the package might look:
20 |
21 | ```js
22 | // using requirejs
23 | requirejs.config({
24 | packages: [
25 | { name: 'when', location: '/path/to/when', main: 'when' }
26 | ]
27 | });
28 |
29 | // using curl.js
30 | curl.config({
31 | packages: {
32 | when: { location: '/path/to/when', main: 'when' }
33 | }
34 | });
35 | ```
36 |
37 | 1. Load when wherever you need it. For example, as part of a module:
38 |
39 | ```
40 | define(function(require) {
41 | var when = require('when');
42 |
43 | // your code...
44 | });
45 | ```
46 |
47 | #### Node
48 |
49 | 1. `npm install --save when`
50 | 1. `var when = require('when');`
51 |
52 | #### RingoJS
53 |
54 | 1. `ringo-admin install cujojs/when`
55 | 1. `var when = require('when');`
56 |
57 | #### Ender
58 |
59 | 1. `ender add when`
60 | 2. `var when = require('when');`
61 |
62 | #### Other CommonJS environments (eg vert.x 1.x and 2.x with CommonJS module support)
63 |
64 | 1. `git clone https://github.com/cujojs/when`
65 | 1. `var when = require('when');` or `var when = require('path/to/when');`
66 |
67 | #### Browser environments (via browserify)
68 |
69 | If you prefer not to use an AMD or CommonJS loader in your project, you can use a pre-built UMD module available in `dist/browser/when[.min|.debug].js` to have a global `when` available.
70 |
71 | 1. `npm install --save when`
72 | 1. ``
73 | 1. Or `` for minified version
74 | 1. Or `` with [when/monitor/console](api.md#debugging-promises) enabled
75 | 1. `when` will be available as `window.when`
76 | 1. Other modules will be available as sub-objects/functions, e.g. `window.when.fn.lift`, `window.when.sequence`. See the [full sub-namespace list in the browserify build file](../build/when.browserify.js)
77 |
78 | If you expose the whole `dist/browser` folder in your application (or make sure that `when[.min|.debug].js` has its corresponding `*.map` file available next to it), you will have the [source maps](https://developer.chrome.com/devtools/docs/javascript-debugging#source-maps) available for debugging in the browser.
79 |
80 | #### Web Worker (via browserify)
81 |
82 | Similarly to browser global environments:
83 |
84 | 1. `npm install --save when`
85 | 1. `importScripts('path/to/when/dist/browser/when.js');`
86 | 1. Or `importScripts('path/to/when/dist/browser/when.min.js');` for minified version
87 | 1. Or `importScripts('path/to/when/dist/browser/when.debug.js');` with [when/monitor/console](api.md#debugging-promises) enabled
88 | 1. `when` will be available as `self.when`
89 | 1. Other modules will be available as sub-objects/functions, e.g. `self.when.fn.lift`, `self.when.sequence`. See the [full sub-namespace list in the browserify build file](../build/when.browserify.js)
90 |
--------------------------------------------------------------------------------
/test/guard-test.js:
--------------------------------------------------------------------------------
1 | var buster = typeof window !== 'undefined' ? window.buster : require('buster');
2 | var assert = buster.assert;
3 | var fail = buster.referee.fail;
4 |
5 | var when = require('../when');
6 | var guard = require('../guard');
7 |
8 | var sentinel = {};
9 | var other = {};
10 |
11 | function noop() {}
12 |
13 | buster.testCase('when/guard', {
14 |
15 | 'should return a function': function() {
16 | assert.isFunction(guard());
17 | },
18 |
19 | 'should invoke condition': function() {
20 | var condition, guarded;
21 |
22 | condition = this.spy();
23 | guarded = guard(condition, noop);
24 |
25 | guarded();
26 |
27 | assert.called(condition);
28 | },
29 |
30 | 'should invoke guarded function after condition promise fulfills': function(done) {
31 | var condition, f, guarded;
32 |
33 | condition = function() { return noop; };
34 | f = this.spy();
35 | guarded = guard(condition, f);
36 |
37 | guarded(sentinel).then(
38 | function() {
39 | assert.calledOnce(f);
40 | assert.same(f.firstCall.args[0], sentinel);
41 | },
42 | fail
43 | ).ensure(done);
44 | },
45 |
46 | 'should notify condition once guarded function settles': function(done) {
47 | var condition, notify, guarded;
48 |
49 | notify = this.spy();
50 | condition = function() { return notify; };
51 | guarded = guard(condition, noop);
52 |
53 | guarded().then(
54 | function() {
55 | assert.calledOnce(notify);
56 | },
57 | fail
58 | ).ensure(done);
59 | },
60 |
61 | 'should initiate next guarded call after notify': function(done) {
62 | var condition, f, guarded;
63 |
64 | f = this.spy();
65 | condition = function() { return noop; };
66 | guarded = guard(condition, f);
67 |
68 | guarded(other).then(
69 | function() {
70 | assert.calledOnce(f);
71 | return guarded(sentinel).then(function() {
72 | assert.calledTwice(f);
73 | assert.same(f.secondCall.args[0], sentinel);
74 | });
75 | },
76 | fail
77 | ).ensure(done);
78 | },
79 |
80 | 'n': {
81 | 'should create a function': function() {
82 | assert.isFunction(guard.n(1));
83 | },
84 |
85 | 'should return a promise': function() {
86 | var c = guard.n(1);
87 | assert.isFunction(c().then);
88 | },
89 |
90 | 'returned promise should resolve to a function': function(done) {
91 | var enter = guard.n(1);
92 | enter().then(
93 | function(exit) {
94 | assert.isFunction(exit);
95 | },
96 | fail
97 | ).ensure(done);
98 | },
99 |
100 | 'should allow one execution': function(done) {
101 | var enter, value, first, second;
102 |
103 | enter = guard.n(1);
104 | value = sentinel;
105 |
106 | first = enter();
107 | second = enter();
108 |
109 | first.then(
110 | function(exit) {
111 | return when().delay(100).then(function() {
112 | assert.same(value, sentinel);
113 | exit();
114 | });
115 | },
116 | fail
117 | );
118 |
119 | second.then(
120 | function() { value = other; }
121 | ).ensure(done);
122 | },
123 |
124 | 'should allow two executions': function(done) {
125 | var one, value, first, second, third;
126 |
127 | one = guard.n(2);
128 | value = sentinel;
129 |
130 | first = one();
131 | second = one();
132 | third = one();
133 |
134 | first.then(
135 | function() {
136 | assert.same(value, sentinel);
137 | },
138 | fail
139 | );
140 |
141 | second.then(
142 | function(exit) {
143 | return when().delay(100).then(function() {
144 | assert.same(value, sentinel);
145 | exit();
146 | });
147 | },
148 | fail
149 | );
150 |
151 | third.then(
152 | function() { value = other; }
153 | ).ensure(done);
154 | }
155 | }
156 |
157 | });
158 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "when",
3 | "version": "3.7.7",
4 | "description": "A lightweight Promises/A+ and when() implementation, plus other async goodies.",
5 | "keywords": [
6 | "cujo",
7 | "Promises/A+",
8 | "promises-aplus",
9 | "promise",
10 | "promises",
11 | "deferred",
12 | "deferreds",
13 | "when",
14 | "async",
15 | "asynchronous",
16 | "ender"
17 | ],
18 | "homepage": "http://cujojs.com",
19 | "license": "MIT",
20 | "repository": {
21 | "type": "git",
22 | "url": "https://github.com/cujojs/when"
23 | },
24 | "bugs": "https://github.com/cujojs/when/issues",
25 | "maintainers": [
26 | {
27 | "name": "Brian Cavalier",
28 | "web": "http://hovercraftstudios.com"
29 | },
30 | {
31 | "name": "John Hann",
32 | "web": "http://unscriptable.com"
33 | }
34 | ],
35 | "contributors": [
36 | {
37 | "name": "Brian Cavalier",
38 | "web": "http://hovercraftstudios.com"
39 | },
40 | {
41 | "name": "John Hann",
42 | "web": "http://unscriptable.com"
43 | },
44 | {
45 | "name": "Scott Andrews"
46 | }
47 | ],
48 | "devDependencies": {
49 | "benchmark": "~1",
50 | "browserify": "~2",
51 | "buster": "~0.7",
52 | "exorcist": "~0.4",
53 | "jshint": "~2",
54 | "json5": "~0.2",
55 | "microtime": "~2",
56 | "optimist": "~0.6",
57 | "poly": "^0.6.1",
58 | "promises-aplus-tests": "~2",
59 | "rest": "1.1.x",
60 | "sauce-connect-launcher": "~0.4",
61 | "uglify-js": "~2",
62 | "wd": "~0.2"
63 | },
64 | "main": "when.js",
65 | "ender": {
66 | "files": [
67 | "*.js",
68 | "lib/*.js",
69 | "node/*.js",
70 | "unfold/*.js",
71 | "monitor/*.js",
72 | "lib/decorators/*.js"
73 | ]
74 | },
75 | "browser": {
76 | "when": "./dist/browser/when.js",
77 | "vertx": false
78 | },
79 | "directories": {
80 | "test": "test"
81 | },
82 | "scripts": {
83 | "test": "jshint . && buster-test -e node && promises-aplus-tests test/promises-aplus-adapter.js",
84 | "build-browser-test": "browserify ./node_modules/poly/es5.js -o test/browser/es5.js && browserify ./test/*-test.js ./test/**/*-test.js -o test/browser/tests.js -x buster ",
85 | "browser-test": "npm run build-browser-test && buster-static -e browser -p 8080",
86 | "ci": "npm test && node test/sauce.js",
87 | "tunnel": "node test/sauce.js -m",
88 | "start": "buster-static -e browser",
89 | "benchmark": "node benchmark/promise && node benchmark/map",
90 | "prepublish": "npm run browserify && npm run uglify",
91 | "preversion": "npm run browserify && npm run uglify",
92 | "browserify": "npm run browserify-es6 && npm run browserify-when && npm run browserify-debug",
93 | "browserify-es6": "browserify -s Promise es6-shim/Promise.browserify-es6.js --no-detect-globals --debug | exorcist -b . -r https://raw.githubusercontent.com/cujojs/when/`git rev-parse HEAD` es6-shim/Promise.js.map >es6-shim/Promise.js",
94 | "browserify-when": "mkdir -p dist/browser && browserify -s when build/when.browserify.js --no-detect-globals --debug | exorcist -b . -r https://raw.githubusercontent.com/cujojs/when/`git rev-parse HEAD` dist/browser/when.js.map >dist/browser/when.js",
95 | "browserify-debug": "mkdir -p dist/browser && browserify -s when build/when.browserify-debug.js --no-detect-globals --debug | exorcist -b . -r https://raw.githubusercontent.com/cujojs/when/`git rev-parse HEAD` dist/browser/when.debug.js.map >dist/browser/when.debug.js",
96 | "uglify": "npm run uglify-es6 && npm run uglify-when",
97 | "uglify-es6": "cd es6-shim; uglifyjs Promise.js --compress --mangle --in-source-map Promise.js.map --source-map Promise.min.js.map -o Promise.min.js; cd ../..",
98 | "uglify-when": "cd dist/browser; uglifyjs when.js --compress --mangle --in-source-map when.js.map --source-map when.min.js.map -o when.min.js; cd ../.."
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | [](https://travis-ci.org/cujojs/when)
4 | [](http://inch-ci.org/github/cujojs/when)
5 |
6 | when.js
7 | =======
8 |
9 | When.js is a rock solid, battle-tested [Promises/A+](http://promises-aplus.github.com/promises-spec) and `when()` implementation, including a complete [ES6 Promise shim](docs/es6-promise-shim.md). It's a powerful combination of small size, high performance, debuggability, and rich features:
10 |
11 | * Resolve arrays and hashes of promises, as well as infinite promise sequences
12 | * Execute tasks in parallel or sequentially
13 | * Transform Node-style and other callback-based APIs into promise-based APIs
14 |
15 | When.js is one of the many stand-alone components of [cujoJS](http://cujojs.com), the JavaScript Architectural Toolkit.
16 |
17 | Check it out:
18 |
19 | - [What's new](CHANGES.md)
20 | - [API docs](docs/api.md#api)
21 | - Read more about how [promises simplify async programming](http://know.cujojs.com/tutorials/async/simplifying-async-with-promises)
22 |
23 | Installation
24 | ------------
25 |
26 | #### AMD
27 |
28 | Available as `when` through [bower](http://bower.io), or just clone the repo and load `when.js` from the root.
29 |
30 | ```
31 | bower install --save when
32 | ```
33 |
34 | #### CommonJS/Node
35 |
36 | ```
37 | npm install --save when
38 | ```
39 |
40 | [More help & other environments »](docs/installation.md)
41 |
42 | Usage
43 | -----
44 |
45 | Promises can be used to help manage complex and/or nested callback flows in a simple manner. To get a better handle on how promise flows look and how they can be helpful, there are a couple examples below (using commonjs).
46 |
47 | This first example will print `"hello world!!!!"` if all went well, or `"drat!"` if there was a problem. It also uses [rest](https://github.com/cujojs/rest) to make an ajax request to a (fictional) external service.
48 |
49 | ```js
50 | var rest = require('rest');
51 |
52 | fetchRemoteGreeting()
53 | .then(addExclamation)
54 | .catch(handleError)
55 | .done(function(greeting) {
56 | console.log(greeting);
57 | });
58 |
59 | function fetchRemoteGreeting() {
60 | // returns a when.js promise for 'hello world'
61 | return rest('http://example.com/greeting');
62 | }
63 |
64 | function addExclamation(greeting) {
65 | return greeting + '!!!!'
66 | }
67 |
68 | function handleError(e) {
69 | return 'drat!';
70 | }
71 | ```
72 |
73 | The second example shows off the power that comes with when's promise logic. Here, we get an array of numbers from a remote source and reduce them. The example will print `150` if all went well, and if there was a problem will print a full stack trace.
74 |
75 | ```js
76 | var when = require('when');
77 | var rest = require('rest');
78 |
79 | when.reduce(when.map(getRemoteNumberList(), times10), sum)
80 | .done(function(result) {
81 | console.log(result);
82 | });
83 |
84 | function getRemoteNumberList() {
85 | // Get a remote array [1, 2, 3, 4, 5]
86 | return rest('http://example.com/numbers').then(JSON.parse);
87 | }
88 |
89 | function sum(x, y) { return x + y; }
90 | function times10(x) {return x * 10; }
91 | ```
92 |
93 | License
94 | -------
95 |
96 | Licensed under MIT. [Full license here »](LICENSE.txt)
97 |
98 | Contributing
99 | ------------
100 |
101 | Please see the [contributing guide](CONTRIBUTING.md) for more information on running tests, opening issues, and contributing code to the project.
102 |
103 | References
104 | ----------
105 |
106 | Much of this code was inspired by the async innards of [wire.js](https://github.com/cujojs/wire), and has been influenced by the great work in [Q](https://github.com/kriskowal/q), [Dojo's Deferred](https://github.com/dojo/dojo), and [uber.js](https://github.com/phiggins42/uber.js).
107 |
--------------------------------------------------------------------------------
/function.js:
--------------------------------------------------------------------------------
1 | /** @license MIT License (c) copyright 2013-2014 original author or authors */
2 |
3 | /**
4 | * Collection of helper functions for wrapping and executing 'traditional'
5 | * synchronous functions in a promise interface.
6 | *
7 | * @author Brian Cavalier
8 | * @contributor Renato Zannon
9 | */
10 |
11 | (function(define) {
12 | define(function(require) {
13 |
14 | var when = require('./when');
15 | var attempt = when['try'];
16 | var _liftAll = require('./lib/liftAll');
17 | var _apply = require('./lib/apply')(when.Promise);
18 | var slice = Array.prototype.slice;
19 |
20 | return {
21 | lift: lift,
22 | liftAll: liftAll,
23 | call: attempt,
24 | apply: apply,
25 | compose: compose
26 | };
27 |
28 | /**
29 | * Takes a function and an optional array of arguments (that might be promises),
30 | * and calls the function. The return value is a promise whose resolution
31 | * depends on the value returned by the function.
32 | * @param {function} f function to be called
33 | * @param {Array} [args] array of arguments to func
34 | * @returns {Promise} promise for the return value of func
35 | */
36 | function apply(f, args) {
37 | // slice args just in case the caller passed an Arguments instance
38 | return _apply(f, this, args == null ? [] : slice.call(args));
39 | }
40 |
41 | /**
42 | * Takes a 'regular' function and returns a version of that function that
43 | * returns a promise instead of a plain value, and handles thrown errors by
44 | * returning a rejected promise. Also accepts a list of arguments to be
45 | * prepended to the new function, as does Function.prototype.bind.
46 | *
47 | * The resulting function is promise-aware, in the sense that it accepts
48 | * promise arguments, and waits for their resolution.
49 | * @param {Function} f function to be bound
50 | * @param {...*} [args] arguments to be prepended for the new function @deprecated
51 | * @returns {Function} a promise-returning function
52 | */
53 | function lift(f /*, args... */) {
54 | var args = arguments.length > 1 ? slice.call(arguments, 1) : [];
55 | return function() {
56 | return _apply(f, this, args.concat(slice.call(arguments)));
57 | };
58 | }
59 |
60 | /**
61 | * Lift all the functions/methods on src
62 | * @param {object|function} src source whose functions will be lifted
63 | * @param {function?} combine optional function for customizing the lifting
64 | * process. It is passed dst, the lifted function, and the property name of
65 | * the original function on src.
66 | * @param {(object|function)?} dst option destination host onto which to place lifted
67 | * functions. If not provided, liftAll returns a new object.
68 | * @returns {*} If dst is provided, returns dst with lifted functions as
69 | * properties. If dst not provided, returns a new object with lifted functions.
70 | */
71 | function liftAll(src, combine, dst) {
72 | return _liftAll(lift, combine, dst, src);
73 | }
74 |
75 | /**
76 | * Composes multiple functions by piping their return values. It is
77 | * transparent to whether the functions return 'regular' values or promises:
78 | * the piped argument is always a resolved value. If one of the functions
79 | * throws or returns a rejected promise, the composed promise will be also
80 | * rejected.
81 | *
82 | * The arguments (or promises to arguments) given to the returned function (if
83 | * any), are passed directly to the first function on the 'pipeline'.
84 | * @param {Function} f the function to which the arguments will be passed
85 | * @param {...Function} [funcs] functions that will be composed, in order
86 | * @returns {Function} a promise-returning composition of the functions
87 | */
88 | function compose(f /*, funcs... */) {
89 | var funcs = slice.call(arguments, 1);
90 |
91 | return function() {
92 | var thisArg = this;
93 | var args = slice.call(arguments);
94 | var firstPromise = attempt.apply(thisArg, [f].concat(args));
95 |
96 | return when.reduce(funcs, function(arg, func) {
97 | return func.call(thisArg, arg);
98 | }, firstPromise);
99 | };
100 | }
101 | });
102 | })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); });
103 |
104 |
105 |
--------------------------------------------------------------------------------
/docs/es6-promise-shim.md:
--------------------------------------------------------------------------------
1 | # ES6 Promise shim
2 |
3 | When 3.x includes a shim for [ES6 Promise](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-promise-constructor). To use it, simply load `when/es6-shim/Promise.js` via script tag or as a module. The shim will create a global `Promise` constructor.
4 |
5 | Since it's built on the when.js core, you get [debuggability with long stack traces](api.md#whenmonitorconsole), too! Just load `when/monitor/console` as usual.
6 |
7 | ## Global script
8 |
9 | ```html
10 |