pax_global_header00006660000000000000000000000064131473317520014520gustar00rootroot0000000000000052 comment=599bc2e3868c39110a3841b1830394c68fd78f45 node-when-3.7.8+ds/000077500000000000000000000000001314733175200140255ustar00rootroot00000000000000node-when-3.7.8+ds/.editorconfig000066400000000000000000000000651314733175200165030ustar00rootroot00000000000000root = true [*] indent_style = tab end_of_line = LF node-when-3.7.8+ds/.gitignore000066400000000000000000000001321314733175200160110ustar00rootroot00000000000000.idea/ experiments/ node_modules/ build/when.js dist/ test/browser/*.js bower_components/ node-when-3.7.8+ds/.jshintignore000066400000000000000000000001641314733175200165320ustar00rootroot00000000000000node_modules/ .git/ .idea/ experiments/ test/monitor/ test/browser/ es6-shim/ build/when.js bower_components/ dist/ node-when-3.7.8+ds/.jshintrc000066400000000000000000000007301314733175200156520ustar00rootroot00000000000000{ "browser": true, "node": true, "predef": [ "define", "module", "system" ], "boss": true, "curly": true, "elision": true, "eqnull": true, "expr": true, "globalstrict": false, "laxbreak": true, "newcap": true, "noarg": true, "noempty": true, "nonew": true, "quotmark": "single", "smarttabs": true, "strict": false, "sub": true, "trailing": true, "undef": true, "unused": true, "maxdepth": 3, "maxcomplexity": 5 }node-when-3.7.8+ds/.npmignore000066400000000000000000000001221314733175200160170ustar00rootroot00000000000000test/ benchmark/ experiments/ docs/ build/ *.md .* *~ bower.json bower_components/node-when-3.7.8+ds/.travis.yml000066400000000000000000000005451314733175200161420ustar00rootroot00000000000000language: node_js node_js: - '0.10' - '0.12' - '4' - '5' sudo: false script: npm run ci branches: only: - dev - master addons: apt: sources: - ubuntu-toolchain-r-test packages: - g++-4.8 env: global: - SAUCE_USERNAME="cujojs-when" - SAUCE_ACCESS_KEY="e5d3d1a5-bc49-4607-8a7e-702a512c7f60" - CXX=g++-4.8 node-when-3.7.8+ds/CHANGES.md000066400000000000000000000633711314733175200154310ustar00rootroot00000000000000### 3.7.7 * Fix browserify ### 3.7.6 * Add browser dist version to npm package ### 3.7.5 * Improve unhandled rejection formatting in ie8 ### 3.7.4 * Add `when/keys settle`, for settling a hash of promises. * Use `poly` from npm instead of a git link in package.json. No need for git to be available to npm install when. * Various community-contributed documentation updates. Thanks! ### 3.7.3 * Fix console.log check when using `monitor/console` in IE8. * Fix issues with webpack environment and fake timers. * Several community-contributed doc fixes. Thanks! ### 3.7.2 * Republish 3.7.1 npm package: for some reason, `npm publish` did not include the file `poll.js` when publishing 3.7.1 * No functional changes ### 3.7.1 * Fix `when.settle` unhandled rejection reporting case. ### 3.7.0 * Add [`process` and `window` unhandled rejection events](#docs/debug-api.md) for cross-library debugging tools. * Improve internal task queueing performance and memory usage. * Stabilize handler ordering in the face of multiple promise implementations. ### 3.6.4 * Fix handling of `null` errors in unhandled rejection reporting * Add [examples of supporting both promise and node style callbacks](docs/api.md#support-promises-and-node-style-callback-functions) in the same API ### 3.6.3 * Fix regression in `when/callbacks` introduced in 3.6.1 ### 3.6.2 * Work around [v8 optimizing compiler bug](https://code.google.com/p/v8/issues/detail?id=3692) with some *truly amazing* help from community members. Thank you [@anodynos](https://github.com/anodynos), [@jefflage](https://github.com/jefflage), [@pbarnes](https://github.com/pbarnes), [@spion](https://github.com/spion), [@tsouza](https://github.com/tsouza). * Fix regressions in `when.filter` and `when.reduce` (which also affected `when/sequence`). ### 3.6.1 * Significant improvements to `when.try`, and `when.lift`. * Additional improvements to array functions: `when.reduce`, `when.any`, and `when.some`. * Improved handling of early bail-out cases in `when.all`, `when.map`, and `when.any`. ### 3.6.0 * Significant performance improvements: * 10x or more for `when.map`, especially for large arrays * ~2x for `when.reduce` and `promise.fold` * ~1.5-2x for generators using `when/generator` `lift`, `call`, and/or `apply`. * Memory use reductions for `when.reduce` and `promise.fold`. ### 3.5.2 * Prevent minifiers from clobbering unhandled rejection reporting if they remove `console.*` calls. Unhandled rejections will be reported even when using Uglify `drop_console`. * `when/function.apply` now handles passing an Arguments object directly, e.g. `fn.apply(f, arguments);`. Use with care: v8 will deoptimize any function where you pass `arguments` to another function. ### 3.5.1 * `when.race` & `Promise.race` now reject with a `TypeError` if you pass something that is not iterable. * Improve scheduler compatibility with MutationObserver shims * Simplify checks for vert.x environment ### 3.5.0 * Improve `when.race` & `Promise.race` performance. * Internal changes to start paving the way toward 4.0.0. * Deprecate `when.iterate` and `when.unfold`. Use [cujoJS/most](https://github.com/cujojs/most) for streaming asynchronous values. * Deprecate progress events. See [the docs for more information](docs/api.md#progress-events-are-deprecated) and [tips on refactoring](docs/api.md#refactoring-progress) code that uses promise progress. ### 3.4.6 * Fix webpack compatibility by excluding `vertx` from browser bundles ### 3.4.5 * Fixes for edge cases for unhandled rejection reporting ### 3.4.4 * Workaround for node 0.10.30 setTimeout bug. See [this issue](https://github.com/joyent/node/issues/8167) ### 3.4.3 * Improve error handling for [predicate catch](docs/api.md#promisecatch) * Simplify internals and reduce code size ### 3.4.2 * Fix for rare false negative in [unhandled rejection reporting](docs/api.md#debugging-promises). ### 3.4.1 * Fix for `promise.finally` not waiting on returned promises. ### 3.4.0 * New [`when.filter`](docs/api.md#whenfilter) for filtering arrays of promises. * [`when.map`](docs/api.md#whenmap) and [`when.filter`](docs/api.md#whenfilter) now provide the array index as the second param to their mapping and filtering functions. * [`when/keys.map`](docs/api.md#whenkeys-map) now provides the associated key to its mapping function. * Smaller ES6 shim. ### 3.3.1 * Fix argument ordering bug in `when/node` introduced in 3.3.0. ### 3.3.0 * Promote [`when.race`](docs/api.md#whenrace) to public API. * `when.any` and `when.some` now reject with a `RangeError` if the race is obviously unwinnable, for example: `when.some([1,2,3], 4)`. See the [`when.any`](docs/api.md#whenany) and [`when.some`](docs/api.md#whensome) docs for more info. ### 3.2.3 * Updated [debugging docs](docs/api.md#debugging-promises) * Report when previously unhandled rejections become handled, with an ID to correlate the two messages. * Improve unhandled rejection reporting for cases where multiple different promise implementations interleave. ### 3.2.2 * More mem and perf improvements * Improvements to unhandled rejection reporting ### 3.2.1 * Minor mem and perf tweaks for `when.all` * Defend against `JSON.stringify` exceptions when formatting unhandled rejection output. ### 3.2.0 * Potentially unhandled rejections are now logged to `console.error` by default, even without using `done` or `when/monitor/console`. As before, enabling `when/monitor/console` still adds long async stack traces, and using `done` still makes errors fatal. See [Debugging Promises](docs/api.md#debugging-promises) for more info. * [`promise.timeout`](docs/api.md#promisetimeout) now rejects with a [`TimeoutError`](docs/api.md#timeouterror) by default (unless you specify a custom reason) for better pattern matching with [`promise.catch`](docs/api.md#promisecatch). * Performance improvements across the board, especially to `when.all` (and `Promise.all` in the [ES6-shim](docs/es6-promise-shim.md)) and `node.lift`: lifted functions and lift*ing* are faster now. * New [`promise.fold`](docs/api.md#promisefold) for combining two promises to generate a new promise. * Deprecated: * Using `when/node.lift`, `when/function.lift`, and `when/callbacks.lift` to provide partial arguments * `promise.then`'s 3rd argument, and `when()`'s 4th argument. Use the dedicated [`promise.progress`](docs/api.md#promiseprogress) API to listen to promise progress events. * `when.some`. See https://github.com/cujojs/when/issues/288 * `when/callbacks.promisify` See https://github.com/cujojs/when/issues/318 ### 3.1.0 * Added [optional `reason` param to `promise.timeout`](docs/api.md#promisetimeout) to specify your own timeout value. * Another significant speed bump for `when.all` (and es6-shim `Promise.all`) * More `when/monitor/console` long stack trace improvements. Traces can track nested async functions [even if you forget to return a promise](docs/api.md#whenmonitorconsole). * Clean up bower and npm installs by ignoring more markdown files ### 3.0.1 * [API doc](docs/api.md) updates and fixes * Improvements to unhandled rejection long stack trace filtering * Internal performance improvements ### 3.0.0 * New internal architecture with significant performance improvements and memory efficiency * New APIs * [`when.try`](docs/api.md#whentry), [`when.lift`](docs/api.md#whenlift), [`when.reduceRight`](docs/api.md#whenreduceRight), [`when.iterate`](docs/api.md#wheniterate), [`when.unfold`](docs/api.md#whenunfold), [`when.race`](docs/api.md#whenrace) * [`promise.with`](docs/api.md#promisewith), [`promise.else`](docs/api.md#promiseelse), [`promise.delay`](docs/api.md#promisedelay), [`promise.timeout`](docs/api.md#promisetimeout), [`promise.progress`](docs/api.md#promiseprogress) * New liftAll variants for lifting all of an object's functions in one shot, eg. `var promisedFs = node.liftAll(require('fs'))` * [`fn.liftAll`](docs/api.md#fnliftall), [`node.liftAll`](docs/api.md#nodeliftall), [`callbacks.liftAll`](docs/api.md#callbacksliftall) * `when.Promise` public, inheritance-friendly, Promise constructor * New [ES6 Promise shim](docs/es6-promise-shim.md) * Check out the [tips for upgrading to 3.0 from 2.x](docs/api.md#upgrading-to-30-from-2x) ### 2.8.0 * Experimental [ES6 generator support](docs/api.md#es6-generators) via new `when/generator` module, with `lift`, `call`, `apply`. ### 2.7.1 * Internal changes to reduce overall memory usage, along with minor performance improvements. ### 2.7.0 * Added [`promise.catch`](docs/api.md#catch) and [`promise.finally`](docs/api.md#finally) as synonyms for `promise.otherwise` and `promise.ensure`. (#212) * New [browserify build](../README.md#legacy-environments-via-browserify) for those using globals. (#209) * Added [ender](http://ender.jit.su) support to `package.json`. (#223) * Fix compatibility with [PhantomJS](http://phantomjs.org)'s CommonJS module support. (#226) * Fix [Sauce Labs](https://saucelabs.com) tests for pull requests. (#216) * Added `bower.json` `ignore` to trim files installed via bower. (#193) ### 2.6.0 * New [`promise.done`](docs/api.md#done) allows consuming the ultimate value at the end of a promise chain while ensuring that any errors are thrown to the host environment so you get loud stack traces. * `when/node/function` [`bindCallback`](docs/api.md#nodefn-bindcallback) and [`liftCallback`](docs/api.md#nodefn-liftcallback) now behave more like standard node-style APIs in that they allow exceptions to propagate to the host environment for loud stack traces. ### 2.5.1 * `ensure` now ignores non-functions, [like `then` does](http://promisesaplus.com/#point-25), for consistency. (#207) ### 2.5.0 * [Promises/A+ 1.1](http://promisesaplus.com) compliant. Passes version 2.0.0 of the [Promises/A+ test suite](https://github.com/promises-aplus/promises-tests). ### 2.4.1 * New `MutationObserver` scheduler further reduces "time-to-first-handler" in modern browsers. (#198) * Also, this works around a horrible IE10 bug (desktop and mobile) that renders `setImmediate`, `MessageChannel`, and `postMessage` unusable as fast task schedulers. Many thanks to @plaa and @calvinmetcalf for their help in discovering the problem and working out a solution. (#197) ### 2.4.0 * Experimental support for [vert.x 2.x](http://vertx.io). Should now run in vert.x >= 1.1.0. * New `when.isPromiseLike` as the more accurately-named synonym for `when.isPromise`. * **DEPRECATED**: `when.isPromise`. It can only tell you that something is "promise-like" (aka "thenable") anyway. Use the new, more accurately-named `when.isPromiseLike` instead. * Fix for promise monitor reporting extra unhandled rejections for `when.all` and `when.map`. ### 2.3.0 * New [`promise.tap`](docs/api.md#tap) for adding side effects to a promise chain. * New `MessageChannel` scheduler reduces "time-to-first" handler, in environments that support it. * Performance optimizations for promise resolution. * Internal architecture improvements to pave the way for when.js 3.0.0. ### 2.2.1 * Fix for `when.defer().reject()` bypassing the unhandled rejection monitor. (#166) * Fix for `when/function`, `when/callbacks`, and `when/node/function` not preserving `thisArg`. (#162) * Doc clarifications for [`promise.yield`](docs/api.md#yield). (#164) ### 2.2.0 * New experimental [promise monitoring and debugging](docs.md#debugging-promises) via `when/monitor/console`. * New [`when.promise(resolver)`](docs/api.md#whenpromise) promise creation API. A lighter alternative to the heavier `when.defer()` * New `bindCallback` and `liftCallback` in `when/node/function` for more integration options with node-style callbacks. ### 2.1.1 * Quote internal usages of `promise.yield` to workaround .NET minifier tools that don't yet understand ES5 identifier-as-property rules. See [#157](https://github.com/cujojs/when/issues/157) ### 2.1.0 * New [`when.settle`](docs/api.md#whensettle) that settles an array of promises, regardless of whether the fulfill or reject. * New [`when/guard`](docs/api.md#whenguard) generalized concurrency guarding and limiting * New [`promise.inspect`](docs/api.md#inspect) for synchronously getting a snapshot of a promise's state at a particular instant. * Significant performance improvements when resolving promises with non-primitives (Arrays, Objects, etc.) * Experimental [vert.x](http://vertx.io) support * **DEPRECATED**: `onFulfilled`, `onRejected`, `onProgress` handler arguments to `when.all`, `when.any`, `when.some`. Use the returned promise's `then()` (or `otherwise()`, `ensure()`, etc) to register handlers instead. * For example, do this: `when.all(array).then(onFulfilled, onRejected)` instead of this: `when.all(array, onFulfilled, onRejected)`. The functionality is equivalent. ### 2.0.1 * Account for the fact that Mocha creates a global named `process`. Thanks [Narsul](https://github.com/cujojs/when/pull/136) ### 2.0.0 * Fully asynchronous resolutions. * [Promises/A+](http://promises-aplus.github.com/promises-spec) compliance. * New [`when/keys`](docs/api.md#object-keys) module with `all()` and `map()` for object keys/values. * New [`promise.ensure`](docs/api.md#ensure) as a better, and safer, replacement for `promise.always`. [See discussion](https://github.com/cujojs/when/issues/103) as to why `promise.always` is mistake-prone. * **DEPRECATED:** `promise.always` * `lift()` is now the preferred name for what was `bind()` in [when/function](docs/api.md#synchronous-functions), [when/node/function](docs/api.md#node-style-asynchronous-functions), and [when/callbacks](docs/api.md#asynchronous-functions). * **DEPRECATED:** `bind()` in `when/function`, `when/node/function`, and `when/callbacks`. Use `lift()` instead. ### 1.8.1 * Last 1.x.x release before 2.0.0 barring critical fixes. * To prepare for 2.0.0, [test your code against the dev-200 branch](https://github.com/cujojs/when/tree/dev-200). It is fully API compatible, but has fully asynchronous resolutions. * Performance improvements for [when/function](docs/api.md#synchronous-functions). * [Documentation](docs/api.md) updates and fixes. Thanks, [@unscriptable](https://github.com/unscriptable)! * **DEPRECATED:** `deferred.progress` and `deferred.resolver.progress`. Use [`deferred.notify`](docs/api.md#progress-events) and [`deferred.resolver.notify`](docs/api.md#progress-events) instead. * **DEPRECATED:** [`when.chain`](docs/api.md#whenchain). Use [`resolver.resolve(promise)`](docs/api.md#resolver) or `resolver.resolve(promise.yield)` ([see `promise.yield`](docs/api.md#yield)) instead. * **DEPRECATED:** `when/timed` module. Use [`when/delay`](docs/api.md#whendelay) and [`when/timeout`](docs/api.md#whentimeout) modules instead. ### 1.8.0 * New [when/function](docs/api.md#synchronous-functions), [when/node/function](docs/api.md#node-style-asynchronous-functions), and [when/callbacks](docs/api.md#asynchronous-functions) with functional programming goodness, and adapters for turning callback-based APIs into promise-based APIs. Kudos [@riccieri](https://github.com/riccieri)! * New [when/unfold](docs/api.md#whenunfold), and [when/unfold/list](docs/api.md#whenunfoldlist) promise-aware anamorphic unfolds that can be used to generate and/or process unbounded lists. * New [when/poll](docs/api.md#whenpoll) promise-based periodic polling and task execution. Kudos [@scothis](https://github.com/scothis)! ### 1.7.1 * Removed leftover internal usages of `deferred.then`. * [when/debug](https://github.com/cujojs/when/wiki/when-debug) allows configuring the set of "fatal" error types that will be rethrown to the host env. ### 1.7.0 * **DEPRECATED:** `deferred.then` [is deprecated](docs/api.md#deferred) and will be removed in an upcoming release. Use `deferred.promise.then` instead. * [promise.yield](docs/api.md#yield)(promiseOrValue) convenience API for substituting a new value into a promise chain. * [promise.spread](docs/api.md#spread)(variadicFunction) convenience API for spreading an array onto a fulfill handler that accepts variadic arguments. [Mmmm, buttery](http://s.shld.net/is/image/Sears/033W048977110001_20100422100331516?hei=1600&wid=1600&op_sharpen=1&resMode=sharp&op_usm=0.9,0.5,0,0) * Doc improvements: * [when()](docs/api.md#when) and [promise.then()](docs/api.md#main-promise-api) have more info about callbacks and chaining behavior. * More info and clarifications about the roles of [Deferred](docs/api.md#deferred) and [Resolver](docs/api.md#resolver) * Several minor clarifications for various APIs * Internal improvements to assimilation and interoperability with other promise implementations. ### 1.6.1 * Fix for accidental coercion of non-promises. See [#62](https://github.com/cujojs/when/issues/60). ### 1.6.0 * New [when.join](docs/api.md#whenjoin) - Joins 2 or more promises together into a single promise. * [when.some](docs/api.md#whensome) and [when.any](docs/api.md#whenany) now act like competitive races, and have generally more useful behavior. [Read the discussion in #60](https://github.com/cujojs/when/issues/60). * *Experimental* progress event propagation. Progress events will propagate through promise chains. [Read the details here](docs/api.md#progress-events). * *Temporarily* removed calls to `Object.freeze`. Promises are no longer frozen due to a horrendous v8 performance penalty. [Read discussion here](https://groups.google.com/d/topic/cujojs/w_olYqorbsY/discussion). * **IMPORTANT:** Continue to treat promises as if they are frozen, since `freeze()` will be reintroduced once v8 performance improves. * [when/debug](https://github.com/cujojs/when/wiki/when-debug) now allows setting global a debugging callback for rejected promises. ### 1.5.2 * Integrate @domenic's [Promises/A Test Suite](https://github.com/domenic/promise-tests). Runs via `npm test`. * No functional change ### 1.5.1 * Performance optimization for [when.defer](docs/api.md#whendefer), up to 1.5x in some cases. * [when/debug](docs/api.md#whendebug) can now log exceptions and rejections in deeper promise chains, in some cases, even when the promises involved aren't when.js promises. ### 1.5.0 * New task execution and concurrency management: [when/sequence](docs/api.md#whensequence), [when/pipeline](docs/api.md#whenpipeline), and [when/parallel](docs/api.md#whenparallel). * Performance optimizations for [when.all](docs/api.md#whenall) and [when.map](docs/api.md#whenmap), up to 2x in some cases. * Options for disabling [paranoid mode](docs/api.md#paranoid-mode) that provides a significant performance gain in v8 (e.g. Node and Chrome). See this [v8 performance problem with Object.freeze](http://stackoverflow.com/questions/8435080/any-performance-benefit-to-locking-down-javascript-objects) for more info. * **Important:** `deferred` and `deferred.resolver` no longer throw when resolved/rejected multiple times. They will return silently as if the they had succeeded. This prevents parties to whom *only* the `resolver` has been given from using `try/catch` to determine the state of the associated promise. * For debugging, you can use the [when/debug](https://github.com/cujojs/when/wiki/when-debug) module, which will still throw when a deferred is resolved/rejected multiple times. ### 1.4.4 * Change UMD boilerplate to check for `exports` to avoid a problem with QUnit. See [#54](https://github.com/cujojs/when/issues/54) for more info. ### 1.4.3 * Fix for infinite promise coercion between when.js and Q (See [#50](https://github.com/cujojs/when/issues/50)). Thanks [@kriskowal](https://github.com/kriskowal) and [@domenic](https://github.com/domenic) ### 1.4.2 * Fix for IE8 infinite recursion (See [#49](https://github.com/cujojs/when/issues/49)) ### 1.4.1 * Code and unit test cleanup and streamlining--no functional changes. ### 1.4.0 * Create a resolved promise: `when.resolve(value)` creates a resolved promise for `value`. See [API docs](docs/api.md#whenresolve). * Resolve/reject return something useful: `deferred.resolve` and `deferred.reject` now return a promise for the fulfilled or rejected value. * Resolve a deferred with another promise: `deferred.resolve(promise)` - when `promise` resolves or rejects, so will `deferred`. ### 1.3.0 * Fixed a deviation from the Promises/A spec where returning undefined from a callback or errback would cause the previous value to be forwarded. See [#31](https://github.com/cujojs/when/issues/31) * *This could be a breaking change* if you depended on this behavior. If you encounter problems, the solution is to ensure that your promise callbacks (registered either with `when()` or `.then()`) return what you intend, keeping in mind that not returning something is equivalent to returning `undefined`. * This change also restores compatibility with the promises returned by `jQuery.get()`, which seem to reject with themselves as the rejection value. See [issue #41](https://github.com/cujojs/when/issues/43) for more information and discussion. Thanks to [@KidkArolis](https://github.com/KidkArolis) for raising the issue. ### 1.2.0 * `promise.otherwise(errback)` as a shortcut for `promise.then(null, errback)`. See discussion [here](https://github.com/cujojs/when/issues/13) and [here](https://github.com/cujojs/when/issues/29). Thanks to [@jonnyreeves](https://github.com/jonnyreeves/) for suggesting the name "otherwise". * [when/debug](https://github.com/cujojs/when/wiki/when-debug) now detects exceptions that typically represent coding errors, such as SyntaxError, ReferenceError, etc. and propagates them to the host environment. In other words, you'll get a very loud stack trace. ### 1.1.1 * Updated [wiki](https://github.com/cujojs/when/wiki) map/reduce examples, and added simple promise forwarding example * Fix for calling `when.any()` without a callback ([#33](https://github.com/cujojs/when/issues/33)) * Fix version number in `when.js` source ([#36](https://github.com/cujojs/when/issues/36)) ### 1.1.0 * `when.all/any/some/map/reduce` can all now accept a promise for an array in addition to an actual array as input. This allows composing functions to do interesting things like `when.reduce(when.map(...))` * `when.reject(promiseOrValue)` that returns a new, rejected promise. * `promise.always(callback)` as a shortcut for `promise.then(callback, callback)` * **Highly experimental** [when/debug](https://github.com/cujojs/when/wiki/when-debug) module: a drop-in replacement for the main `when` module that enables debug logging for promises created or consumed by when.js ### 1.0.4 * [Travis CI](http://travis-ci.org/cujojs/when) integration * Fix for cancelable deferred not invoking progress callbacks. ([#24](https://github.com/cujojs/when/pull/24) Thanks [@scothis](https://github.com/scothis)) * The promise returned by `when.chain` now rejects when the input promise rejects. ### 1.0.3 * Fix for specific situation where `null` could incorrectly be used as a promise resolution value ([#23](https://github.com/cujojs/when/pull/23)) ### 1.0.2 * Updated README for running unit tests in both Node and Browsers. See **Running the Unit Tests** below. * Set package name to 'when' in package.json ### 1.0.1 * Fix for rejections propagating in some cases when they shouldn't have been ([#19](https://github.com/cujojs/when/issues/19)) * Using [buster.js](http://busterjs.org/) for unit tests now. ### 1.0.0 * First official when.js release as a part of [cujojs](https://github.com/cujojs). * Added [when/cancelable](https://github.com/cujojs/when/wiki/when-cancelable) decorator for creating cancelable deferreds * Added [when/delay](https://github.com/cujojs/when/wiki/when-delay) and [when/timeout](https://github.com/cujojs/when/wiki/when-timeout) helpers for creating delayed promises and promises that timeout and reject if not resolved first. ### 0.11.1 * Added [when/apply](https://github.com/cujojs/when/wiki/when-apply) helper module for using arguments-based and variadic callbacks with `when.all`, `when.some`, `when.map`, or any promise that resolves to an array. ([#14](https://github.com/cujojs/when/issues/14)) * `.then()`, `when()`, and all other methods that accept callback/errback/progress handlers will throw if you pass something that's not a function. ([#15](https://github.com/cujojs/when/issues/15)) ### 0.11.0 * `when.js` now *assimilates* thenables that pass the [Promises/A duck-type test](http://wiki.commonjs.org/wiki/Promises/A), but which may not be fully Promises/A compliant, such as [jQuery's Deferred](http://api.jquery.com/category/deferred-object/) and [curl's global API](https://github.com/cujojs/curl) (See the **API at a glance** section) * `when()`, and `when.all/some/any/map/reduce/chain()` are all now guaranteed to return a fully Promises/A compliant promise, even when their input is not compliant. * Any non-compliant thenable returned by a callback or errback will also be assimilated to protect subsequent promises and callbacks in a promise chain, and preserve Promises/A forwarding guarantees. ### 0.10.4 * **Important Fix for some AMD build/optimizer tools**: Switching back to more verbose, builder-friendly boilerplate * If you are using when.js 0.10.3 with the dojo or RequireJS build tools, you should update to v.10.4 as soon as possible. ### 0.10.3 **Warning**: This version will not work with most AMD build tools. You should update to 0.10.4 as soon as possible. * Minor `package.json` updates * Slightly smaller module boilerplate ### 0.10.2 * Performance optimizations for `when.map()` (thanks @[smitranic](https://github.com/smitranic)), especially for large arrays where the `mapFunc` is also async (i.e. returns a promise) * `when.all/some/any/map/reduce` handle sparse arrays (thanks @[rwaldrn](https://github.com/rwldrn/)) * Other minor performance optimizations ### 0.10.1 * Minor tweaks (thanks @[johan](https://github.com/johan)) * Add missing semis that WebStorm didn't catch * Fix DOH submodule ref, and update README with info for running unit tests ### 0.10.0 * `when.map` and `when.reduce` - just like Array.map and Array.reduce, but they operate on promises and arrays of promises * Lots of internal size and performance optimizations * Still only 1k! ### 0.9.4 * Important fix for break in promise chains node-when-3.7.8+ds/CONTRIBUTING.md000066400000000000000000000027221314733175200162610ustar00rootroot00000000000000# Contributing 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. Opening Issues -------------- 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. Pull Requests ------------- 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: - Good clean commit messages. [This guide](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) should help. - A thorough description of what your code does in the description field - Tests written for any features that have been added. Running the Tests ----------------- #### Node 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. 1. `npm install` 2. `npm test` #### Browsers 1. `npm install` 2. `npm run browser-test` 3. Point browsers at , e.g. `http://localhost:8080/` node-when-3.7.8+ds/LICENSE.txt000066400000000000000000000022031314733175200156450ustar00rootroot00000000000000Open Source Initiative OSI - The MIT License http://www.opensource.org/licenses/mit-license.php Copyright (c) 2011 Brian Cavalier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.node-when-3.7.8+ds/README.md000066400000000000000000000071061314733175200153100ustar00rootroot00000000000000Promises/A+ logo [![Build Status](https://travis-ci.org/cujojs/when.svg?branch=master)](https://travis-ci.org/cujojs/when) [![Inline docs](http://inch-ci.org/github/cujojs/when.svg?branch=master)](http://inch-ci.org/github/cujojs/when) when.js ======= 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: * Resolve arrays and hashes of promises, as well as infinite promise sequences * Execute tasks in parallel or sequentially * Transform Node-style and other callback-based APIs into promise-based APIs When.js is one of the many stand-alone components of [cujoJS](http://cujojs.com), the JavaScript Architectural Toolkit. Check it out: - [What's new](CHANGES.md) - [API docs](docs/api.md#api) - Read more about how [promises simplify async programming](http://know.cujojs.com/tutorials/async/simplifying-async-with-promises) Installation ------------ #### AMD Available as `when` through [bower](http://bower.io), or just clone the repo and load `when.js` from the root. ``` bower install --save when ``` #### CommonJS/Node ``` npm install --save when ``` [More help & other environments »](docs/installation.md) Usage ----- 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). 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. ```js var rest = require('rest'); fetchRemoteGreeting() .then(addExclamation) .catch(handleError) .done(function(greeting) { console.log(greeting); }); function fetchRemoteGreeting() { // returns a when.js promise for 'hello world' return rest('http://example.com/greeting'); } function addExclamation(greeting) { return greeting + '!!!!' } function handleError(e) { return 'drat!'; } ``` 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. ```js var when = require('when'); var rest = require('rest'); when.reduce(when.map(getRemoteNumberList(), times10), sum) .done(function(result) { console.log(result); }); function getRemoteNumberList() { // Get a remote array [1, 2, 3, 4, 5] return rest('http://example.com/numbers').then(JSON.parse); } function sum(x, y) { return x + y; } function times10(x) {return x * 10; } ``` License ------- Licensed under MIT. [Full license here »](LICENSE.txt) Contributing ------------ Please see the [contributing guide](CONTRIBUTING.md) for more information on running tests, opening issues, and contributing code to the project. References ---------- 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). node-when-3.7.8+ds/benchmark/000077500000000000000000000000001314733175200157575ustar00rootroot00000000000000node-when-3.7.8+ds/benchmark/index.html000066400000000000000000000010341314733175200177520ustar00rootroot00000000000000 node-when-3.7.8+ds/benchmark/map.js000066400000000000000000000015111314733175200170700ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function(require) { var when, tests, run; when = require('../when'); run = require('./run'); tests = [ { name: 'map 100', fn: map(100), defer: true }, { name: 'map 1k', fn: map(1e3), defer: true } ]; run(tests); // // Benchmark tests // function map(n) { return function(deferred) { var input = []; for(var i = 0; i < n; i++) { input.push(when(i)); } when.map(input, addOne).then(function() { deferred.resolve(); }); }; } // // Promise helpers // function addOne(x) { return x + 1; } }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/benchmark/promise.js000066400000000000000000000106341314733175200177770ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function(require) { /*global setImmediate,process*/ var Promise, tests, run, ok; Promise = require('../lib/Promise'); run = require('./run'); ok = 0; tests = [ { name: 'pending', fn: createPending }, { name: 'resolved', fn: createResolved }, { name: 'rejected', fn: createRejected }, { name: 'never', fn: createNever }, { name: 'resolve', fn: resolvePromise, defer: true }, { name: 'reject', fn: rejectPromise, defer: true }, { name: 'setImmediate', fn: viaSetImmediate, defer: true, condition: checkSetImmediate }, { name: 'process.nextTick', fn: viaProcessNextTick, defer: true, condition: checkProcessNextTick }, { name: 'setTimeout', fn: viaSetTimeout, defer: true }, { name: 'reject then resolve', fn: rejectThenResolve, defer: true }, { name: 'resolve chain 100', fn: resolveChain(100), defer: true }, { name: 'resolve chain 1k', fn: resolveChain(1e3), defer: true }, { name: 'sparse resolve chain 1k', fn: resolveChainSparse(1e3), defer: true }, { name: 'reject chain 100', fn: rejectChain(100), defer: true }, { name: 'reject chain 1k', fn: rejectChain(1e3), defer: true }, { name: 'sparse reject chain 1k', fn: rejectChainSparse(1e3), defer: true }, // These 10k tests seem to cause significant garbage collection // hits that skew results of other tests. So, they are disabled // for now, but we need to figure out how to reduce the memory // thrashing these cause. // Leaving one enabled for now. { name: 'resolve chain 10k', fn: resolveChain(1e4), defer: true } // { name: 'sparse resolve chain 10k', fn: resolveChainSparse(1e4), defer: true }, // { name: 'reject chain 10k', fn: rejectChain(1e4), defer: true }, // { name: 'sparse reject chain 10k', fn: rejectChainSparse(1e4), defer: true } ]; run(tests); // // Benchmark tests // function createPending() { /*jshint nonew:false*/ new Promise(pendingForever); } function createResolved() { Promise.resolve(); } function createRejected() { Promise.reject(); } function createNever() { Promise.never(); } function resolvePromise(deferred) { /*jshint nonew:false*/ new Promise(resolve).then(function() { deferred.resolve(); }); } function rejectPromise(deferred) { /*jshint nonew:false*/ new Promise(reject).then(null, function() { deferred.resolve(); }); } function rejectThenResolve(deferred) { /*jshint nonew:false*/ new Promise(reject).then(null, identity).then(function() { deferred.resolve(); }); } function viaSetTimeout(deferred) { setTimeout(function() { deferred.resolve(); }, 0); } function viaSetImmediate(deferred) { setImmediate(function() { deferred.resolve(); }); } function viaProcessNextTick(deferred) { process.nextTick(function() { deferred.resolve(); }); } function resolveChain(n) { return function(deferred) { var p = Promise.resolve({}), i = 0; for(;i < n; i++) { p = p.then(identity); } p.then(function() { deferred.resolve(); }); }; } function resolveChainSparse(n) { return function(deferred) { var p = Promise.resolve({}), i = 1; for(;i < n; i++) { p = p.then(null); } p.then(identity).then(function() { deferred.resolve(); }); }; } function rejectChain(n) { return function(deferred) { var p = Promise.reject({}), i = 0; for(;i < n; i++) { p = p.then(null, rethrow); } p.then(null, function() { deferred.resolve(); }); }; } function rejectChainSparse(n) { return function(deferred) { var p = Promise.reject({}), i = 1; for(;i < n; i++) { p = p.then(null, rethrow); } p.then(null, identity).then(function() { deferred.resolve(); }); }; } // // Promise helpers // function pendingForever() {} function resolve(r) { r(); } function reject(_, r) { r(); } function identity(x) { return x; } function rethrow(e) { throw e; } function checkSetImmediate() { return typeof setImmediate === 'function' ? ok : 'setImmediate() not available'; } function checkProcessNextTick() { return typeof process !== 'undefined' && typeof process.nextTick === 'function' ? ok : 'process.nextTick() not available'; } }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/benchmark/run.js000066400000000000000000000035471314733175200171320ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function(require) { var Benchmark, log, err; Benchmark = require('benchmark'); log = console.log.bind(console); err = console.error.bind(console); // // Simple multi-benchmark runner // return function run(tests) { var skipped = []; tests.reduce(function (suite, test) { var skip = shouldSkip(test); if(skip) { skipped.push(pad(test.name, 24) + ' ' + skip); return suite; } test.onError = err; test.onComplete = function (event) { var result, t; t = event.currentTarget; result = pad(t.name, 24) + pad(t.hz.toFixed(2) + ' op/s', 18) + pad((1000 * t.stats.mean).toFixed(2), 8) + ' ms/op \xb1 ' + t.stats.rme.toFixed(2) + '%'; log(result); }; return suite.add(test); }, new Benchmark.Suite()) .on('start', function() { log('Platform:', Benchmark.platform.description || 'unknown'); if(skipped.length) { log('------------------------------------------------'); log('Skipping ' + count(skipped.length, 'benchmark')); log(skipped.join('\n')); } log('------------------------------------------------'); log('Running ' + count(this.length, 'benchmark')); }) .on('complete', function () { log('------------------------------------------------'); }).run(); }; function shouldSkip(test) { return typeof test.condition === 'function' && test.condition(); } function pad(str, len) { var result = str; while (result.length < len) { result = ' ' + result; } return result; } function count(n, s) { return '' + n + ' ' + (n === 1 ? s : (s + 's')); } }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/bower.json000066400000000000000000000011231314733175200160330ustar00rootroot00000000000000{ "name": "when", "main": "when.js", "moduleType": ["amd", "node"], "description": "A lightweight Promises/A+ and when() implementation, plus other async goodies.", "keywords": ["Promises/A+", "promises-aplus", "promise", "promises", "deferred", "deferreds", "when", "async", "asynchronous", "cujo"], "homepage": "https://github.com/cujojs/when", "authors": [ "Brian Cavalier " ], "license": "MIT", "ignore": [ "**/.*", "**/*.md", "docs", "benchmark", "node_modules", "bower_components", "test", "build" ] } node-when-3.7.8+ds/build/000077500000000000000000000000001314733175200151245ustar00rootroot00000000000000node-when-3.7.8+ds/build/when.browserify-debug.js000066400000000000000000000001221314733175200216740ustar00rootroot00000000000000require('../monitor/console'); module.exports = require('./when.browserify.js'); node-when-3.7.8+ds/build/when.browserify.js000066400000000000000000000007711314733175200206220ustar00rootroot00000000000000var when = module.exports = require('../when'); when.callbacks = require('../callbacks'); when.cancelable = require('../cancelable'); when.delay = require('../delay'); when.fn = require('../function'); when.guard = require('../guard'); when.keys = require('../keys'); when.nodefn = when.node = require('../node'); when.parallel = require('../parallel'); when.pipeline = require('../pipeline'); when.poll = require('../poll'); when.sequence = require('../sequence'); when.timeout = require('../timeout'); node-when-3.7.8+ds/callbacks.js000066400000000000000000000203311314733175200163010ustar00rootroot00000000000000/** @license MIT License (c) copyright 2013-2014 original author or authors */ /** * Collection of helper functions for interacting with 'traditional', * callback-taking functions using a promise interface. * * @author Renato Zannon * @contributor Brian Cavalier */ (function(define) { define(function(require) { var when = require('./when'); var Promise = when.Promise; var _liftAll = require('./lib/liftAll'); var slice = Array.prototype.slice; var makeApply = require('./lib/apply'); var _apply = makeApply(Promise, dispatch); return { lift: lift, liftAll: liftAll, apply: apply, call: call, promisify: promisify }; /** * Takes a `traditional` callback-taking function and returns a promise for its * result, accepting an optional array of arguments (that might be values or * promises). It assumes that the function takes its callback and errback as * the last two arguments. The resolution of the promise depends on whether the * function will call its callback or its errback. * * @example * var domIsLoaded = callbacks.apply($); * domIsLoaded.then(function() { * doMyDomStuff(); * }); * * @example * function existingAjaxyFunction(url, callback, errback) { * // Complex logic you'd rather not change * } * * var promise = callbacks.apply(existingAjaxyFunction, ["/movies.json"]); * * promise.then(function(movies) { * // Work with movies * }, function(reason) { * // Handle error * }); * * @param {function} asyncFunction function to be called * @param {Array} [extraAsyncArgs] array of arguments to asyncFunction * @returns {Promise} promise for the callback value of asyncFunction */ function apply(asyncFunction, extraAsyncArgs) { return _apply(asyncFunction, this, extraAsyncArgs || []); } /** * Apply helper that allows specifying thisArg * @private */ function dispatch(f, thisArg, args, h) { args.push(alwaysUnary(h.resolve, h), alwaysUnary(h.reject, h)); tryCatchResolve(f, thisArg, args, h); } function tryCatchResolve(f, thisArg, args, resolver) { try { f.apply(thisArg, args); } catch(e) { resolver.reject(e); } } /** * Works as `callbacks.apply` does, with the difference that the arguments to * the function are passed individually, instead of as an array. * * @example * function sumInFiveSeconds(a, b, callback) { * setTimeout(function() { * callback(a + b); * }, 5000); * } * * var sumPromise = callbacks.call(sumInFiveSeconds, 5, 10); * * // Logs '15' 5 seconds later * sumPromise.then(console.log); * * @param {function} asyncFunction function to be called * @param {...*} args arguments that will be forwarded to the function * @returns {Promise} promise for the callback value of asyncFunction */ function call(asyncFunction/*, arg1, arg2...*/) { return _apply(asyncFunction, this, slice.call(arguments, 1)); } /** * Takes a 'traditional' callback/errback-taking function and returns a function * that returns a promise instead. The resolution/rejection of the promise * depends on whether the original function will call its callback or its * errback. * * If additional arguments are passed to the `lift` call, they will be prepended * on the calls to the original function, much like `Function.prototype.bind`. * * The resulting function is also "promise-aware", in the sense that, if given * promises as arguments, it will wait for their resolution before executing. * * @example * function traditionalAjax(method, url, callback, errback) { * var xhr = new XMLHttpRequest(); * xhr.open(method, url); * * xhr.onload = callback; * xhr.onerror = errback; * * xhr.send(); * } * * var promiseAjax = callbacks.lift(traditionalAjax); * promiseAjax("GET", "/movies.json").then(console.log, console.error); * * var promiseAjaxGet = callbacks.lift(traditionalAjax, "GET"); * promiseAjaxGet("/movies.json").then(console.log, console.error); * * @param {Function} f traditional async function to be decorated * @param {...*} [args] arguments to be prepended for the new function @deprecated * @returns {Function} a promise-returning function */ function lift(f/*, args...*/) { var args = arguments.length > 1 ? slice.call(arguments, 1) : []; return function() { return _apply(f, this, args.concat(slice.call(arguments))); }; } /** * Lift all the functions/methods on src * @param {object|function} src source whose functions will be lifted * @param {function?} combine optional function for customizing the lifting * process. It is passed dst, the lifted function, and the property name of * the original function on src. * @param {(object|function)?} dst option destination host onto which to place lifted * functions. If not provided, liftAll returns a new object. * @returns {*} If dst is provided, returns dst with lifted functions as * properties. If dst not provided, returns a new object with lifted functions. */ function liftAll(src, combine, dst) { return _liftAll(lift, combine, dst, src); } /** * `promisify` is a version of `lift` that allows fine-grained control over the * arguments that passed to the underlying function. It is intended to handle * functions that don't follow the common callback and errback positions. * * The control is done by passing an object whose 'callback' and/or 'errback' * keys, whose values are the corresponding 0-based indexes of the arguments on * the function. Negative values are interpreted as being relative to the end * of the arguments array. * * If arguments are given on the call to the 'promisified' function, they are * intermingled with the callback and errback. If a promise is given among them, * the execution of the function will only occur after its resolution. * * @example * var delay = callbacks.promisify(setTimeout, { * callback: 0 * }); * * delay(100).then(function() { * console.log("This happens 100ms afterwards"); * }); * * @example * function callbackAsLast(errback, followsStandards, callback) { * if(followsStandards) { * callback("well done!"); * } else { * errback("some programmers just want to watch the world burn"); * } * } * * var promisified = callbacks.promisify(callbackAsLast, { * callback: -1, * errback: 0, * }); * * promisified(true).then(console.log, console.error); * promisified(false).then(console.log, console.error); * * @param {Function} asyncFunction traditional function to be decorated * @param {object} positions * @param {number} [positions.callback] index at which asyncFunction expects to * receive a success callback * @param {number} [positions.errback] index at which asyncFunction expects to * receive an error callback * @returns {function} promisified function that accepts * * @deprecated */ function promisify(asyncFunction, positions) { return function() { var thisArg = this; return Promise.all(arguments).then(function(args) { var p = Promise._defer(); var callbackPos, errbackPos; if(typeof positions.callback === 'number') { callbackPos = normalizePosition(args, positions.callback); } if(typeof positions.errback === 'number') { errbackPos = normalizePosition(args, positions.errback); } if(errbackPos < callbackPos) { insertCallback(args, errbackPos, p._handler.reject, p._handler); insertCallback(args, callbackPos, p._handler.resolve, p._handler); } else { insertCallback(args, callbackPos, p._handler.resolve, p._handler); insertCallback(args, errbackPos, p._handler.reject, p._handler); } asyncFunction.apply(thisArg, args); return p; }); }; } function normalizePosition(args, pos) { return pos < 0 ? (args.length + pos + 2) : pos; } function insertCallback(args, pos, callback, thisArg) { if(typeof pos === 'number') { args.splice(pos, 0, alwaysUnary(callback, thisArg)); } } function alwaysUnary(fn, thisArg) { return function() { if (arguments.length > 1) { fn.call(thisArg, slice.call(arguments)); } else { fn.apply(thisArg, arguments); } }; } }); })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); node-when-3.7.8+ds/cancelable.js000066400000000000000000000031771314733175200164440ustar00rootroot00000000000000/** @license MIT License (c) copyright B Cavalier & J Hann */ /** * cancelable.js * @deprecated * * Decorator that makes a deferred "cancelable". It adds a cancel() method that * will call a special cancel handler function and then reject the deferred. The * cancel handler can be used to do resource cleanup, or anything else that should * be done before any other rejection handlers are executed. * * Usage: * * var cancelableDeferred = cancelable(when.defer(), myCancelHandler); * * @author brian@hovercraftstudios.com */ (function(define) { define(function() { /** * Makes deferred cancelable, adding a cancel() method. * @deprecated * * @param deferred {Deferred} the {@link Deferred} to make cancelable * @param canceler {Function} cancel handler function to execute when this deferred * is canceled. This is guaranteed to run before all other rejection handlers. * The canceler will NOT be executed if the deferred is rejected in the standard * way, i.e. deferred.reject(). It ONLY executes if the deferred is canceled, * i.e. deferred.cancel() * * @returns deferred, with an added cancel() method. */ return function(deferred, canceler) { // Add a cancel method to the deferred to reject the delegate // with the special canceled indicator. deferred.cancel = function() { try { deferred.reject(canceler(deferred)); } catch(e) { deferred.reject(e); } return deferred.promise; }; return deferred; }; }); })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(); }); node-when-3.7.8+ds/delay.js000066400000000000000000000010601314733175200154560ustar00rootroot00000000000000/** @license MIT License (c) copyright 2011-2013 original author or authors */ /** * delay.js * * Helper that returns a promise that resolves after a delay. * * @author Brian Cavalier * @author John Hann */ (function(define) { define(function(require) { var when = require('./when'); /** * @deprecated Use when(value).delay(ms) */ return function delay(msec, value) { return when(value).delay(msec); }; }); })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); node-when-3.7.8+ds/docs/000077500000000000000000000000001314733175200147555ustar00rootroot00000000000000node-when-3.7.8+ds/docs/api.md000066400000000000000000002465271314733175200160700ustar00rootroot00000000000000API === 1. Core * [when(x)](#when) * [when(x, f)](#when) * [when.try(f, ...args)](#whentry) * [when.lift(f)](#whenlift) * [when.join(...promises)](#whenjoin) * [when.promise(resolver)](#whenpromise) * [when.resolve(x)](#whenresolve) * [when.reject(error)](#whenreject) * [when.defer()](#whendefer) * [when.isPromiseLike(x)](#whenispromiselike) 1. Promise * [promise.done(handleResult, handleError)](#promisedone) * [promise.then(onFulfilled)](#promisethen) * [promise.spread(onFulfilledArray)](#promisespread) * [promise.fold(combine, promise2)](#promisefold) * [promise.catch(onRejected)](#promisecatch) * [promise.finally(cleanup)](#promisefinally) * [promise.yield(x)](#promiseyield) * [promise.else(x)](#promiseelse) * [promise.tap(onFulfilledSideEffect)](#promisetap) * [promise.delay(milliseconds)](#promisedelay) * [promise.timeout(milliseconds, reason)](#promisetimeout) * [promise.inspect()](#promiseinspect) * [promise.with(thisArg)](#promisewith) * [promise.progress(onProgress)](#promiseprogress) 1. Arrays * [when.all(array)](#whenall) * [when.settle(array)](#whensettle) * [when.map(array, mapper)](#whenmap) * [when.filter(array, predicate)](#whenfilter) * [when.reduce(array, reducer)](#whenreduce) * [when.reduceRight(array, reducer)](#whenreduceright) 1. Array Races * [when.any(array)](#whenany) * [when.some(array, n)](#whensome) 1. Infinite Promise Sequences * [when.iterate(f, condition, handler, seed)](#wheniterate) * [when.unfold(f, condition, handler, seed)](#whenunfold) 1. Objects * when/keys * [keys.all(object)](#whenkeys-all) * [keys.map(object, mapper)](#whenkeys-map) * [keys.settle(object)](#whenkeys-settle) 1. Functions * when/function * [fn.lift(f)](#fnlift) * [fn.liftAll(object)](#fnliftall) * [fn.call(f, ...args)](#fncall) * [fn.apply(f, argsArray)](#fnapply) * when/node * [node.lift(nodeFunction)](#nodelift) * [node.liftAll(object)](#nodeliftall) * [node.call(nodeFunction, ...args)](#nodecall) * [node.apply(nodeFunction, argsArray)](#nodeapply) * [node.bindCallback(promise, nodeback)](#nodebindcallback) * [node.liftCallback(callback)](#nodeliftcallback) * [node.createCallback(resolver)](#nodecreatecallback) * [Support promises and node-style functions](#support-promises-and-node-style-callback-functions) * when/callbacks * [callbacks.lift(asyncFunction)](#callbackslift) * [callbacks.liftAll(object)](#callbacksliftall) * [callbacks.call(asyncFunction, ...args)](#callbackscall) * [callbacks.apply(asyncFunction, argsArray)](#callbacksapply) 1. [ES6 generators](#es6-generators) * when/generator * [generator.lift(g)](#generatorlift) * [generator.call(g, ...args)](#generatorcall) * [generator.apply(g, argsArray)](#generatorapply) 1. Task Execution * [when/sequence(tasks, ...args)](#whensequence) * [when/pipeline(tasks, ...args)](#whenpipeline) * [when/parallel(tasks, ...args)](#whenparallel) * [when/poll(task, interval, condition [, initialDelay])](#whenpoll) 1. Limiting Concurrency * [when/guard(condition, f)](#whenguard) * [Guard conditions](#guard-conditions) 1. [Error types](#error-types) 1. [Debugging promises](#debugging-promises) 1. [Upgrading to 3.0 from 2.x](#upgrading-to-30-from-2x) 1. [Refactoring progress](#refactoring-progress) # Core ## when() ```js var promise = when(x); ``` Get a trusted promise for `x`. If `x` is: * a value, returns a promise fulfilled with `x` * a promise, returns `x`. * a foreign thenable, returns a promise that follows `x` ```js var transformedPromise = when(x, f); ``` Get a trusted promise by transforming `x` with `f`. If `x` is * a value, returns a promise fulfilled with `f(x)` * a promise or thenable, returns a promise that * if `x` fulfills, will fulfill with the result of calling `f` with `x`'s fulfillment value. * if `x` rejects, will reject with the same reason as `x` `when()` accepts any promise that provides a *thenable* promise--any object that provides a `.then()` method, even promises that aren't fully Promises/A+ compliant, such as jQuery's Deferred. It will assimilate such promises and make them behave like Promises/A+. ## when.try **ALIAS:** when.attempt() for non-ES5 environments ```js var promise = when.try(f /*, arg1, arg2, ...*/); ``` Calls `f` with the supplied arguments, returning a promise for the result. The arguments may be promises, in which case, `f` will be called after they have fulfilled. The returned promise will fulfill with the successful result of calling `f`. If any argument is a rejected promise, or if `f` fails by throwing or returning a rejected promise, the returned promise will also be rejected. This can be a great way to kick off a promise chain when you want to return a promise, rather than creating a one manually. ```js // Try to parse the JSON, capture any failures in the returned promise // (This will never throw) return when.try(JSON.parse, jsonString); ``` ### See also: * [when.lift](#whenlift) * [when/node call](#nodecall) * [when/node apply](#nodeapply) ## when.lift ```js var g = when.lift(f); ``` Creates a "promisified" version of `f`, which always returns promises (`g` will never throw) and accepts promises or values as arguments. In other words, calling `g(x, y z)` is like calling `when.try(f, x, y, z)` with the added convenience that once you've created `g` you can call it repeatedly or pass it around like any other function. In addition, `g`'s thisArg will behave in a predictable way, like any other function (you can `.bind()` it, or use `.call()` or `.apply()`, etc.). Like `when.try`, lifting functions provides a convenient way start promise chains without having to explicitly create promises, e.g. `new Promise` ```js // Call parse as often as you need now. // It will always return a promise, and will never throw // Errors will be captured in the returned promise. var jsonParse = when.lift(JSON.parse); // Now use it wherever you need return jsonParse(jsonString); ``` `when.lift` correctly handles `this`, so object methods can be lifted as well: ```js var parser = { reviver: ... parse: when.lift(function(str) { return JSON.parse(str, this.reviver); }); }; // Now use it wherever you need return parser.parse(jsonString); ``` ### See also: * [when.try](#whentry) * [when/node lift](#nodelift) * [when/node liftAll](#nodeliftall) ## when.join ```js var joinedPromise = when.join(promiseOrValue1, promiseOrValue2, ...); ``` Return a promise that will fulfill only once *all* the inputs have fulfilled. The value of the returned promise will be an array containing the values of each of the inputs. If any of the input promises is rejected, the returned promise will be rejected with the reason from the first one that is rejected. ```js // largerPromise will resolve to the greater of two eventual values var largerPromise = when.join(promise1, promise2).then(function (values) { return values[0] > values[1] ? values[0] : values[1]; }); ``` ### See also: * [when.all](#whenall) - resolving an Array of promises ## when.promise ```js var promise = when.promise(resolver); ``` Create a [Promise](#promise), whose fate is determined by running the supplied resolver function. The resolver function will be called synchronously, with 3 arguments: ```js var promise = when.promise(function(resolve, reject, notify) { // Do some work, possibly asynchronously, and then // resolve or reject. // DEPRECATED: You can notify of progress events // along the way if you want/need. resolve(awesomeResult); // or resolve(anotherPromise); // or reject(nastyError); }); ``` * `resolve(promiseOrValue)` - Primary function that seals the fate of the returned promise. Accepts either a non-promise value, or another promise. * When called with a non-promise value, fulfills `promise` with that value. * When called with another promise, e.g. `resolve(otherPromise)`, `promise`'s fate will be equivalent to that that of `otherPromise`. * `reject(reason)` - function that rejects `promise`. * `notify(update)` - **DEPRECATED** function that issues progress events for `promise`. See [Refactoring progress](#refactoring-progress) for more info. ## when.resolve ```js var resolved = when.resolve(x); ``` Get a promise for the supplied `x`. If `x` is already a trusted promise, it is returned. If `x` is a value, the returned promise will be fulfilled with `x`. If `x` is a thenable, the returned promise will follow `x`, adopting its eventual state (fulfilled or rejected). ## when.reject ```js var rejected = when.reject(error); ``` Create a rejected promise with the supplied error as the rejection reason. **DEPRECATION WARNING:** In when.js 2.x, error is allowed to be a promise for an error. In when.js 3.0, error will always be used verbatim as the rejection reason, even if it is a promise. ## when.defer ```js var deferred = when.defer(); ``` **Note:** The use of `when.defer` is discouraged. In most cases, using [`when.promise`](#whenpromise), [`when.try`](#whentry), or [`when.lift`](#whenlift) provides better separation of concerns. Create a `{promise, resolve, reject, notify}` tuple. In certain (rare) scenarios it can be convenient to have access to both the `promise` and it's associated resolving functions. The deferred API: ```js var promise = deferred.promise; // Resolve the promise, x may be a promise or non-promise deferred.resolve(x) // Reject the promise with error as the reason deferred.reject(error) // DEPRECATED Notify promise consumers of a progress update deferred.notify(x) ``` Note that `resolve`, `reject`, and `notify` all become no-ops after either `resolve` or `reject` has been called the first time. One common use case for creating a deferred is adapting callback-based functions to promises. In those cases, it's preferable to use the [when/callbacks](#asynchronous-functions) module to [call](#callbackscall) or [lift](#callbackslift) the callback-based functions instead. For adapting node-style async functions, use the [when/node](#node-style-asynchronous-functions) module. ## when.isPromiseLike ```js var is = when.isPromiseLike(x); ``` Return true if `x` is an object or function with a `then` method. It does not distinguish trusted when.js promises from other "thenables" (e.g. from some other promise implementation). Using `isPromiseLike` is discouraged. In cases where you have an `x` and don't know if it's a promise, typically the best thing to do is to cast it: `var trustedPromise = when(x);` and then use `trustedPromise`. # Promise A promise is a proxy for a value that isn't available yet allowing you to interact with it as if it is. ## promise.done ```js promise.done(handleValue); // returns undefined ``` The simplest API for interacting with a promise, `done` consumes the promise's ultimate value if it fulfills, or causes a fatal error with a loud stack trace if it rejects. ```js promise.done(handleValue, handleError); // returns undefined ``` Consume the promise's ultimate value if the promise fulfills, or handle the ultimate error. It will cause a fatal error if either `handleValue` or `handleError` throw or return a rejected promise. Since `done`'s purpose is consumption rather than transformation, `done` always returns `undefined`. One golden rule of promise error handling is: Either `return` the promise, thereby *passing the error-handling buck* to the caller, or call `done` and *assuming responsibility for errors*. ### See also * [promise.then vs. promise.done](#promisethen-vs-promisedone) * [promise.then](#promisethen) ## promise.then ```js var transformedPromise = promise.then(onFulfilled); ``` [Promises/A+ `then`](http://promisesaplus.com). *Transforms* a promise's value by applying a function to the promise's fulfillment value. Returns a new promise for the transformed result. ```js var transformedPromise = promise.then(onFulfilled, onRejected); ``` `then` may also be used to recover from intermediate errors. However, [`promise.catch`](#promisecatch) is almost always a better, and more readable choice. When `onRejected` is provided, it only handles errors from `promise`, and *will not* handle errors thrown by `onFulfilled`. Compare: ```js // Using only then(): onRejected WILL NOT handle errors thrown by onFulfilled var transformedPromise = promise .then(onFulfilled, onRejected); // Using catch(): onRejected will handled errors thrown by onFulfilled var transformedPromise = promise .then(onFulfilled) .catch(onRejected); // Using catch() is equivalent to: var transformedPromise = promise .then(onFulfilled) .then(void 0, onRejected); ``` **DEPRECATED**: Progress events are deprecated and will be removed in a future release. Until that release. See [Refactoring progress](#refactoring-progress). ```js // Deprecated use of then() and promise.progress() to listen for progress events var transformedPromise = promise.then(onFulfilled, onRejected, onProgress); // or var transformedPromise = promise .progress(onProgress) .then(onFulfilled) .catch(onRejected) ``` `then` arranges for: * `onFulfilled` to be called with the value after `promise` is fulfilled, or * `onRejected` to be called with the rejection reason after `promise` is rejected. * **DEPRECATED**: `onProgress` to be called with any progress updates issued by `promise`. See [Refactoring progress](#refactoring-progress). A promise makes the following guarantees about handlers registered in the same call to `.then()`: 1. Only one of `onFulfilled` or `onRejected` will be called, never both. 1. `onFulfilled` and `onRejected` will never be called more than once. 1. `onProgress` may be called zero or more times. ### See also * [Promises/A+](http://promisesaplus.com) for extensive information on the behavior of `then`. * [promise.done](#promisedone) * [promise.spread](#promisespread) * [promise.progress](#promiseprogress) ## promise.spread ```js var transformedPromise = promise.spread(onFulfilledArray); ``` Similar to [`then`](#promisethen), but calls `onFulfilledArray` with promise's value, which is assumed to be an array, as its argument list. It will also deeply resolve promises within the array. It's equivalent to: ```js // Wrapping onFulfilledArray when.all(promise).then(function(array) { return onFulfilledArray.apply(undefined, array); }); ``` ### See also * [when.all](#whenall) ## promise.fold ```js var resultPromise = promise2.fold(combine, promise1) ``` Combine `promise1` and `promise2` to produce a `resultPromise`. The `combine` function will be called once both `promise1` and `promise2` have fulfilled: `combine(promise1, promise2)`, and like `then` et al, it may return a promise or a value. Just as `promise.then` allows you to easily re-use existing one-argument functions to transform promises, `promise.fold` allows you to reuse two-argument functions. It can also be useful when you need to thread one extra piece of information into a promise chain, *without* having to capture it in a closure or use `promise.with`. For, example, with an existing `sum` function, you can easily sum the value of two promises: ```js function sum(x, y) { return x + y; } var promiseFor3 = when(3); var promiseFor5 = promiseFor3.fold(sum, promiseFor2); // Of course, it accepts values as well: var promiseFor5 = promiseFor3.fold(sum, 2); ``` Or get object properties or array values: ```js function get(key, object) { return object[key]; } when({ name: 'Bob' }) .fold(get, 'name') .done(console.log); // logs 'Bob' when(['a', 'b', 'c']) .fold(get, 1) .done(console.log); // logs 'b' ``` In both cases, `sum` and `get` are generic, *reusable* functions, and no closures were required. ## promise.catch **ALIAS:** otherwise() for non-ES5 environments ```js var recoveredPromise = promise.catch(onRejected); ``` In it's simplest form, `catch` arranges to call `onRejected` on the promise's rejection reason if it is rejected. ```js var recoveredPromise = promise.catch(predicate, onRejected); ``` If you also supply a `predicate`, you can `catch` only errors matching the predicate. This allows much more precise error handling. The `predicate` can be either an `Error` constructor, like `TypeError`, `ReferenceError`, or any custom error type (its `prototype` must be `instanceof Error`), or it can be a function that returns a boolean. ```js promise.then(function() { throw new CustomError('oops!'); }).catch(CustomError, function(e) { // Only catch CustomError instances // all other types of errors will propagate automatically }).catch(function(e) { // Catch other errors }) ``` Doing this in synchronous code is more clumsy, requiring `instanceof` checks inside a `catch` block: ```js try { throw new CustomError('oops!'); } catch(e) { if(e instanceof CustomError) { // Handler CustomError instances } else { // Handle other errors } } ``` ### See also: * [promise.finally](#promisefinally) ## promise.finally **ALIAS:** `ensure()` for non-ES5 environments ```js var promise2 = promise1.finally(cleanup); ``` Finally allows you to execute "cleanup" type tasks in a promise chain. It arranges for `cleanup` to be called, *with no arguments*, when `promise1` is either fulfilled or rejected. It behaves similarly the synchronous `finally` statement: * If `promise1` fulfills, and `cleanup` returns successfully, `promise2` will fulfill with the same value as `promise1`. * If `promise1` rejects, and `cleanup` returns successfully, `promise2` will reject with the same reason as `promise1`. * If `promise1` rejects, and `cleanup` throws or returns a rejected promise, `promise2` will reject with the thrown exception or rejected promise's reason. When combined with `promise.catch`, `promise.finally` allows you to write code that is similar to the familiar synchronous `catch`/`finally` pair. Consider the following synchronous code: ```js try { return doSomething(x); } catch(e) { return handleError(e); } finally { cleanup(); } ``` Using `promise.finally`, similar asynchronous code (with `doSomething()` that returns a promise) can be written: ```js return doSomething() .catch(handleError) .finally(cleanup); ``` ### See also: * [promise.catch](#promisecatch) - intercept a rejected promise ## promise.yield ```js originalPromise.yield(promiseOrValue); ``` Returns a new promise: 1. If `originalPromise` is rejected, the returned promise will be rejected with the same reason 2. If `originalPromise` is fulfilled, then it "yields" the resolution of the returned promise to promiseOrValue, namely: 1. If `promiseOrValue` is a value, the returned promise will be fulfilled with `promiseOrValue` 2. If `promiseOrValue` is a promise, the returned promise will be: - fulfilled with the fulfillment value of `promiseOrValue`, or - rejected with the rejection reason of `promiseOrValue` In other words, it's much like: ```js originalPromise.then(function() { return promiseOrValue; }); ``` ### See also: * [promise.else](#promiseelse) - return a default value when promise rejects ## promise.else **ALIAS:** `orElse()` for non-ES5 environments ```js var p1 = doAsyncOperationThatMightFail(); return p1.else(defaultValue); ``` If a promise is rejected, `else` catches the rejection and resolves the returned promise with a default value. This is a shortcut for manually `catch`ing a promise and returning a different value, as such: ```js var p1 = doAsyncOperationThatMightFail(); return p1.catch(function() { return defaultValue; }); ``` ### See also: * [promise.catch](#promisecatch) - intercept a rejected promise * [promise.tap](#promisetap) - execute a side effect in a promise chain * [promise.yield](#promiseyield) - execute a side effect in a promise chain ## promise.tap ```js var promise2 = promise1.tap(onFulfilledSideEffect); ``` Executes a function as a side effect when `promise` fulfills. Returns a new promise: 1. If `promise` fulfills, `onFulfilledSideEffect` is executed: - If `onFulfilledSideEffect` returns successfully, the promise returned by `tap` fulfills with `promise`'s original fulfillment value. That is, `onfulfilledSideEffect`'s result is discarded. - If `onFulfilledSideEffect` throws or returns a rejected promise, the promise returned by `tap` rejects with the same reason. 2. If `promise` rejects, `onFulfilledSideEffect` is *not* executed, and the promise returned by `tap` rejects with `promise`'s rejection reason. These are equivalent: ```js // Using only .then() promise.then(function(x) { return when(doSideEffectsHere(x)).yield(x); }); // Using .tap() promise.tap(doSideEffectsHere); ``` ### See also: * [promise.catch](#promisecatch) - intercept a rejected promise * [promise.else](#promiseelse) - return a default value when promise rejects ## promise.delay ```js var delayedPromise = promise.delay(milliseconds); ``` Create a new promise that will, after `milliseconds` delay, fulfill with the same value as `promise`. If `promise` rejects, `delayedPromise` will be rejected immediately. ```js var delayed; // delayed is a pending promise that will become fulfilled // in 1 second with the value "hello" delayed = when('hello').delay(1000); // delayed is a pending promise that will become fulfilled // 1 second after anotherPromise resolves, or will become rejected // *immediately* after anotherPromise rejects. delayed = promise.delay(1000); // Do something 1 second after promise resolves promise.delay(1000).then(doSomething).catch(handleRejection); ``` ### See also: * [promise.timeout](#promisetimeout) ## promise.timeout ```js var timedPromise = promise.timeout(milliseconds, reason); ``` Create a new promise that will reject with a [`TimeoutError`](#timeouterror) or a custom `reason` after a timeout if `promise` does not fulfill or reject beforehand. ```js var node = require('when/node'); // Lift fs.readFile so it returns promises var readFile = node.lift(fs.readFile); // Try to read the file, but timeout if it takes too long function readWithTimeout(path) { return readFile(path).timeout(500); } ``` You can [pattern-match using `catch`](#promisecatch) to specifically handle `TimeoutError`s: ```js var when = require('when'); var p = readWithTimeout('/etc/passwd') .catch(when.TimeoutError, handleTimeout) // handle only TimeoutError .catch(handleFailure) // handle other errors ``` ### See also: * [promise.delay](#promisedelay) ## promise.inspect ```js var status = promise.inspect(); ``` Returns a snapshot descriptor of the current state of `promise`. This descriptor is *not live* and will not update when `promise`'s state changes. The descriptor is an object with the following properties. When promise is: * pending: `{ state: 'pending' }` * fulfilled: `{ state: 'fulfilled', value: }` * rejected: `{ state: 'rejected', reason: }` While there are use cases where synchronously inspecting a promise's state can be helpful, the use of `inspect` is discouraged. It is almost always preferable to simply use `when()` or `promise.then` to be notified when the promise fulfills or rejects. ### See also: * [when.settle](#whensettle) - settling an Array of promises ## promise.with **ALIAS:** `withThis()` for non-ES5 environments ```js var boundPromise = promise.with(object); ``` Creates a new promise that follows `promise`, but which will invoke its handlers with their `this` set to `object`. Normally, promise handlers are invoked with no specific `thisArg`, so `with` can be very useful when bridging promises to object-oriented patterns and libraries. **NOTE:** Promises returned from `with`/`withThis` are NOT Promises/A+ compliant, specifically violating 2.2.5 (http://promisesaplus.com/#point-41) For example: ```js function Thing(value, message) { this.value = value; this.message = message; } Thing.prototype.doSomething = function(x) { var promise = doAsyncStuff(x); return promise.with(this) // Set thisArg to this thing instance .then(this.addValue) // Works since addValue will have correct thisArg .then(this.format); // all subsequent promises retain thisArg }; Thing.prototype.addValue = function(y) { return this.value + y; }; Thing.prototype.format = function(result) { return this.message + result; }; // Using it var thing = new Thing(41, 'The answer is '); thing.doSomething(1) .with(console) // Re-bind thisArg now to console .then(console.log); // Logs 'The answer is 42' ``` All promises created from `boundPromise` will also be bound to the same thisArg until `with` is used to re-bind or *unbind* it. In the previous example, the promise returned from `thing.doSomething` still has its thisArg bound to `thing`. That may not be what you want, so you can *unbind* it just before returning: ```js Thing.prototype.doSomething = function(x) { var promise = doAsyncStuff(x); return promise.with(this) .then(this.addValue) .then(this.format) .with(); // Unbind thisArg }; ``` ## promise.progress **DEPRECATED** Progress events are deprecated. See [Refactoring progress](#refactoring-progress) ```js promise.progress(onProgress); ``` Registers a handler for progress updates from `promise`. It is a shortcut for: ```js promise.then(void 0, void 0, onProgress); ``` ### Notes on Progress events Progress events are not specified in Promises/A+ and are optional in Promises/A. They have proven to be useful in practice, but unfortunately, they are also underspecified, and there is no current *de facto* or agreed-upon behavior in the promise implementor community. In when.js, progress events will be propagated through a promise chain: 1. In the same way as resolution and rejection handlers, your progress handler *MUST* return a progress event to be propagated to the next link in the chain. If you return nothing, *undefined will be propagated*. 1. Also in the same way as resolutions and rejections, if you don't register a progress handler (e.g. `.then(handleResolve, handleReject /* no progress handler */)`), the update will be propagated through. 1. **This behavior will likely change in future releases:** If your progress handler throws an exception, the exception will be propagated to the next link in the chain. The best thing to do is to ensure your progress handlers do not throw exceptions. 1. **Known Issue:** If you allow an exception to propagate and there are no more progress handlers in the chain, the exception will be silently ignored. We're working on a solution to this. This gives you the opportunity to *transform* progress events at each step in the chain so that they are meaningful to the next step. It also allows you to choose *not* to transform them, and simply let them propagate untransformed, by not registering a progress handler. Here is an example: ```js function myProgressHandler(update) { logProgress(update); // Return a transformed progress update that is // useful for progress handlers of the next promise! return update + 1; } function myOtherProgressHandler(update) { logProgress(update); } var d = when.defer(); d.promise.then(undefined, undefined, myProgressHandler); var chainedPromise = d.promise.then(doStuff); chainedPromise.then(undefined, undefined, myOtherProgressHandler); var update = 1; d.notify(update); // Results in: // logProgress(1); // logProgress(2); ``` # Arrays ## when.all ```js var promise = when.all(array) ``` Where: * array is an Array *or a promise for an array*, which may contain promises and/or values. Return a promise that will resolve only once all the items in `array` have resolved. The resolution value of the returned promise will be an array containing the resolution values of each of the items in `array`. If any of the promises is rejected, the returned promise will be rejected with the rejection reason of the first promise that was rejected. ### See also: * [when.join](#whenjoin) * [when.settle](#whensettle) ## when.map ```js var promise = when.map(array, mapper) ``` Where: * array is an Array or promise for an Array, which may contain promises and/or values Traditional array map function, similar to `Array.prototype.map()`, but allows input to contain promises and/or values, and mapFunc may return either a value or a promise. The order of items in the input array and the results will match, however, `when.map` allows mapping to proceed opportunistically as promises in the array fulfill, making it extremely efficient. If any of the promises is rejected, the returned promise will be rejected with the rejection reason of the first promise that was rejected. The map function should have the signature: ```js mapFunc(value:*, index:Number):* ``` Where: * `value` fulfilled value * `index` array index of `value` ## when.filter ```js var promise = when.filter(array, predicate); ``` Where: * array is an Array or promise for an Array, which may contain promises and/or values Filters the input array, returning a promise for the filtered array. The filtering `predicate` may return a boolean or promise for boolean. If any of the promises is rejected, the returned promise will be rejected with the rejection reason of the first promise that was rejected. The predicate should have the signature: ```js predicate(value:*, index:Number):boolean ``` Where: * `value` fulfilled value * `index` array index of `value` ## when.reduce ## when.reduceRight ```js var promise = when.reduce(array, reducer [, initialValue]) var promise = when.reduceRight(array, reducer [, initialValue]) ``` Where: * array is an Array *or a promise for an array*, which may contain promises and/or values. Traditional array reduce function, similar to `Array.prototype.reduce()` and `Array.prototype.reduceRight()`, but input may contain promises and/or values, and reduceFunc may return either a value or a promise, *and* initialValue may be a promise for the starting value. Both `when.reduce` and `when.reduceRight` proceed in index order (ascending or descending, respectively), without any overlapping--in contrast to [`when.map`](#whenmap) which proceeds opportunistically. The reduce function should have the signature: ```js reducer(currentResult, value, index) ``` Where: * `currentResult` is the current accumulated reduce value * `value` is the fully resolved value at `index` in `array` * `index` is the *basis* of `value` ... practically speaking, this is the array index of the array corresponding to `value` ```js // sum the eventual values of several promises var sumPromise = when.reduce(inputPromisesOrValues, function (sum, value) { return sum += value; }, 0); ``` If any of the promises is rejected, the returned promise will be rejected with the rejection reason of the first promise that was rejected. ## when.settle ```js var promise = when.settle(array); ``` Returns a promise for an array containing the same number of elements as the input array. Each element is a descriptor object describing of the outcome of the corresponding element in the input. The returned promise will only reject if `array` itself is a rejected promise. Otherwise, it will always fulfill with an array of descriptors. This is in contrast to [when.all](#whenall), which will reject if any element of `array` rejects. If the corresponding input promise is: * fulfilled, the descriptor will be: `{ state: 'fulfilled', value: }` * rejected, the descriptor will be: `{ state: 'rejected', reason: }` ```js // Process all successful results, and also log all errors // Input array var array = [when.reject(1), 2, when(3), when.reject(4)]; // Settle all inputs var settled = when.settle(array); // Logs 1 & 4 and processes 2 & 3 settled.then(function(descriptors) { descriptors.forEach(function(d) { if(d.state === 'rejected') { logError(d.reason); } else { processSuccessfulResult(d.value); } }); }); ``` ### See also: * [when.all](#whenall) * [promise.inspect](#inspect) * [keys.settle](#whenkeys-settle) # Objects the `when/keys` module provides `all()`, and `map()` for working with object keys, for the times when organizing promises in a hash using object keys is more convenient than using an array. ## when/keys all ```js var promise = keys.all(object) ``` Where: * object is an Object *or a promise for an Object*, whose keys represent promises and/or values. Return a promise that will resolve only once *all* the items in `object` have resolved. The resolution value of the returned promise will be an object containing the resolved key-value pairs of each of the items in `object`. If any of the promises is rejected, the returned promise will be rejected with the rejection reason of the first promise that was rejected. ### See also: * [when.all](#whenall) ## when/keys map ```js var promise = keys.map(object, mapper) ``` Where: * object is an Object *or a promise for an Object*, whose keys represent promises and/or values. Similar to `when.map`, but for object keys, returns a promise for the key-mappedValue pairs by applying `mapper` to every value. `mapper` may return either a promise or a value. If any of the promises is rejected, the returned promise will be rejected with the rejection reason of the first promise that was rejected. The map function should have the signature: ```js mapFunc(value:*, key:String):* ``` Where: * `value` fulfilled value * `key` key corresponding to `value` ### See also: * [when.map](#whenmap) ## when/keys settle ```js var promise = keys.settle(object) ``` Where * object is an Object whose keys represent promises and/or values. Similar to `when.settle`, but for object keys, returns a promise for the key-value pairs with a resultant descriptor object for each key. The returned promise should always fulfill. ### See also: * [when.settle](#whensettle) # Array Races The *competitive race* pattern may be used if one or more of the entire possible set of *eventual outcomes* are sufficient to resolve a promise. ## when.any ```js var promise = when.any(array) ``` A competitive race that allows one winner. The returned promise will: * fulfill as soon as any one of the input promises fulfills, with the value of the fulfilled input promise, *or* * reject: * with a `RangeError` if the input array is empty--i.e. it is impossible to have one winner. * with an array of all the rejection reasons, if the input array is non-empty, and *all* input promises reject. ### See also: * [when.race](#whenrace) * [when.some](#whensome) ## when.some **DEPRECATED** ```js var promise = when.some(array, n) ``` A competitive race that requires `n` winners. The returned promise will * fulfill when `n` promises are fulfilled with an array containing the values of the fulfilled input promises, *or* * reject: * with a `RangeError` if the input contains fewer than `n` items--i.e. it is impossible to have `n` winners. * with an array containing the reasons of the rejected input promises when it becomes impossible for `n` promises to become fulfilled (ie when `(array.length - n) + 1` reject). ```js // ping all of the p2p servers and fail if at least two don't respond var remotes = [ping('p2p.cdn.com'), ping('p2p2.cdn.com'), ping('p2p3.cdn.com')]; when.some(remotes, 2).done(itsAllOk, failGracefully); ``` ### See also: * [when.any](#whenany) ## when.race ```js var promise = when.race(array); ``` A competitive race to settle. The returned promise will settle in the same way as the earliest promise in `array` to settle. That is, it will * fulfill if the earliest promise in array fulfills, with the same value, *or* * reject if the earliest promise in array rejects, with the same reason. **WARNING:** As per the ES6 spec, the returned promise will *remain pending forever* if `array` is empty. ### See also: * [when.any](#whenany) # Infinite Promise Sequences [when.reduce](#whenreduce), [when/sequence](#whensequence), and [when/pipeline](#whenpipeline) are great ways to process asynchronous arrays of promises and tasks. Sometimes, however, you may not know the array in advance, or may not need or want to process *all* the items in the array. For example, here are a few situations where you may not know the bounds: 1. You need to process a queue to which items are still being added as you process it 1. You need to execute a task repeatedly until a particular condition becomes true 1. You need to selectively process items in an array, rather than all items In these cases, you can use `when/iterate` and `when/unfold` to iteratively and asynchronously process items until a particular predicate is true, or even forever without blocking other code. ## when.iterate ```js var promise = when.iterate(f, predicate, handler, seed); ``` Generates a potentially infinite stream of promises by repeatedly calling `f` until `predicate` becomes true. Where: * `f` - function that, given a seed, returns the next value or a promise for it. * `predicate` - function that receives the current iteration value, and should return truthy when the iterating should stop * `handler` - function that receives each value as it is produced by `f`. It may return a promise to delay the next iteration. * `seed` - initial value provided to the handler, and first `f` invocation. May be a promise. ### Examples Here is a trivial example of counting up to any arbitrary number using promises and delays. Note that this "iteration" is asynchronous and will not block other code. It stores no intermediate arrays in memory, and will never blow the call stack. ```js // Logs // 0 // 1 // 2 // ... // 100000000000 when.iterate(function(x) { return x+1; }, function(x) { // Stop when x >= 100000000000 return x >= 100000000000; }, function(x) { console.log(x); }, 0).done(); ``` Which becomes even nicer with [ES6 arrow functions](http://tc39wiki.calculist.org/es6/arrow-functions/): ```js when.iterate(x => x+1, x => x >= 100000000000, x => console.log(x), 0).done(); ``` ## when.unfold ```js var promise = when.unfold(unspool, predicate, handler, seed); ``` Similar to [`when/iterate`](#wheniterate), `when.unfold` generates a potentially infinite stream of promises by repeatedly calling `unspool` until `predicate` becomes true. `when.unfold` allows you to thread additional state information through the iteration. Where: * `unspool` - function that, given a seed, returns a `[valueToSendToHandler, newSeed]` pair. May return an array, array of promises, promise for an array, or promise for an array of promises. * `predicate` - function that receives the current seed, and should return truthy when the unfold should stop * `handler` - function that receives the `valueToSendToHandler` of the current iteration. This function can process `valueToSendToHandler` in whatever way you need. It may return a promise to delay the next iteration of the unfold. * `seed` - initial value provided to the first `unspool` invocation. May be a promise. ### Examples This example generates random numbers at random intervals for 10 seconds. The `predicate` could easily be modified (to `return false;`) to generate random numbers *forever*. This would not overflow the call stack, and would not starve application code since it is asynchronous. ```js var when = require('when'); var end = Date.now() + 10000; var start = Date.now(); // Generate random numbers at random intervals! // Note that we could generate these forever, and never // blow the call stack, nor would we starve the application function unspool(seed) { // seed is passed in, although for this example, we don't need it // Return a random number as the value, and the time it was generated // as the new seed var next = [Math.random(), Date.now()]; // Introduce a delay, just for fun, to show that we can return a promise return when(next).delay(Math.random() * 1000); } // Stop after 10 seconds function predicate(time) { return time > end; } function log(value) { console.log(value); } when.unfold(unspool, predicate, log, start).then(function() { console.log('Ran for', Date.now() - start, 'ms'); }).done(); ``` Which again becomes quite compact with [ES6 arrow functions](http://tc39wiki.calculist.org/es6/arrow-functions/): ```js when.unfold(unspool, time => time > end, x => console.log(x), start) .then(() => console.log('Ran for', Date.now() - start, 'ms')) .done(); ``` This example iterates over files in a directory, mapping each file to the first line (or first 80 characters) of its content. It uses a `predicate` to terminate early, which would not be possible with `when.map`. Notice that, while the pair returned by `unspool` is an Array (not a promise), it does *contain* a promise as it's 0th element. The promise will be resolved by the `unfold` machinery. Notice also the use of `when/node`'s [`call()`](#node-style-asynchronous-functions) to call Node-style async functions (`fs.readdir` and `fs.readFile`), and return a promise instead of requiring a callback. This allows node-style functions can be promisified and composed with other promise-aware functions. ```js var when = require('when'); var node = require('when/node'); var fs = node.liftAll(require('fs')); // Lifted fs methods return promises var files = fs.readdir('.'); function unspool(files) { // Return the pair [<*promise* for contents of first file>, ] // the first file's contents will be handed to printFirstLine() // the remaining files will be handed to condition(), and then // to the next call to unspool. // So we are iteratively working our way through the files in // the dir, but allowing condition() to stop the iteration at // any point. var file, content; file = files[0]; content = fs.readFile(file) .catch(function(e) { return '[Skipping dir ' + file + ']'; }); return [content, files.slice(1)]; } function predicate(remaining) { // This could be any test we want. For fun, stop when // the next file name starts with a 'p'. return remaining[0].charAt(0) === 'p'; } function printFirstLine(content) { // Even though contents was a promise in unspool() above, // when/unfold ensures that it is fully resolved here, i.e. it is // not a promise any longer. // We can do any work, even asynchronous work, we need // here on the current file // Node fs returns buffers, convert to string content = String(content); // Print the first line, or only the first 80 chars if the fist line is longer console.log(content.slice(0, Math.min(80, content.indexOf('\n')))); } when.unfold(unspool, predicate, printFirstLine, files).done(); ``` # Task Execution These modules allow you to execute tasks in series or parallel. Each module takes an Array of task functions (or a *promise* for an Array), executes the tasks, and returns a promise that resolves when all the tasks have completed. ## when/sequence ```js var sequence = require('when/sequence'); var resultsPromise = sequence(arrayOfTasks, arg1, arg2 /*, ... */); ``` Run an array of tasks in sequence, without overlap. Each task will be called with the arguments passed to `when.sequence()`, and each may return a promise or a value. When all tasks have completed, the returned promise will resolve to an array containing the result of each task at the corresponding array position. The returned promise will reject when any task throws or returns a rejection. ## when/pipeline ```js var pipeline = require('when/pipeline'); var resultsPromise = pipeline(arrayOfTasks, arg1, arg2 /*, ... */); ``` Run an array of tasks in sequence, without overlap, similarly to [when/sequence](#whensequence). The *first task* (e.g. `arrayOfTasks[0]`) will be called with the arguments passed to `when.pipeline()`, and each subsequence task will be called with the result of the previous task. Again, each may return a promise or a value. When a task returns a promise, the fully resolved value will be passed to the next task. When all tasks have completed, the returned promise will resolve to the result of the last task. The returned promise will reject when any task throws or returns a rejection. ## when/parallel ```js var parallel = require('when/parallel'); var resultsPromise = parallel(arrayOfTasks, arg1, arg2 /*, ... */); ``` Run an array of tasks in "parallel". The tasks are allowed to execute in any order, and may interleave if they are asynchronous. Each task will be called with the arguments passed to `when.parallel()`, and each may return a promise or a value. When all tasks have completed, the returned promise will resolve to an array containing the result of each task at the corresponding array position. The returned promise will reject when any task throws or returns a rejection. ## when/poll ```js var poll = require('when/poll'); var resultPromise = poll(task, interval, condition /*, initialDelay */); ``` Where: * `task` - function to be called periodically * `interval` - interval between calls to `task`. It may be a number *or* a function that returns a promise. If it's a function, the next polling iteration will wait until the promise fulfills. * `condition` - function that evaluates each result of `task`. Polling will continue until it returns a truthy value. * `initialDelay` - if provided and truthy, the first execution of `task` will be delayed by `interval`. If not provided, or falsey, the first execution of `task` will happen as soon as possible. Execute a task (`task`) repeatedly at the specified `interval`, until the `condition` function returns true. The `resultPromise` will be resolved with the most recent value returned from `task`. If `task` fails (throws an exception or returns a rejected promise) before `condition` returns true, the `resultPromise` will be rejected. # Interacting with non-promise code These modules are aimed at dampening the friction between code that is based on promises and code that follows more conventional approaches to make asynchronous tasks and/or error handling. By using them, you are more likely to be able to reuse code that already exists, while still being able to reap the benefits of promises on your new code. ## Synchronous functions The `when/function` module contains functions for calling and adapting "normal" functions (i.e. those that take plain values, return plain values, and throw exceptions on errors). By calling those functions with `fn.call` and `fn.apply`, or by creating a new function with `fn.lift`, the return value will always be a promise, and thrown exceptions will be turned into rejections. As a bonus, promises given as arguments will be transparently resolved before the call. ### fn.lift ```js var promiseFunction = fn.lift(normalFunction); // Deprecated: using lift to partially apply while lifting var promiseFunction = fn.lift(normalFunction, arg1, arg2/* ...more args */); ``` When the same function will be called through `fn.call()` or `fn.apply()` multiple times, it can be more efficient to lift it create a wrapper function that has promise-awareness and exposes the same behavior as the original function. That's what `fn.lift()` does: It takes a normal function and returns a new, promise-aware version of it. Note: Use [`when.lift`](#whenlift) instead: `when.lift` is equivalent to, but also slightly faster than `fn.lift` when used without the (now deprecated) partial application feature. ```js var when = require('when'); var fn = require('when/function'); function setText(element, text) { element.text = text; } function getMessage() { // Async function that returns a promise } var element = {}; // Resolving the promise ourselves getMessage().then(function(message) { setText(element, message); }); // Using fn.call() fn.call(setText, element, getMessage()); // Creating a lifted function using fn.lift() var promiseSetText = fn.lift(setText); promiseSetText(element, getMessage()); // Partial application var setElementMessage = fn.lift(setText, element); setElementMessage(getMessage()); ``` ### fn.liftAll ```js var liftedApi = fn.liftAll(srcApi); var liftedApi = fn.liftAll(srcApi, transform); var destApi = fn.liftAll(srcApi, transform, destApi); ``` Lifts all the methods of a source object, returning a new object with all the lifted methods. The optional `transform` function allows you to rename or otherwise customize how the lifted functions are added to the returned object. If `destApi` is provided, lifted methods will be added to it, instead of to a new object, and `destApi` will be returned. ### fn.call ```js var promisedResult = fn.call(normalFunction, arg1, arg2/* ...more args */); ``` A parallel to the `Function.prototype.call` function, that gives promise-awareness to the function given as first argument. ```js var when = require('when'); var fn = require('when/function'); function divideNumbers(a, b) { if(b !== 0) { return a / b; } else { throw new Error("Can't divide by zero!"); } } // Prints '2' fn.call(divideNumbers, 10, 5).then(console.log); // Prints '4' var promiseForFive = when(5); fn.call(divideNumbers, 20, promiseForFive).then(console.log); // Prints "Can't divide by zero!" fn.call(divideNumbers, 10, 0).then(console.log, console.error); ``` ### fn.apply ```js var promisedResult = fn.apply(normalFunction, [arg1, arg2/* ...more args */]); ``` `fn.apply` is to [`fn.call`](#fncall) as `Function.prototype.apply` is to `Function.prototype.call`: what changes is the way the arguments are taken. While `fn.call` takes the arguments separately, `fn.apply` takes them as an array. ```js var when = require('when'); var fn = require('when/function'); function sumMultipleNumbers() { return Array.prototype.reduce.call(arguments, function(prev, n) { return prev + n; }, 0); } // Prints '50' fn.apply(sumMultipleNumbers, [10, 20, 20]).then(console.log, console.error); // Prints 'something wrong happened', and the sum function never executes var shortCircuit = when.reject("something wrong happened"); fn.apply(sumMultipleNumbers, [10, 20, shortCircuit]).then(console.log, console.error); ``` ### fn.compose ```js var composedFunc = fn.compose(func1, func2 /* ...more functions */); ``` Composes multiple functions by piping their return values. It is transparent to whether the functions return 'regular' values or promises: the piped argument is always a resolved value. If one of the functions throws or returns a rejected promise, the promise returned by `composedFunc` will be rejected. ```js // Reusing the same functions from the fn.lift() example // Gets the message from the server every 1s, then sets it on the 'element' var refreshMessage = fn.compose(getMessage, setElementMessage); setInterval(refreshMessage, 1000); // Which is equivalent to: setInterval(function() { return fn.call(getMessage).then(setElementMessage); }, 1000); ``` # Node-style asynchronous functions Node.js APIs have their own standard for asynchronous functions: Instead of taking an errback, errors are passed as the first argument to the callback function. To use promises instead of callbacks with node-style asynchronous functions, you can use the `when/node` module, which is very similar to `when/callbacks`, but tuned to this convention. Note: There are some Node.js functions that don't follow the typical Node-style async function conventions, such as `http.get`. These functions will not work with `when/node`. ## node.lift ```js var promiseFunc = nodefn.lift(nodeStyleFunction); // Deprecated: using lift to partially apply while lifting var promiseFunc = nodefn.lift(nodeStyleFunction, arg1, arg2/*...more args*/); ``` Function based on the same principles from [`fn.lift()`](#fnlift) and [`callbacks.lift()`](#callbackslift), but tuned to handle nodejs-style async functions. ```js var dns = require('dns'); var when = require('when'); var nodefn = require('when/node'); var resolveAddress = nodefn.lift(dns.resolve); when.join( resolveAddress('twitter.com'), resolveAddress('facebook.com'), resolveAddress('google.com') ).then(function(addresses) { // All addresses resolved }).catch(function(reason) { // At least one of the lookups failed }); ``` ## node.liftAll ```js var liftedApi = fn.liftAll(srcApi); var liftedApi = fn.liftAll(srcApi, transform); var destApi = fn.liftAll(srcApi, transform, destApi); ``` Lifts all the methods of a source object, returning a new object with all the lifted methods. The optional `transform` function allows you to rename or otherwise customize how the lifted functions are added to the returned object. If `destApi` is provided, lifted methods will be added to it, instead of to a new object, and `destApi` will be returned. ```js // Lift the entire dns API var dns = require('dns'); var promisedDns = node.liftAll(dns); when.join( promisedDns.resolve("twitter.com"), promisedDns.resolveNs("facebook.com"), promisedDns.resolveMx("google.com") ).then(function(addresses) { // All addresses resolved }).catch(function(reason) { // At least one of the lookups failed }); ``` For additional flexibility, you can use the optional `transform` function to do things like renaming: ```js // Lift all of the fs methods, but name them with an 'Async' suffix var fs = require('fs'); var promisedFs = node.liftAll(fs, function(promisedFs, liftedFunc, name) { promisedFs[name + 'Async'] = liftedFunc; return promisedFs; }); promisedFs.readFileAsync('file.txt').done(console.log.bind(console)); ``` You can also supply your own destination object onto which all of the lifted functions will be added: ```js // Lift all of the fs methods, but name them with an 'Async' suffix // and add them back onto fs! var fs = require('fs'); var promisedFs = node.liftAll(fs, function(promisedFs, liftedFunc, name) { promisedFs[name + 'Async'] = liftedFunc; return promisedFs; }, fs); fs.readFileAsync('file.txt').done(console.log.bind(console)); ``` ## node.call ```js var promisedResult = nodefn.call(nodeStyleFunction, arg1, arg2/*...more args*/); ``` Analogous to [`fn.call()`](#fncall) and [`callbacks.call()`](#callbackscall): Takes a function plus optional arguments to that function, and returns a promise for its final value. The promise will be resolved or rejected depending on whether the conventional error argument is passed or not. ```js var fs = require('fs'); var nodefn = require('when/node'); var loadPasswd = nodefn.call(fs.readFile, '/etc/passwd'); loadPasswd.done(function(passwd) { console.log('Contents of /etc/passwd:\n' + passwd); }, function(error) { console.log('Something wrong happened: ' + error); }); ``` ## node.apply ```js var promisedResult = nodefn.apply(nodeStyleFunction, [arg1, arg2/*...more args*/]); ``` Following the tradition from `when/function` and `when/callbacks`, `when/node` also provides a array-based alternative to `nodefn.call()`. ```js var fs = require('fs'); var nodefn = require('when/node'); var loadPasswd = nodefn.apply(fs.readFile, ['/etc/passwd']); loadPasswd.done(function(passwd) { console.log('Contents of /etc/passwd:\n' + passwd); }, function(error) { console.log('Something wrong happened: ' + error); }); ``` ## node.liftCallback ```js var promiseAcceptingFunction = nodefn.liftCallback(nodeback); ``` Transforms a node-style callback function into a function that accepts a promise. This allows you to bridge promises and node-style in "the other direction". For example, if you have a node-style callback, and a function that returns promises, you can lift the former to allow the two functions to be composed. The lifted function will always returns its input promise, and always executes `nodeback` in a future turn of the event loop. Thus, the outcome of `nodeback` has no bearing on the returned promise. If `nodeback` throws an exception, it will propagate to the host environment, just as it would when using node-style callbacks with typical Node.js APIs. ```js var nodefn = require('when/node'); function fetchData(key) { // go get the data and, return promise; } function handleData(err, result) { if(err) { // handle the error } else { // Use the result } } // Lift handleData var handlePromisedData = nodefn.liftCallback(handleData); var dataPromise = fetchData(123); handlePromisedData(dataPromise); ``` ## node.bindCallback ```js var resultPromise = nodefn.bindCallback(promise, nodeback); ``` Lifts and then calls the node-style callback on the provided promise. This is a one-shot version of [nodefn.liftCallback](#nodeliftcallback), and the `resultPromise` will behave as described there. ```js var nodefn = require('when/node'); function fetchData(key) { // go get the data and, return promise; } function handleData(err, result) { if(err) { // handle the error } else { // Use the result } } // Lift handleData var dataPromise = fetchData(123); nodefn.bindCallback(dataPromise, handleData); ``` ## node.createCallback ```js var nodeStyleCallback = nodefn.createCallback(resolver); ``` A helper function of the `when/node` implementation, which might be useful for cases that aren't covered by the higher level API. It takes an object that responds to the resolver interface (`{ resolve:function, reject:function }`) and returns a function that can be used with any node-style asynchronous function, and will call `resolve()` or `reject()` on the resolver depending on whether the conventional error argument is passed to it. ```js var when = require('when'); var nodefn = require('when/node'); function nodeStyleAsyncFunction(callback) { if(Math.random() * 2 > 1) { callback(new Error('Oh no!')); } else { callback(null, "Interesting value"); } } var deferred = when.defer(); nodeStyleAsyncFunction(nodefn.createCallback(deferred.resolver)); deferred.promise.then(function(interestingValue) { console.log(interestingValue) },function(err) { console.error(err) }); ``` ## Support Promises and Node-style callback Functions Sometimes you may want to support both promises and node-style callbacks from within a method, rather than [`lift`](#nodelift) or [`liftAll`](#nodeliftall). To do this you can use [`bindCallback`](#nodebindcallback) which returns the promise you pass to it, and also checks whether a callback is provided or not. ```js var when = require('when'); var bindCallback = require('when/node').bindCallback; module.exports = { getFullName: function (firstName, lastName, callback) { return bindCallback(when.promise(function(resolve, reject) { if (firstName && lastName) { var fullName = firstName + " " + lastName; resolve(fullName); } else { reject("First and last name must be passed."); } }), callback); } }; ``` # Asynchronous functions Much of the asynchronous functionality available to javascript developers, be it directly from the environment or via third party libraries, is callback/errback-based. The `when/callbacks` module provides functions to interact with those APIs via promises in a transparent way, without having to write custom wrappers or change existing code. All the functions on this module (with the exception of `callbacks.promisify()`) assume that the callback and errback will be on the "standard" positions - the penultimate and last arguments, respectively. ### callbacks.lift ```js var promiseFunc = callbacks.lift(callbackTakingFunc); // Deprecated: using lift to partially apply while lifting var promiseFunc = callbacks.lift(callbackTakingFunc, arg1, arg2/* ...more args */); ``` Much like [`fn.lift()`](#fnlift), `callbacks.lift` creates a promise-friendly function, based on an existing function, but following the asynchronous resolution patterns from [`callbacks.call()`](#callbackscall) and [`callbacks.apply()`](#callbacksapply). It can be useful when a particular function needs to be called in multiple places, or for creating an alternative API for a library. Like `Function.prototype.bind`, additional arguments will be partially applied to the new function. ```js // Fictional ajax library, because we don't have enough of those function traditionalAjax(method, url, callback, errback) { var xhr = new XMLHttpRequest(); xhr.open(method, url); xhr.onload = callback; xhr.onerror = errback; xhr.send(); } var myLib = { // Traditional browser API: Takes callback and errback ajax: traditionalAjax, // Promise API: returns a promise, and may take promises as arguments promiseAjax: callbacks.lift(traditionalAjax) }; ``` ### callbacks.liftAll ```js var liftedApi = callbacks.liftAll(srcApi); var liftedApi = callbacks.liftAll(srcApi, transform); var destApi = callbacks.liftAll(srcApi, transform, destApi); ``` Lifts all the methods of a source object, returning a new object with all the lifted methods. The optional `transform` function allows you to rename or otherwise customize how the lifted functions are added to the returned object. If `destApi` is provided, lifted methods will be added to it, instead of to a new object, and `destApi` will be returned. ### callbacks.call ```js var promisedResult = callbacks.call(callbackTakingFunc, arg1, arg2/* ...more args */); ``` Takes a callback-taking function and returns a promise for its final value, forwarding any additional arguments. The promise will be resolved when the function calls its callback, and the resolution value will be callback's first argument. If multiple values are passed to the callback, the promise will resolve to an array. The same thing happens if the function call the errback, with the difference that the promise will be rejected instead. ```js var domIsLoaded = callbacks.call($); domIsLoaded.then(doMyDomStuff); ``` ```js // Fictional ajax library function function traditionalAjax(method, url, callback, errback) { var xhr = new XMLHttpRequest(); xhr.open(method, url); xhr.onload = callback; xhr.onerror = errback; xhr.send(); } var xhrResult = callbacks.call(traditionalAjax, 'GET', url); xhrResult.then(function(result) { console.log("Got result", result); }); ``` ### callbacks.apply ```js var promisedResult = callbacks.apply(callbackTakingFunc, [arg1, arg2/* ...more args */]); ``` The array-taking analog to `callbacks.call`, as `Function.prototype.apply` is to `Function.prototype.call`. ```js // This example simulates fading away an element, fading in a new one, fetching // two remote resources, and then waiting for all that to finish before going // forward. The APIs are all callback-based, but only promises are manipulated. // Function.prototype.bind is needed to preserve the context var oldHidden = callbacks.apply($old.fadeOut.bind($old), ["slow"]); var transitionedScreens = oldHidden.then(function() { return callbacks.apply($new.fadeIn.bind($new), ["slow"]); }); var venuesLoaded = callbacks.apply($.getJSON, ["./venues.json"]); var artistsLoaded = callbacks.apply($.getJSON, ["./artists.json"]); // Leveraging when.join to combine promises when.join(venuesLoaded, artistsLoaded, transitionedScreens).then(function() { // Render next screen when everything is ready }, function() { // Catch-all error handler }); ``` ### callbacks.promisify **DEPRECATED** ```js var promiseFunc = callbacks.promisify(nonStandardFunc, { callback: zeroBasedIndex, errback: otherZeroBasedIndex, }); ``` Almost all the functions on the `callbacks` module assume that the creators of the API were kind enough to follow the unspoken standard of taking the callback and errback as the last arguments on the function call; `callbacks.promisify()` is for when they weren't. In addition to the function to be adapted, `promisify` takes an object that describes what are the positions of the callback and errback arguments. ```js function inverseStandard(errback, callback) { // ... } var promisified1 = callbacks.promisify(inverseStandard, { callback: 1, errback: 0, // indexes are zero-based }); function firstAndThird(callback, someParam, errback) { // ... } var promisified2 = callbacks.promisify(firstAndThird, { callback: 0, errback: 2, }); // The arguments to the promisified call are interleaved with the callback and // errback. promisified(10); function inverseVariadic(/* arg1, arg2, arg3... , */errback, callback) { // ... } var promisified3 = callbacks.promisify(inverseVariadic, { callback: -1, // Negative indexes represent positions relative to the end errback: -2, }); ``` ### Which one should I use? | | fn | node | callback | |----------------------------|----|------|----------| |**The function looks like:**|```doStuff(x, y);```
Synchronous, no callbacks.| ```doStuff(x,y, callback);```
The last parameter is a callback like ```function(err, result)```. | ```doStuff(x, y, callback, errback);```
The next-to-last is callback, last is errback.| |**Use this:** | ```require('when');```
```when.lift(doStuff)(x,y).then(...);```|```nodefn = require('when/node');```
```nodefn.lift(doStuff)(x,y).then(...);```|```callbacks = require('when/callbacks');```
```callbacks.lift(doStuff)(x,y).then(...);```| # ES6 generators **Experimental**: Requires an environment that supports ES6 generators and the `yield` keyword. ## when/generator The `when/generator` module provides APIs for using ES6 generators as coroutines. You can `yield` promises to await their resolution while control is transferred back to the JS event loop. You can write code that looks and acts like synchronous code, even using synchronous `try`, `catch` and `finally`. The following example uses `generator.call` to fetch a list of todos for a user, `yield`ing control until the promise returned by `getTodosForUser` is resolved. If the promise fulfills, execution will continue and show the todos. If the promise rejects, the rejection will be translated to a synchronous exception (using ES6 generator `.throw()`). As you'd expect, control will jump to the `catch` and show an error. ```js var gen = require('when/generator'); gen.call(function*(todosFilter, userId) { var todos; try { todos = yield getTodosForUser(userId); showTodos(todos.filter(todosFilter)); } catch(e) { showError(e); } }, isRecentTodo, 123); function getTodosForUser(userId) { // returns a promise for an array of the user's todos } ``` ## generator.lift ```js var coroutine = generator.lift(es6generator*); // Deprecated: using lift to partially apply while lifting var coroutine = generator.lift(es6generator*, arg1, arg2/*...more args*/); ``` Lifts `es6generator` to a promise-aware coroutine, instead of calling it immediately. Returns a function that, when called, can use `yield` to await promises. This can be more convenient than using `generator.call` or `generator.apply` by allowing you to create the coroutine once, and call it repeatedly as a plain function. Additional arguments provided to `generator.lift` will be partially applied to the lifted coroutine. Here is a revised version of the above example using `generator.lift`. Note that we're also partially applying the `isRecentTodos` filtering function. ```js var gen = require('when/generator'); // Use generator.lift to create a function that acts as a coroutine var getRecentTodosForUser = gen.lift(function*(userId) { var todos; try { todos = yield getTodosForUser(userId); showTodos(todos.filter(isRecentTodo)); } catch(e) { showError(e); } }); function getTodosForUser(userId) { // returns a promise for an array of the user's todos } // Get the recent todos for user 123. getRecentTodosForUser(123); ``` In addition to `try`, `catch`, and `finally`, `return` also works as expected. In this revised example, `yield` allows us to return a result and move error handling out to the caller. ```js var gen = require('when/generator'); // Use generator.lift to create a function that acts as a coroutine var getRecentTodosForUser = gen.lift(function*(userId) { var todos = yield getTodosForUser(userId); return todos.filter(isRecentTodo); }); function getTodosForUser(userId) { // returns a promise for an array of the user's todos } // filteredTodos is a promise for the recent todos for user 123 var filteredTodos = getRecentTodosForUser(123); ``` ## generator.call ```js var resultPromise = generator.call(es6generator*, arg1, arg2/*...more args*/); ``` Immediately calls `es6generator` with the supplied args, and allows it use `yield` to await promises. ## generator.apply ```js var resultPromise = generator.apply(es6generator*, [arg1, arg2/*...more args*/]); ``` Similar to `generator.call`, immediately calls `es6generator` with the supplied args array, and allows it use `yield` to await promises. # Limiting Concurrency ## when/guard ```js var guard = require('when/guard'); var guarded = guard(condition, function() { // .. Do important stuff }); ``` Where: * `condition` is a concurrency limiting condition, such as [guard.n](#guardn) Limit the concurrency of a function. Creates a new function whose concurrency is limited by `condition`. This can be useful with operations such as [when.map](#whenmap), [when/parallel](#whenparallel), etc. that allow tasks to execute in "parallel", to limit the number which can be inflight simultanously. ```js // Using when/guard with when.map to limit concurrency // of the mapFunc var guard, guardedAsyncOperation, mapped; guard = require('when/guard'); // Allow only 1 inflight execution of guarded guardedAsyncOperation = guard(guard.n(1), asyncOperation); mapped = when.map(array, guardedAsyncOperation); mapped.then(function(results) { // Handle results as usual }); ``` ```js // Using when/guard with when/parallel to limit concurrency // across *all tasks* var guard, parallel, guardTask, tasks, taskResults; guard = require('when/guard'); parallel = require('when/parallel'); tasks = [/* Array of async functions to execute as tasks */]; // Use bind() to create a guard that can be applied to any function // Only 2 tasks may execute simultaneously guardTask = guard.bind(null, guard.n(2)); // Use guardTask to guard all the tasks. tasks = tasks.map(guardTask); // Execute the tasks with concurrency/"parallelism" limited to 2 taskResults = parallel(tasks); taskResults.then(function(results) { // Handle results as usual }); ``` ## Guard conditions ### guard.n ```js var condition = guard.n(number); ``` Creates a condition that allows at most `number` of simultaneous executions inflight. # Error types ### TimeoutError ```js var TimeoutError = when.TimeoutError; // or var TimeoutError = require('when/lib/TimeoutError'); ``` [Timeout promises](#promisetimeout) reject with `TimeoutError` unless a custom reason is provided. # Debugging promises Errors in an asynchronous operation always occur in a different call stack than the the one that initiated the operation. Because of that, such errors cannot be caught using synchronous `try/catch`. Promises help to manage that process by capturing the error and rejecting the associated promise, so that application code can handle the error using promise error handling features, such as [`promise.catch`](#promisecatch). This is generally a good thing. If promises *didn't* do this, *any* thrown exception would be uncatchable, even those errors that could have been handled by the application, and would instead cause a crash. However, this also means that errors captured in rejected promises often go silent until observed by calling `promise.catch`. In nearly all promise implementations, if application code never calls `promise.catch`, the error will be silent. By default, when.js logs *potentially unhandled rejections* to `console.error`, along with stack traces. This works even if you don't call [`promise.done`](#promisedone), or if you never call `promise.catch`, and is much like uncaught synchronous exceptions. Tracking down asynchronous failures can be tricky, so to get even richer debugging information, including long, asynchronous, stack traces, you can enable [`when/monitor/console`](#whenmonitorconsole). ## Potentially unhandled rejections For example, the following error will be completely silent in most promise implementations. ```js var when = require('when'); when.resolve(123).then(function(x) { // This code executes in a future call stack, and the // ReferenceError cannot be caught with try/catch oops(x); }); ``` In when.js, you will get an error stack trace to the console: ``` Potentially unhandled rejection [1] ReferenceError: oops is not defined at /Users/brian/Projects/cujojs/when/experiments/unhandled.js:4:2 at tryCatchReject (/Users/brian/Projects/cujojs/when/lib/makePromise.js:806:14) at FulfilledHandler.when (/Users/brian/Projects/cujojs/when/lib/makePromise.js:602:9) at ContinuationTask.run (/Users/brian/Projects/cujojs/when/lib/makePromise.js:726:24) at Scheduler._drain (/Users/brian/Projects/cujojs/when/lib/scheduler.js:56:14) at Scheduler.drain (/Users/brian/Projects/cujojs/when/lib/scheduler.js:21:9) at process._tickCallback (node.js:419:13) at Function.Module.runMain (module.js:499:11) at startup (node.js:119:16) at node.js:906:3 ``` The error is tagged with "Potentially unhandled rejection" and an *id*, `[1]` in this case, to visually call out that it is potentially unhandled. If the rejection is handled at a later time, a second message including the same id will be logged to help correlate which rejection was handled. Read on to find out why this might happen. ### Rejections handled later It's important to remember that potentially unhandled rejections are, well, *potentially* unhandled. Due to their asynchronous nature, rejected promises may be handled at a later time. For example, a rejection could be handled after a call to `setTimeout`, even though this is very rare in practice. Promise rejections fall into 3 categories: #### Typical usage In typical usage, rejections should be handled quickly (by calling `then`, `catch`, etc.) either by code higher in the current call stack as a promise is returned, or by code in the current promise chain. In these most common cases, where all rejections are handled, no errors will be logged just as you expect in synchronous code where all exceptions are caught and handled using `try/catch`. #### Developer errors These cases typically represent coding mistakes, such as `ReferenceError`s. In these cases, the errors will be logged as potentially unhandled rejections, again just as you expect in synchronous code where there is an uncaught exception. #### Edge cases In rare cases, application code may leave a rejected promise unobserved for a longer period of time, and then at some point later (for example, after a `setTimeout`), handle it. In such cases, the rejection may be reported as being potentially unhandled. When that rejection *is* handled, when.js will log a second message to let you know. For example: ```js var when = require('when'); var p = when.resolve(123).then(function() { throw new Error('this rejection will be handled later'); }); setTimeout(function() { p.catch(function(e) { // ... handled ... }); }, 1000); ``` ``` Potentially unhandled rejection [1] Error: this rejection will be handled later at /Users/brian/Projects/cujojs/when/experiments/unhandled.js:4:8 at tryCatchReject (/Users/brian/Projects/cujojs/when/lib/makePromise.js:806:14) at FulfilledHandler.when (/Users/brian/Projects/cujojs/when/lib/makePromise.js:602:9) at ContinuationTask.run (/Users/brian/Projects/cujojs/when/lib/makePromise.js:726:24) at Scheduler._drain (/Users/brian/Projects/cujojs/when/lib/scheduler.js:56:14) at Scheduler.drain (/Users/brian/Projects/cujojs/when/lib/scheduler.js:21:9) at process._tickCallback (node.js:419:13) at Function.Module.runMain (module.js:499:11) at startup (node.js:119:16) at node.js:906:3 ... one second later ... Handled previous rejection [1] Error: this rejection will be handled later ``` In this case, the rejection was handled later. As mentioned above, the second message includes the id and the original message to correlate with the original error. ## promise.then vs. promise.done Remember the golden rule: either `return` your promise, or call `done` on it. At first glance, `then`, and `done` seem very similar. However, there are important distinctions: 1. The *intent* 2. The error handling characteristics ### Intent The intent of `then` is to *transform* a promise's value and to pass or return a new promise for the transformed value along to other parts of your application. The intent of `done` is to *consume* a promise's value, transferring *responsibility* for the value to your code. ### Errors In addition to transforming a value, `then` allows you to recover from, or propagate, *intermediate* errors. Any errors that are not handled will be caught by the promise machinery and used to reject the promise returned by `then`. **Note:** [`catch`](#promisecatch) is almost always a better choice for handling errors than `then`. It is more readable, and accepts a `predicate` for matching particular error types. Calling `done` transfers all responsibility for errors to your code. If an error (either a thrown exception or returned rejection) escapes the `handleValue`, or `handleError` you provide to `done`, it will be rethrown in an uncatchable way to the host environment, causing a loud stack trace or a crash. This can be a big help with debugging, since most environments will then generate a loud stack trace. In some environments, such as Node.js, the VM will also exit immediately, making it very obvious that a fatal error has escaped your promise chain. ### A Note on JavaScript Errors JavaScript allows `throw`ing and `catch`ing any value, not just the various builtin Error types (Error, TypeError, ReferenceError, etc). However, in most VMs, *only Error types* will produce a usable stack trace. If at all possible, you should always `throw` Error types, and likewise always reject promises with Error types. To get good stack traces, do this: ```js return when.promise(function(resolve, reject) { // ... reject(new Error('Oops!')); }); ``` And not this: ```js return when.promise(function(resolve, reject) { // ... reject('Oops!'); }); ``` Do this: ```js return promise.then(function(x) { // ... throw new Error('Oops!'); }) ``` And not this: ```js return promise.then(function(x) { // ... throw 'Oops!'; }) ``` ## when/monitor/console Experimental promise monitoring and debugging utilities for when.js. ## What does it do? tl;dr Load `when/monitor/console` and get awesome async stack traces, even if you forget to return promises or forget to call `promise.done`: ```js require('when/monitor/console'); var when = require('when'); when().then(function f1() { when().then(function f2() { when().then(function f3() { doh(); }); }); }); ``` ``` ReferenceError: doh is not defined at f3 (/Users/brian/Projects/cujojs/when/experiments/trace.js:7:4) from execution context: at f2 (/Users/brian/Projects/cujojs/when/experiments/trace.js:6:21) from execution context: at f1 (/Users/brian/Projects/cujojs/when/experiments/trace.js:5:10) from execution context: at Object. (/Users/brian/Projects/cujojs/when/experiments/trace.js:4:9) ``` It monitors promise state transitions and then takes action, such as logging to the console, when certain criteria are met, such as when a promise has been rejected but has no `onRejected` handlers attached to it, and thus the rejection would have been silent. Since promises are asynchronous and their execution may span multiple disjoint stacks, it will also attempt to stitch together a more complete stack trace. This synthesized trace includes the point at which a promise chain was created, through other promises in the chain to the point where the rejection "escaped" the end of the chain without being handled. ## Using it Load `when/monitor/console` in your environment as early as possible. That's it. If you have no unhandled rejections, it will be silent, but when you do have them, it will report them to the console, complete with synthetic stack traces. It works in modern browsers (AMD), and in Node and RingoJS (CommonJS). ### AMD Load `when/monitor/console` early, such as using curl.js's `preloads`: ```js curl.config({ packages: [ { name: 'when', location: 'path/to/when', main: 'when' }, // ... other packages ], preloads: ['when/monitor/console'] }); curl(['my/app']); ``` ### Node/Ringo/CommonJS ```js require('when/monitor/console'); ``` ### Browserify ```js browserify -s PromiseMonitor when/monitor/console.js -o PromiseMonitor.js ``` ### PrettyMonitor for when.js and Node [PrettyMonitor](https://github.com/AriaMinaei/pretty-monitor) by [@AriaMinaei](https://github.com/AriaMinaei) is an alternative promise monitor on Node. It's built using when.js's own monitoring apis and modules, and provides a very nice visual display of unhandled rejections in Node. ## Roll your own! The monitor modules are building blocks. The [when/monitor/console](../monitor/console.js) module is one particular, and fairly simple, monitor built using the monitoring APIs and tools (PrettyMonitor is another, prettier one!). Using when/monitor/console as an example, you can build your own promise monitoring tools that look for specific types of errors, or patterns and log or display them in whatever way you need. # Upgrading to 3.0 from 2.x While there have been significant architectural changes in 3.0, it remains almost fully backward compatible. There are a few things that were deprecated and have now been removed, and functionality that has moved to a new preferred spot. ## ES5 Required 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). For more information, see the [installation docs](installation.md). ## Backward incompatible changes Previously deprecated features that have been removed in 3.0: * `promise.always` was removed. Use [`promise.finally(cleanup)`](#promisefinally) (or its ES3 alias [`promise.ensure`](#promisefinally)), or [`promise.then(cleanup, cleanup)`](#promisethen) instead. * `deferred.resolve`, `deferred.reject`, `deferred.resolver.resolve`, and `deferred.resolver.reject` no longer return promises. They always return `undefined`. You can simply return `deferred.promise` instead if you need. * [`when.all`](#whenall), [`when.any`](#whenany), and [`when.some`](#whensome) no longer directly accept `onFulfilled`, `onRejected`, and `onProgress` callbacks. Simply use the returned promise instead. * For example, do this: `when.all(array).then(handleResults)` instead of this: `when.all(array, handleResults)` * `when.isPromise` was removed. Use [`when.isPromiseLike`](#whenispromiselike) instead. ## Moved functionality Some functionality has moved to a new, preferred API. The old APIs still work, and were left in place for backward compatibility, but will eventually be removed: * `when/delay` module. Use [`promise.delay`](#promisedelay) instead. * `when/timeout` module. Use [`promise.timeout`](#promisetimeout) instead. * `when/node/function` module. Use the [`when/node`](#node-style-asynchronous-functions) module instead. * `when/unfold` and `when/unfold/list` modules. Use [`when.unfold`](#whenunfold) instead * `when/function` `lift` and `call`. Use [`when.lift`](#whenlift) and [`when.try`](#whentry) instead. * In the [browserify build](installation.md), `when.node` is now the preferred alias over `when.nodefn`. # Progress events are deprecated Progress events are now deprecated, and will be removed in a future release. They are problematic for several reasons, including: 1. They're implemented in inconsistent ways across promise libraries, making them unreliable when mixing promises. 1. They don't work in a predictable way when combining promises with `all`, `race`, `any`, etc. 1. Returning a promise from a progress handler doesn't have the expected effect of making a promise chain wait. ## Refactoring progress There is a simple alternative using `promise.tap` that can replace many usages of progress. Here's an example of the pattern using `tap` to issue progress updates. ```js var progressBar = //...; function showProgressUpdate(update) { progressBar.setValue(update); } functionThatUsesPromiseProgress(showProgressUpdate) .then(showCompletedMessage); // Accept the progress update function as an argument and use // tap() to call it with progress values function functionThatUsesPromiseProgress(notify) { return doFirstTask() .tap(function() { // `return` is optional, depending on your needs. // Returning allows notify to delay subsequent steps if it returns // a promise. If you don't want that, just call notify and discard // its return value. return notify(0.333); }) .then(doSecondTask) .tap(function() { return notify(0.667); } .then(doThirdTask) .tap(function() { return notify(1.0); }); } ``` node-when-3.7.8+ds/docs/debug-api.md000066400000000000000000000141641314733175200171420ustar00rootroot00000000000000# Debug APIs **NOTE:** This document describes APIs that provide support to external debugging tools. Do not use these APIs in normal application logic. For info and help on debugging promises in your application, see [Debugging Promises](api.md#debugging-promises). These APIs allow debugging tools to receive information about promise errors. For example, when.js's default [builtin unhandled rejection reporting](#debugging-promises) is built using these APIs, as is the long async stack trace support in [`when/monitor/console`](#whenmonitorconsole). A debugger could use them to do any number of things, such as display a list of "currently unhandled promise rejections", or send error reports to an error aggregation service. ## Global rejection events when.js >= 3.7.0 supports global `window` events in browsers, and `process` events in Node, similar to Node's `'uncaughtException'` event. This allows applications to register a handler to receive events from all promise implementations that support these global events. The events are: * `'unhandledRejection'`: fired when an unhandled rejection is detected * `'rejectionHandled'`: fired when rejection previously reported via an '`unhandledRejection'` event becomes handled ## Browser window events The following example shows how to use global `window` events in browsers to implement simple debug output. The `event` object has the following extra properties: * `event.detail.reason` - the rejection reason (typically an `Error` instance) * `event.detail.key` - opaque unique key representing the promise that was rejected. This key can be used to correlate corresponding `unhandledRejection` and `rejectionHandled` events for the same promise. ```js window.addEventListener('unhandledRejection', function(event) { // Calling preventDefault() suppresses when.js's default rejection logging // in favor of your own. event.preventDefault(); reportRejection(event.detail.reason, event.detail.key); }, false); window.addEventListener('rejectionHandled', function(event) { // Calling preventDefault() suppresses when.js's default rejection logging // in favor of your own. event.preventDefault(); reportHandled(event.detail.key); }, false); function reportRejection(error, key) { // Implement whatever logic your application requires // Log or record error state, etc. } function reportHandled(key) { // Implement whatever logic your application requires // Log that error has been handled, etc. } ``` ## Node global process events The following example shows how to use global `process` events in Node.js to implement simple debug output. The parameters passed to the `process` event handlers: * `reason` - the rejection reason (typically an `Error` instance) * `key` - opaque unique key representing the promise that was rejected. This key can be used to correlate corresponding `unhandledRejection` and `rejectionHandled` events for the same promise. ```js process.on('unhandledRejection', function(reason, key) { reportRejection(reason, key); }); process.on('rejectionHandled', function(key) { reportHandled(key); }); function reportRejection(error, key) { // Implement whatever logic your application requires // Log or record error state, etc. } function reportHandled(key) { // Implement whatever logic your application requires // Log that error has been handled, etc. } ``` ## Local when.js instance API ### Example A good example is the default implementation in `when/lib/decorators/unhandledRejection`, which logs unhandled rejections to the `console`. The following example shows how to combine `Promise.onPotentiallyUnhandledRejection` and `Promise.onPotentiallyUnhandledRejectionHandled` to implement a simple debug UI: ```js var Promise = require('when').Promise; Promise.onPotentiallyUnhandledRejection = function(rejection) { addToDebugDisplay(rejection.id, rejection.value); } Promise.onPotentiallyUnhandledRejectionHandled = function(rejection) { removeFromDebugDisplay(rejection.id); } function addToDebugDisplay(id, error) { // Add to custom debug UI here } function removeFromDebugDisplay(id) { // Remove from custom debug UI here } ``` ### Promise.onPotentiallyUnhandledRejection Called for each rejected promise that appears not to have been handled. A rejection descriptor is provided as the argument: ``` { id: value: handled: // may contain other, internal/bookkeeping fields } ``` Technically, this is called after the internal task queue has been flushed, for each rejected promise that hasn't yet been *observed*, for example by calling its `.then` or `.catch` methods. The `handled` flag is useful if your implementation of `onPotentiallyUnhandledRejection` uses `setTimeout` or another technique to delay reporting, since the rejection *may be handled* between the instant you call `setTimeout` and the instant the timeout function executes. IOW, if you use `setTimeout`, you should check `handled` to verify that the rejection is still unhandled. The default implementation in `when/lib/decorators/unhandledRejection` logs error information to `console.error` that includes the `id`. ### Promise.onPotentiallyUnhandledRejectionHandled Called when a rejection previously passed to `Promise.onPotentiallyUnhandledRejection` becomes handled, for example if it is observed later by calling its `.then` or `.catch` methods. It is passed the same rejection descriptor object as `Promise.onPotentiallyUnhandledRejection`. The `handled` field will always be `true` when a descriptor is passed to `onPotentiallyUnhandledRejectionHandled`. The default implementation in `when/lib/decorators/unhandledRejection` logs an additional message to `console.log` with the `id` indicating that the rejection has been handled. ### Promise.onFatalRejection Called when an error propagates out of a terminal [`promise.done`](#promisedone), for example, if a callback passed to `promise.done` throws an exception. The default implementation in `when/lib/decorators/unhandledRejection` throws an uncatchable exception that will be logged to `console.error` by browsers and will halt (crash) Node.js. node-when-3.7.8+ds/docs/es6-promise-shim.md000066400000000000000000000077311314733175200204160ustar00rootroot00000000000000# ES6 Promise shim 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. 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. ## Global script ```html ` 1. Or `` for minified version 1. Or `` with [when/monitor/console](api.md#debugging-promises) enabled 1. `when` will be available as `window.when` 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) 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. #### Web Worker (via browserify) Similarly to browser global environments: 1. `npm install --save when` 1. `importScripts('path/to/when/dist/browser/when.js');` 1. Or `importScripts('path/to/when/dist/browser/when.min.js');` for minified version 1. Or `importScripts('path/to/when/dist/browser/when.debug.js');` with [when/monitor/console](api.md#debugging-promises) enabled 1. `when` will be available as `self.when` 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) node-when-3.7.8+ds/function.js000066400000000000000000000073771314733175200162260ustar00rootroot00000000000000/** @license MIT License (c) copyright 2013-2014 original author or authors */ /** * Collection of helper functions for wrapping and executing 'traditional' * synchronous functions in a promise interface. * * @author Brian Cavalier * @contributor Renato Zannon */ (function(define) { define(function(require) { var when = require('./when'); var attempt = when['try']; var _liftAll = require('./lib/liftAll'); var _apply = require('./lib/apply')(when.Promise); var slice = Array.prototype.slice; return { lift: lift, liftAll: liftAll, call: attempt, apply: apply, compose: compose }; /** * Takes a function and an optional array of arguments (that might be promises), * and calls the function. The return value is a promise whose resolution * depends on the value returned by the function. * @param {function} f function to be called * @param {Array} [args] array of arguments to func * @returns {Promise} promise for the return value of func */ function apply(f, args) { // slice args just in case the caller passed an Arguments instance return _apply(f, this, args == null ? [] : slice.call(args)); } /** * Takes a 'regular' function and returns a version of that function that * returns a promise instead of a plain value, and handles thrown errors by * returning a rejected promise. Also accepts a list of arguments to be * prepended to the new function, as does Function.prototype.bind. * * The resulting function is promise-aware, in the sense that it accepts * promise arguments, and waits for their resolution. * @param {Function} f function to be bound * @param {...*} [args] arguments to be prepended for the new function @deprecated * @returns {Function} a promise-returning function */ function lift(f /*, args... */) { var args = arguments.length > 1 ? slice.call(arguments, 1) : []; return function() { return _apply(f, this, args.concat(slice.call(arguments))); }; } /** * Lift all the functions/methods on src * @param {object|function} src source whose functions will be lifted * @param {function?} combine optional function for customizing the lifting * process. It is passed dst, the lifted function, and the property name of * the original function on src. * @param {(object|function)?} dst option destination host onto which to place lifted * functions. If not provided, liftAll returns a new object. * @returns {*} If dst is provided, returns dst with lifted functions as * properties. If dst not provided, returns a new object with lifted functions. */ function liftAll(src, combine, dst) { return _liftAll(lift, combine, dst, src); } /** * Composes multiple functions by piping their return values. It is * transparent to whether the functions return 'regular' values or promises: * the piped argument is always a resolved value. If one of the functions * throws or returns a rejected promise, the composed promise will be also * rejected. * * The arguments (or promises to arguments) given to the returned function (if * any), are passed directly to the first function on the 'pipeline'. * @param {Function} f the function to which the arguments will be passed * @param {...Function} [funcs] functions that will be composed, in order * @returns {Function} a promise-returning composition of the functions */ function compose(f /*, funcs... */) { var funcs = slice.call(arguments, 1); return function() { var thisArg = this; var args = slice.call(arguments); var firstPromise = attempt.apply(thisArg, [f].concat(args)); return when.reduce(funcs, function(arg, func) { return func.call(thisArg, arg); }, firstPromise); }; } }); })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); node-when-3.7.8+ds/generator.js000066400000000000000000000050351314733175200163540ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function(require) { var when = require('./when'); var slice = Array.prototype.slice; var Promise = when.Promise; var reject = Promise.reject; /** * Lift a generator to create a function that can suspend and * resume using the `yield` keyword to await promises. * @param {function} generator * @return {function} */ function lift(generator) { return function() { return run(generator, this, arguments); }; } /** * Immediately call a generator as a promise-aware coroutine * that can suspend and resume using the `yield` keyword to * await promises. Additional arguments after the first will * be passed through to the generator. * @param {function} generator * @returns {Promise} promise for the ultimate value returned * from the generator. */ function call(generator /*x, y, z...*/) { /*jshint validthis:true*/ return run(generator, this, slice.call(arguments, 1)); } /** * Immediately apply a generator, with the supplied args array, * as a promise-aware coroutine that can suspend and resume * using the `yield` keyword to await promises. * @param {function} generator * @param {Array} args arguments with which to initialize the generator * @returns {Promise} promise for the ultimate value returned * from the generator. */ function apply(generator, args) { /*jshint validthis:true*/ return run(generator, this, args || []); } /** * Helper to initiate the provided generator as a coroutine * @returns {*} */ function run(generator, thisArg, args) { return runNext(void 0, generator.apply(thisArg, args)); } function runNext(x, iterator) { try { return handle(iterator.next(x), iterator); } catch(e) { return reject(e); } } function next(x) { /*jshint validthis:true*/ return runNext(x, this); } function error(e) { /*jshint validthis:true*/ try { return handle(this.throw(e), this); } catch(e) { return reject(e); } } function handle(result, iterator) { if(result.done) { return result.value; } var h = Promise._handler(result.value); if(h.state() > 0) { return runNext(h.value, iterator); } var p = Promise._defer(); h.chain(p._handler, iterator, next, error); return p; } return { lift: lift, call: call, apply: apply }; }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/guard.js000066400000000000000000000035521314733175200154720ustar00rootroot00000000000000/** @license MIT License (c) copyright 2011-2013 original author or authors */ /** * Generalized promise concurrency guard * Adapted from original concept by Sakari Jokinen (Rocket Pack, Ltd.) * * @author Brian Cavalier * @author John Hann * @contributor Sakari Jokinen */ (function(define) { define(function(require) { var when = require('./when'); var slice = Array.prototype.slice; guard.n = n; return guard; /** * Creates a guarded version of f that can only be entered when the supplied * condition allows. * @param {function} condition represents a critical section that may only * be entered when allowed by the condition * @param {function} f function to guard * @returns {function} guarded version of f */ function guard(condition, f) { return function() { var args = slice.call(arguments); return when(condition()).withThis(this).then(function(exit) { return when(f.apply(this, args))['finally'](exit); }); }; } /** * Creates a condition that allows only n simultaneous executions * of a guarded function * @param {number} allowed number of allowed simultaneous executions * @returns {function} condition function which returns a promise that * fulfills when the critical section may be entered. The fulfillment * value is a function ("notifyExit") that must be called when the critical * section has been exited. */ function n(allowed) { var count = 0; var waiting = []; return function enter() { return when.promise(function(resolve) { if(count < allowed) { resolve(exit); } else { waiting.push(resolve); } count += 1; }); }; function exit() { count = Math.max(count - 1, 0); if(waiting.length > 0) { waiting.shift()(exit); } } } }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/keys.js000066400000000000000000000055561314733175200153510ustar00rootroot00000000000000/** @license MIT License (c) copyright 2011-2013 original author or authors */ /** * Licensed under the MIT License at: * http://www.opensource.org/licenses/mit-license.php * * @author Brian Cavalier * @author John Hann */ (function(define) { 'use strict'; define(function(require) { var when = require('./when'); var Promise = when.Promise; var toPromise = when.resolve; return { all: when.lift(all), map: map, settle: settle }; /** * Resolve all the key-value pairs in the supplied object or promise * for an object. * @param {Promise|object} object or promise for object whose key-value pairs * will be resolved * @returns {Promise} promise for an object with the fully resolved key-value pairs */ function all(object) { var p = Promise._defer(); var resolver = Promise._handler(p); var results = {}; var keys = Object.keys(object); var pending = keys.length; for(var i=0, k; i>>0; var pending = l; var errors = []; for (var h, x, i = 0; i < l; ++i) { x = promises[i]; if(x === void 0 && !(i in promises)) { --pending; continue; } h = Promise._handler(x); if(h.state() > 0) { resolver.become(h); Promise._visitRemaining(promises, i, h); break; } else { h.visit(resolver, handleFulfill, handleReject); } } if(pending === 0) { resolver.reject(new RangeError('any(): array must not be empty')); } return p; function handleFulfill(x) { /*jshint validthis:true*/ errors = null; this.resolve(x); // this === resolver } function handleReject(e) { /*jshint validthis:true*/ if(this.resolved) { // this === resolver return; } errors.push(e); if(--pending === 0) { this.reject(errors); } } } /** * N-winner competitive race * Return a promise that will fulfill when n input promises have * fulfilled, or will reject when it becomes impossible for n * input promises to fulfill (ie when promises.length - n + 1 * have rejected) * @param {array} promises * @param {number} n * @returns {Promise} promise for the earliest n fulfillment values * * @deprecated */ function some(promises, n) { /*jshint maxcomplexity:7*/ var p = Promise._defer(); var resolver = p._handler; var results = []; var errors = []; var l = promises.length>>>0; var nFulfill = 0; var nReject; var x, i; // reused in both for() loops // First pass: count actual array items for(i=0; i nFulfill) { resolver.reject(new RangeError('some(): array must contain at least ' + n + ' item(s), but had ' + nFulfill)); } else if(nFulfill === 0) { resolver.resolve(results); } // Second pass: observe each array item, make progress toward goals for(i=0; i 2 ? ar.call(promises, liftCombine(f), arguments[2]) : ar.call(promises, liftCombine(f)); } /** * Traditional reduce function, similar to `Array.prototype.reduceRight()`, but * input may contain promises and/or values, and reduceFunc * may return either a value or a promise, *and* initialValue may * be a promise for the starting value. * @param {Array|Promise} promises array or promise for an array of anything, * may contain a mix of promises and values. * @param {function(accumulated:*, x:*, index:Number):*} f reduce function * @returns {Promise} that will resolve to the final reduced value */ function reduceRight(promises, f /*, initialValue */) { return arguments.length > 2 ? arr.call(promises, liftCombine(f), arguments[2]) : arr.call(promises, liftCombine(f)); } function liftCombine(f) { return function(z, x, i) { return applyFold(f, void 0, [z,x,i]); }; } }; }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/lib/decorators/flow.js000066400000000000000000000112661314733175200202530ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function() { return function flow(Promise) { var resolve = Promise.resolve; var reject = Promise.reject; var origCatch = Promise.prototype['catch']; /** * Handle the ultimate fulfillment value or rejection reason, and assume * responsibility for all errors. If an error propagates out of result * or handleFatalError, it will be rethrown to the host, resulting in a * loud stack track on most platforms and a crash on some. * @param {function?} onResult * @param {function?} onError * @returns {undefined} */ Promise.prototype.done = function(onResult, onError) { this._handler.visit(this._handler.receiver, onResult, onError); }; /** * Add Error-type and predicate matching to catch. Examples: * promise.catch(TypeError, handleTypeError) * .catch(predicate, handleMatchedErrors) * .catch(handleRemainingErrors) * @param onRejected * @returns {*} */ Promise.prototype['catch'] = Promise.prototype.otherwise = function(onRejected) { if (arguments.length < 2) { return origCatch.call(this, onRejected); } if(typeof onRejected !== 'function') { return this.ensure(rejectInvalidPredicate); } return origCatch.call(this, createCatchFilter(arguments[1], onRejected)); }; /** * Wraps the provided catch handler, so that it will only be called * if the predicate evaluates truthy * @param {?function} handler * @param {function} predicate * @returns {function} conditional catch handler */ function createCatchFilter(handler, predicate) { return function(e) { return evaluatePredicate(e, predicate) ? handler.call(this, e) : reject(e); }; } /** * Ensures that onFulfilledOrRejected will be called regardless of whether * this promise is fulfilled or rejected. onFulfilledOrRejected WILL NOT * receive the promises' value or reason. Any returned value will be disregarded. * onFulfilledOrRejected may throw or return a rejected promise to signal * an additional error. * @param {function} handler handler to be called regardless of * fulfillment or rejection * @returns {Promise} */ Promise.prototype['finally'] = Promise.prototype.ensure = function(handler) { if(typeof handler !== 'function') { return this; } return this.then(function(x) { return runSideEffect(handler, this, identity, x); }, function(e) { return runSideEffect(handler, this, reject, e); }); }; function runSideEffect (handler, thisArg, propagate, value) { var result = handler.call(thisArg); return maybeThenable(result) ? propagateValue(result, propagate, value) : propagate(value); } function propagateValue (result, propagate, x) { return resolve(result).then(function () { return propagate(x); }); } /** * Recover from a failure by returning a defaultValue. If defaultValue * is a promise, it's fulfillment value will be used. If defaultValue is * a promise that rejects, the returned promise will reject with the * same reason. * @param {*} defaultValue * @returns {Promise} new promise */ Promise.prototype['else'] = Promise.prototype.orElse = function(defaultValue) { return this.then(void 0, function() { return defaultValue; }); }; /** * Shortcut for .then(function() { return value; }) * @param {*} value * @return {Promise} a promise that: * - is fulfilled if value is not a promise, or * - if value is a promise, will fulfill with its value, or reject * with its reason. */ Promise.prototype['yield'] = function(value) { return this.then(function() { return value; }); }; /** * Runs a side effect when this promise fulfills, without changing the * fulfillment value. * @param {function} onFulfilledSideEffect * @returns {Promise} */ Promise.prototype.tap = function(onFulfilledSideEffect) { return this.then(onFulfilledSideEffect)['yield'](this); }; return Promise; }; function rejectInvalidPredicate() { throw new TypeError('catch predicate must be a function'); } function evaluatePredicate(e, predicate) { return isError(predicate) ? e instanceof predicate : predicate(e); } function isError(predicate) { return predicate === Error || (predicate != null && predicate.prototype instanceof Error); } function maybeThenable(x) { return (typeof x === 'object' || typeof x === 'function') && x !== null; } function identity(x) { return x; } }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); })); node-when-3.7.8+ds/lib/decorators/fold.js000066400000000000000000000012731314733175200202250ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ /** @author Jeff Escalante */ (function(define) { 'use strict'; define(function() { return function fold(Promise) { Promise.prototype.fold = function(f, z) { var promise = this._beget(); this._handler.fold(function(z, x, to) { Promise._handler(z).fold(function(x, z, to) { to.resolve(f.call(this, z, x)); }, x, this, to); }, z, promise._handler.receiver, promise._handler); return promise; }; return Promise; }; }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); })); node-when-3.7.8+ds/lib/decorators/inspect.js000066400000000000000000000010051314733175200207370ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function(require) { var inspect = require('../state').inspect; return function inspection(Promise) { Promise.prototype.inspect = function() { return inspect(Promise._handler(this)); }; return Promise; }; }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/lib/decorators/iterate.js000066400000000000000000000044071314733175200207400ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function() { return function generate(Promise) { var resolve = Promise.resolve; Promise.iterate = iterate; Promise.unfold = unfold; return Promise; /** * @deprecated Use github.com/cujojs/most streams and most.iterate * Generate a (potentially infinite) stream of promised values: * x, f(x), f(f(x)), etc. until condition(x) returns true * @param {function} f function to generate a new x from the previous x * @param {function} condition function that, given the current x, returns * truthy when the iterate should stop * @param {function} handler function to handle the value produced by f * @param {*|Promise} x starting value, may be a promise * @return {Promise} the result of the last call to f before * condition returns true */ function iterate(f, condition, handler, x) { return unfold(function(x) { return [x, f(x)]; }, condition, handler, x); } /** * @deprecated Use github.com/cujojs/most streams and most.unfold * Generate a (potentially infinite) stream of promised values * by applying handler(generator(seed)) iteratively until * condition(seed) returns true. * @param {function} unspool function that generates a [value, newSeed] * given a seed. * @param {function} condition function that, given the current seed, returns * truthy when the unfold should stop * @param {function} handler function to handle the value produced by unspool * @param x {*|Promise} starting value, may be a promise * @return {Promise} the result of the last value produced by unspool before * condition returns true */ function unfold(unspool, condition, handler, x) { return resolve(x).then(function(seed) { return resolve(condition(seed)).then(function(done) { return done ? seed : resolve(unspool(seed)).spread(next); }); }); function next(item, newSeed) { return resolve(handler(item)).then(function() { return unfold(unspool, condition, handler, newSeed); }); } } }; }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); })); node-when-3.7.8+ds/lib/decorators/progress.js000066400000000000000000000011421314733175200211400ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function() { return function progress(Promise) { /** * @deprecated * Register a progress handler for this promise * @param {function} onProgress * @returns {Promise} */ Promise.prototype.progress = function(onProgress) { return this.then(void 0, void 0, onProgress); }; return Promise; }; }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); })); node-when-3.7.8+ds/lib/decorators/timed.js000066400000000000000000000036231314733175200204040ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function(require) { var env = require('../env'); var TimeoutError = require('../TimeoutError'); function setTimeout(f, ms, x, y) { return env.setTimer(function() { f(x, y, ms); }, ms); } return function timed(Promise) { /** * Return a new promise whose fulfillment value is revealed only * after ms milliseconds * @param {number} ms milliseconds * @returns {Promise} */ Promise.prototype.delay = function(ms) { var p = this._beget(); this._handler.fold(handleDelay, ms, void 0, p._handler); return p; }; function handleDelay(ms, x, h) { setTimeout(resolveDelay, ms, x, h); } function resolveDelay(x, h) { h.resolve(x); } /** * Return a new promise that rejects after ms milliseconds unless * this promise fulfills earlier, in which case the returned promise * fulfills with the same value. * @param {number} ms milliseconds * @param {Error|*=} reason optional rejection reason to use, defaults * to a TimeoutError if not provided * @returns {Promise} */ Promise.prototype.timeout = function(ms, reason) { var p = this._beget(); var h = p._handler; var t = setTimeout(onTimeout, ms, reason, p._handler); this._handler.visit(h, function onFulfill(x) { env.clearTimer(t); this.resolve(x); // this = h }, function onReject(x) { env.clearTimer(t); this.reject(x); // this = h }, h.notify); return p; }; function onTimeout(reason, h, ms) { var e = typeof reason === 'undefined' ? new TimeoutError('timed out after ' + ms + 'ms') : reason; h.reject(e); } return Promise; }; }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/lib/decorators/unhandledRejection.js000066400000000000000000000041601314733175200231040ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function(require) { var setTimer = require('../env').setTimer; var format = require('../format'); return function unhandledRejection(Promise) { var logError = noop; var logInfo = noop; var localConsole; if(typeof console !== 'undefined') { // Alias console to prevent things like uglify's drop_console option from // removing console.log/error. Unhandled rejections fall into the same // category as uncaught exceptions, and build tools shouldn't silence them. localConsole = console; logError = typeof localConsole.error !== 'undefined' ? function (e) { localConsole.error(e); } : function (e) { localConsole.log(e); }; logInfo = typeof localConsole.info !== 'undefined' ? function (e) { localConsole.info(e); } : function (e) { localConsole.log(e); }; } Promise.onPotentiallyUnhandledRejection = function(rejection) { enqueue(report, rejection); }; Promise.onPotentiallyUnhandledRejectionHandled = function(rejection) { enqueue(unreport, rejection); }; Promise.onFatalRejection = function(rejection) { enqueue(throwit, rejection.value); }; var tasks = []; var reported = []; var running = null; function report(r) { if(!r.handled) { reported.push(r); logError('Potentially unhandled rejection [' + r.id + '] ' + format.formatError(r.value)); } } function unreport(r) { var i = reported.indexOf(r); if(i >= 0) { reported.splice(i, 1); logInfo('Handled previous rejection [' + r.id + '] ' + format.formatObject(r.value)); } } function enqueue(f, x) { tasks.push(f, x); if(running === null) { running = setTimer(flush, 0); } } function flush() { running = null; while(tasks.length > 0) { tasks.shift()(tasks.shift()); } } return Promise; }; function throwit(e) { throw e; } function noop() {} }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/lib/decorators/with.js000066400000000000000000000024721314733175200202560ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function() { return function addWith(Promise) { /** * Returns a promise whose handlers will be called with `this` set to * the supplied receiver. Subsequent promises derived from the * returned promise will also have their handlers called with receiver * as `this`. Calling `with` with undefined or no arguments will return * a promise whose handlers will again be called in the usual Promises/A+ * way (no `this`) thus safely undoing any previous `with` in the * promise chain. * * WARNING: Promises returned from `with`/`withThis` are NOT Promises/A+ * compliant, specifically violating 2.2.5 (http://promisesaplus.com/#point-41) * * @param {object} receiver `this` value for all handlers attached to * the returned promise. * @returns {Promise} */ Promise.prototype['with'] = Promise.prototype.withThis = function(receiver) { var p = this._beget(); var child = p._handler; child.receiver = receiver; this._handler.chain(child, receiver); return p; }; return Promise; }; }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); })); node-when-3.7.8+ds/lib/env.js000066400000000000000000000041771314733175200157320ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ /*global process,document,setTimeout,clearTimeout,MutationObserver,WebKitMutationObserver*/ (function(define) { 'use strict'; define(function(require) { /*jshint maxcomplexity:6*/ // Sniff "best" async scheduling option // Prefer process.nextTick or MutationObserver, then check for // setTimeout, and finally vertx, since its the only env that doesn't // have setTimeout var MutationObs; var capturedSetTimeout = typeof setTimeout !== 'undefined' && setTimeout; // Default env var setTimer = function(f, ms) { return setTimeout(f, ms); }; var clearTimer = function(t) { return clearTimeout(t); }; var asap = function (f) { return capturedSetTimeout(f, 0); }; // Detect specific env if (isNode()) { // Node asap = function (f) { return process.nextTick(f); }; } else if (MutationObs = hasMutationObserver()) { // Modern browser asap = initMutationObserver(MutationObs); } else if (!capturedSetTimeout) { // vert.x var vertxRequire = require; var vertx = vertxRequire('vertx'); setTimer = function (f, ms) { return vertx.setTimer(ms, f); }; clearTimer = vertx.cancelTimer; asap = vertx.runOnLoop || vertx.runOnContext; } return { setTimer: setTimer, clearTimer: clearTimer, asap: asap }; function isNode () { return typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]'; } function hasMutationObserver () { return (typeof MutationObserver !== 'undefined' && MutationObserver) || (typeof WebKitMutationObserver !== 'undefined' && WebKitMutationObserver); } function initMutationObserver(MutationObserver) { var scheduled; var node = document.createTextNode(''); var o = new MutationObserver(run); o.observe(node, { characterData: true }); function run() { var f = scheduled; scheduled = void 0; f(); } var i = 0; return function (f) { scheduled = f; node.data = (i ^= 1); }; } }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/lib/format.js000066400000000000000000000030431314733175200164210ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function() { return { formatError: formatError, formatObject: formatObject, tryStringify: tryStringify }; /** * Format an error into a string. If e is an Error and has a stack property, * it's returned. Otherwise, e is formatted using formatObject, with a * warning added about e not being a proper Error. * @param {*} e * @returns {String} formatted string, suitable for output to developers */ function formatError(e) { var s = typeof e === 'object' && e !== null && (e.stack || e.message) ? e.stack || e.message : formatObject(e); return e instanceof Error ? s : s + ' (WARNING: non-Error used)'; } /** * Format an object, detecting "plain" objects and running them through * JSON.stringify if possible. * @param {Object} o * @returns {string} */ function formatObject(o) { var s = String(o); if(s === '[object Object]' && typeof JSON !== 'undefined') { s = tryStringify(o, s); } return s; } /** * Try to return the result of JSON.stringify(x). If that fails, return * defaultValue * @param {*} x * @param {*} defaultValue * @returns {String|*} JSON.stringify(x) or defaultValue */ function tryStringify(x, defaultValue) { try { return JSON.stringify(x); } catch(e) { return defaultValue; } } }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); })); node-when-3.7.8+ds/lib/liftAll.js000066400000000000000000000014471314733175200165260ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function() { return function liftAll(liftOne, combine, dst, src) { if(typeof combine === 'undefined') { combine = defaultCombine; } return Object.keys(src).reduce(function(dst, key) { var f = src[key]; return typeof f === 'function' ? combine(dst, liftOne(f), key) : dst; }, typeof dst === 'undefined' ? defaultDst(src) : dst); }; function defaultCombine(o, f, k) { o[k] = f; return o; } function defaultDst(src) { return typeof src === 'function' ? src.bind() : Object.create(src); } }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); })); node-when-3.7.8+ds/lib/makePromise.js000066400000000000000000000553251314733175200174170ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function() { return function makePromise(environment) { var tasks = environment.scheduler; var emitRejection = initEmitRejection(); var objectCreate = Object.create || function(proto) { function Child() {} Child.prototype = proto; return new Child(); }; /** * Create a promise whose fate is determined by resolver * @constructor * @returns {Promise} promise * @name Promise */ function Promise(resolver, handler) { this._handler = resolver === Handler ? handler : init(resolver); } /** * Run the supplied resolver * @param resolver * @returns {Pending} */ function init(resolver) { var handler = new Pending(); try { resolver(promiseResolve, promiseReject, promiseNotify); } catch (e) { promiseReject(e); } return handler; /** * Transition from pre-resolution state to post-resolution state, notifying * all listeners of the ultimate fulfillment or rejection * @param {*} x resolution value */ function promiseResolve (x) { handler.resolve(x); } /** * Reject this promise with reason, which will be used verbatim * @param {Error|*} reason rejection reason, strongly suggested * to be an Error type */ function promiseReject (reason) { handler.reject(reason); } /** * @deprecated * Issue a progress event, notifying all progress listeners * @param {*} x progress event payload to pass to all listeners */ function promiseNotify (x) { handler.notify(x); } } // Creation Promise.resolve = resolve; Promise.reject = reject; Promise.never = never; Promise._defer = defer; Promise._handler = getHandler; /** * Returns a trusted promise. If x is already a trusted promise, it is * returned, otherwise returns a new trusted Promise which follows x. * @param {*} x * @return {Promise} promise */ function resolve(x) { return isPromise(x) ? x : new Promise(Handler, new Async(getHandler(x))); } /** * Return a reject promise with x as its reason (x is used verbatim) * @param {*} x * @returns {Promise} rejected promise */ function reject(x) { return new Promise(Handler, new Async(new Rejected(x))); } /** * Return a promise that remains pending forever * @returns {Promise} forever-pending promise. */ function never() { return foreverPendingPromise; // Should be frozen } /** * Creates an internal {promise, resolver} pair * @private * @returns {Promise} */ function defer() { return new Promise(Handler, new Pending()); } // Transformation and flow control /** * Transform this promise's fulfillment value, returning a new Promise * for the transformed result. If the promise cannot be fulfilled, onRejected * is called with the reason. onProgress *may* be called with updates toward * this promise's fulfillment. * @param {function=} onFulfilled fulfillment handler * @param {function=} onRejected rejection handler * @param {function=} onProgress @deprecated progress handler * @return {Promise} new promise */ Promise.prototype.then = function(onFulfilled, onRejected, onProgress) { var parent = this._handler; var state = parent.join().state(); if ((typeof onFulfilled !== 'function' && state > 0) || (typeof onRejected !== 'function' && state < 0)) { // Short circuit: value will not change, simply share handler return new this.constructor(Handler, parent); } var p = this._beget(); var child = p._handler; parent.chain(child, parent.receiver, onFulfilled, onRejected, onProgress); return p; }; /** * If this promise cannot be fulfilled due to an error, call onRejected to * handle the error. Shortcut for .then(undefined, onRejected) * @param {function?} onRejected * @return {Promise} */ Promise.prototype['catch'] = function(onRejected) { return this.then(void 0, onRejected); }; /** * Creates a new, pending promise of the same type as this promise * @private * @returns {Promise} */ Promise.prototype._beget = function() { return begetFrom(this._handler, this.constructor); }; function begetFrom(parent, Promise) { var child = new Pending(parent.receiver, parent.join().context); return new Promise(Handler, child); } // Array combinators Promise.all = all; Promise.race = race; Promise._traverse = traverse; /** * Return a promise that will fulfill when all promises in the * input array have fulfilled, or will reject when one of the * promises rejects. * @param {array} promises array of promises * @returns {Promise} promise for array of fulfillment values */ function all(promises) { return traverseWith(snd, null, promises); } /** * Array> -> Promise> * @private * @param {function} f function to apply to each promise's value * @param {Array} promises array of promises * @returns {Promise} promise for transformed values */ function traverse(f, promises) { return traverseWith(tryCatch2, f, promises); } function traverseWith(tryMap, f, promises) { var handler = typeof f === 'function' ? mapAt : settleAt; var resolver = new Pending(); var pending = promises.length >>> 0; var results = new Array(pending); for (var i = 0, x; i < promises.length && !resolver.resolved; ++i) { x = promises[i]; if (x === void 0 && !(i in promises)) { --pending; continue; } traverseAt(promises, handler, i, x, resolver); } if(pending === 0) { resolver.become(new Fulfilled(results)); } return new Promise(Handler, resolver); function mapAt(i, x, resolver) { if(!resolver.resolved) { traverseAt(promises, settleAt, i, tryMap(f, x, i), resolver); } } function settleAt(i, x, resolver) { results[i] = x; if(--pending === 0) { resolver.become(new Fulfilled(results)); } } } function traverseAt(promises, handler, i, x, resolver) { if (maybeThenable(x)) { var h = getHandlerMaybeThenable(x); var s = h.state(); if (s === 0) { h.fold(handler, i, void 0, resolver); } else if (s > 0) { handler(i, h.value, resolver); } else { resolver.become(h); visitRemaining(promises, i+1, h); } } else { handler(i, x, resolver); } } Promise._visitRemaining = visitRemaining; function visitRemaining(promises, start, handler) { for(var i=start; i 0 ? toFulfilledState(handler.value) : toRejectedState(handler.value); } }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); })); node-when-3.7.8+ds/monitor.js000066400000000000000000000011021314733175200160440ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function(require) { var PromiseMonitor = require('./monitor/PromiseMonitor'); var ConsoleReporter = require('./monitor/ConsoleReporter'); var promiseMonitor = new PromiseMonitor(new ConsoleReporter()); return function(Promise) { return promiseMonitor.monitor(Promise); }; }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/monitor/000077500000000000000000000000001314733175200155145ustar00rootroot00000000000000node-when-3.7.8+ds/monitor/ConsoleReporter.js000066400000000000000000000055611314733175200212060ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function(require) { var error = require('./error'); var unhandledRejectionsMsg = '[promises] Unhandled rejections: '; var allHandledMsg = '[promises] All previously unhandled rejections have now been handled'; function ConsoleReporter() { this._previouslyReported = false; } ConsoleReporter.prototype = initDefaultLogging(); ConsoleReporter.prototype.log = function(traces) { if(traces.length === 0) { if(this._previouslyReported) { this._previouslyReported = false; this.msg(allHandledMsg); } return; } this._previouslyReported = true; this.groupStart(unhandledRejectionsMsg + traces.length); try { this._log(traces); } finally { this.groupEnd(); } }; ConsoleReporter.prototype._log = function(traces) { for(var i=0; i= 0; --i) { t = this._traces[i]; if(t.handler === handler) { break; } } if(i >= 0) { t.extraContext = extraContext; } else { this._traces.push({ handler: handler, extraContext: extraContext }); } this.logTraces(); }; PromiseMonitor.prototype.removeTrace = function(/*handler*/) { this.logTraces(); }; PromiseMonitor.prototype.fatal = function(handler, extraContext) { var err = new Error(); err.stack = this._createLongTrace(handler.value, handler.context, extraContext).join('\n'); setTimer(function() { throw err; }, 0); }; PromiseMonitor.prototype.logTraces = function() { if(!this._traceTask) { this._traceTask = setTimer(this._doLogTraces, this.logDelay); } }; PromiseMonitor.prototype._logTraces = function() { this._traceTask = void 0; this._traces = this._traces.filter(filterHandled); this._reporter.log(this.formatTraces(this._traces)); }; PromiseMonitor.prototype.formatTraces = function(traces) { return traces.map(function(t) { return this._createLongTrace(t.handler.value, t.handler.context, t.extraContext); }, this); }; PromiseMonitor.prototype._createLongTrace = function(e, context, extraContext) { var trace = error.parse(e) || [String(e) + ' (WARNING: non-Error used)']; trace = filterFrames(this.stackFilter, trace, 0); this._appendContext(trace, context); this._appendContext(trace, extraContext); return this.filterDuplicateFrames ? this._removeDuplicates(trace) : trace; }; PromiseMonitor.prototype._removeDuplicates = function(trace) { var seen = {}; var sep = this.stackJumpSeparator; var count = 0; return trace.reduceRight(function(deduped, line, i) { if(i === 0) { deduped.unshift(line); } else if(line === sep) { if(count > 0) { deduped.unshift(line); count = 0; } } else if(!seen[line]) { seen[line] = true; deduped.unshift(line); ++count; } return deduped; }, []); }; PromiseMonitor.prototype._appendContext = function(trace, context) { trace.push.apply(trace, this._createTrace(context)); }; PromiseMonitor.prototype._createTrace = function(traceChain) { var trace = []; var stack; while(traceChain) { stack = error.parse(traceChain); if (stack) { stack = filterFrames(this.stackFilter, stack); appendStack(trace, stack, this.stackJumpSeparator); } traceChain = traceChain.parent; } return trace; }; function appendStack(trace, stack, separator) { if (stack.length > 1) { stack[0] = separator; trace.push.apply(trace, stack); } } function filterFrames(stackFilter, stack) { return stack.filter(function(frame) { return !stackFilter.test(frame); }); } function filterHandled(t) { return !t.handler.handled; } return PromiseMonitor; }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/monitor/README.md000066400000000000000000000002631314733175200167740ustar00rootroot00000000000000# Promise monitoring and debugging This dir contains experimental new promise monitoring and debugging utilities for when.js. See [the docs](../docs/api.md#debugging-promises). node-when-3.7.8+ds/monitor/console.js000066400000000000000000000006521314733175200175170ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function(require) { var monitor = require('../monitor'); var Promise = require('../when').Promise; return monitor(Promise); }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/monitor/error.js000066400000000000000000000034201314733175200172020ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** @author Brian Cavalier */ /** @author John Hann */ (function(define) { 'use strict'; define(function() { var parse, captureStack, format; if(Error.captureStackTrace) { // Use Error.captureStackTrace if available parse = function(e) { return e && e.stack && e.stack.split('\n'); }; format = formatAsString; captureStack = Error.captureStackTrace; } else { // Otherwise, do minimal feature detection to determine // how to capture and format reasonable stacks. parse = function(e) { var stack = e && e.stack && e.stack.split('\n'); if(stack && e.message) { stack.unshift(e.message); } return stack; }; (function() { var e = new Error(); if(typeof e.stack !== 'string') { format = formatAsString; captureStack = captureSpiderMonkeyStack; } else { format = formatAsErrorWithStack; captureStack = useStackDirectly; } }()); } function captureSpiderMonkeyStack(host) { try { throw new Error(); } catch(err) { host.stack = err.stack; } } function useStackDirectly(host) { host.stack = new Error().stack; } function formatAsString(longTrace) { return join(longTrace); } function formatAsErrorWithStack(longTrace) { var e = new Error(); e.stack = formatAsString(longTrace); return e; } // About 5-10x faster than String.prototype.join o_O function join(a) { var sep = false; var s = ''; for(var i=0; i< a.length; ++i) { if(sep) { s += '\n' + a[i]; } else { s+= a[i]; sep = true; } } return s; } return { parse: parse, format: format, captureStack: captureStack }; }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(); })); node-when-3.7.8+ds/node.js000066400000000000000000000203051314733175200153100ustar00rootroot00000000000000/** @license MIT License (c) copyright 2013 original author or authors */ /** * Collection of helpers for interfacing with node-style asynchronous functions * using promises. * * @author Brian Cavalier * @contributor Renato Zannon */ (function(define) { define(function(require) { var when = require('./when'); var _liftAll = require('./lib/liftAll'); var setTimer = require('./lib/env').setTimer; var slice = Array.prototype.slice; var _apply = require('./lib/apply')(when.Promise, dispatch); return { lift: lift, liftAll: liftAll, apply: apply, call: call, createCallback: createCallback, bindCallback: bindCallback, liftCallback: liftCallback }; /** * Takes a node-style async function and calls it immediately (with an optional * array of arguments or promises for arguments). It returns a promise whose * resolution depends on whether the async functions calls its callback with the * conventional error argument or not. * * With this it becomes possible to leverage existing APIs while still reaping * the benefits of promises. * * @example * function onlySmallNumbers(n, callback) { * if(n < 10) { * callback(null, n + 10); * } else { * callback(new Error("Calculation failed")); * } * } * * var nodefn = require("when/node/function"); * * // Logs '15' * nodefn.apply(onlySmallNumbers, [5]).then(console.log, console.error); * * // Logs 'Calculation failed' * nodefn.apply(onlySmallNumbers, [15]).then(console.log, console.error); * * @param {function} f node-style function that will be called * @param {Array} [args] array of arguments to func * @returns {Promise} promise for the value func passes to its callback */ function apply(f, args) { return _apply(f, this, args || []); } function dispatch(f, thisArg, args, h) { var cb = createCallback(h); try { switch(args.length) { case 2: f.call(thisArg, args[0], args[1], cb); break; case 1: f.call(thisArg, args[0], cb); break; case 0: f.call(thisArg, cb); break; default: args.push(cb); f.apply(thisArg, args); } } catch(e) { h.reject(e); } } /** * Has the same behavior that {@link apply} has, with the difference that the * arguments to the function are provided individually, while {@link apply} accepts * a single array. * * @example * function sumSmallNumbers(x, y, callback) { * var result = x + y; * if(result < 10) { * callback(null, result); * } else { * callback(new Error("Calculation failed")); * } * } * * // Logs '5' * nodefn.call(sumSmallNumbers, 2, 3).then(console.log, console.error); * * // Logs 'Calculation failed' * nodefn.call(sumSmallNumbers, 5, 10).then(console.log, console.error); * * @param {function} f node-style function that will be called * @param {...*} [args] arguments that will be forwarded to the function * @returns {Promise} promise for the value func passes to its callback */ function call(f /*, args... */) { return _apply(f, this, slice.call(arguments, 1)); } /** * Takes a node-style function and returns new function that wraps the * original and, instead of taking a callback, returns a promise. Also, it * knows how to handle promises given as arguments, waiting for their * resolution before executing. * * Upon execution, the orginal function is executed as well. If it passes * a truthy value as the first argument to the callback, it will be * interpreted as an error condition, and the promise will be rejected * with it. Otherwise, the call is considered a resolution, and the promise * is resolved with the callback's second argument. * * @example * var fs = require("fs"), nodefn = require("when/node/function"); * * var promiseRead = nodefn.lift(fs.readFile); * * // The promise is resolved with the contents of the file if everything * // goes ok * promiseRead('exists.txt').then(console.log, console.error); * * // And will be rejected if something doesn't work out * // (e.g. the files does not exist) * promiseRead('doesnt_exist.txt').then(console.log, console.error); * * * @param {Function} f node-style function to be lifted * @param {...*} [args] arguments to be prepended for the new function @deprecated * @returns {Function} a promise-returning function */ function lift(f /*, args... */) { var args1 = arguments.length > 1 ? slice.call(arguments, 1) : []; return function() { // TODO: Simplify once partialing has been removed var l = args1.length; var al = arguments.length; var args = new Array(al + l); var i; for(i=0; i 2) { resolver.resolve(slice.call(arguments, 1)); } else { resolver.resolve(value); } }; } /** * Attaches a node-style callback to a promise, ensuring the callback is * called for either fulfillment or rejection. Returns a promise with the same * state as the passed-in promise. * * @example * var deferred = when.defer(); * * function callback(err, value) { * // Handle err or use value * } * * bindCallback(deferred.promise, callback); * * deferred.resolve('interesting value'); * * @param {Promise} promise The promise to be attached to. * @param {Function} callback The node-style callback to attach. * @returns {Promise} A promise with the same state as the passed-in promise. */ function bindCallback(promise, callback) { promise = when(promise); if (callback) { promise.then(success, wrapped); } return promise; function success(value) { wrapped(null, value); } function wrapped(err, value) { setTimer(function () { callback(err, value); }, 0); } } /** * Takes a node-style callback and returns new function that accepts a * promise, calling the original callback when the promise is either * fulfilled or rejected with the appropriate arguments. * * @example * var deferred = when.defer(); * * function callback(err, value) { * // Handle err or use value * } * * var wrapped = liftCallback(callback); * * // `wrapped` can now be passed around at will * wrapped(deferred.promise); * * deferred.resolve('interesting value'); * * @param {Function} callback The node-style callback to wrap. * @returns {Function} The lifted, promise-accepting function. */ function liftCallback(callback) { return function(promise) { return bindCallback(promise, callback); }; } }); })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); node-when-3.7.8+ds/node/000077500000000000000000000000001314733175200147525ustar00rootroot00000000000000node-when-3.7.8+ds/node/function.js000066400000000000000000000005461314733175200171420ustar00rootroot00000000000000/** @license MIT License (c) copyright 2013 original author or authors */ /** * @author Brian Cavalier */ (function(define) { 'use strict'; define(function(require) { // DEPRECATED: Use when/node instead return require('../node'); }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/package.json000066400000000000000000000056651314733175200163270ustar00rootroot00000000000000{ "name": "when", "version": "3.7.8", "description": "A lightweight Promises/A+ and when() implementation, plus other async goodies.", "keywords": [ "cujo", "Promises/A+", "promises-aplus", "promise", "promises", "deferred", "deferreds", "when", "async", "asynchronous", "ender" ], "homepage": "http://cujojs.com", "license": "MIT", "repository": { "type": "git", "url": "https://github.com/cujojs/when" }, "bugs": "https://github.com/cujojs/when/issues", "maintainers": [ { "name": "Brian Cavalier", "web": "http://hovercraftstudios.com" }, { "name": "John Hann", "web": "http://unscriptable.com" } ], "contributors": [ { "name": "Brian Cavalier", "web": "http://hovercraftstudios.com" }, { "name": "John Hann", "web": "http://unscriptable.com" }, { "name": "Scott Andrews" } ], "devDependencies": { "benchmark": "~1", "browserify": "~2", "buster": "~0.7", "exorcist": "~0.4", "glob": "^7.1.1", "jshint": "~2", "json5": "~0.2", "microtime": "~2", "mkdirp": "^0.5.1", "optimist": "~0.6", "poly": "^0.6.1", "promises-aplus-tests": "~2", "rest": "1.1.x", "sauce-connect-launcher": "~0.4", "uglify-js": "~2", "wd": "~0.2" }, "main": "when.js", "ender": { "files": [ "*.js", "lib/*.js", "node/*.js", "unfold/*.js", "monitor/*.js", "lib/decorators/*.js" ] }, "browser": { "when": "./dist/browser/when.js", "vertx": false }, "directories": { "test": "test" }, "scripts": { "test": "jshint . && buster-test -e node && promises-aplus-tests test/promises-aplus-adapter.js", "build-browser-test": "browserify ./node_modules/poly/es5.js -o test/browser/es5.js && node scripts/browserify-tests", "browser-test": "npm run build-browser-test && buster-static -e browser -p 8080", "ci": "npm test && node test/sauce.js", "tunnel": "node test/sauce.js -m", "start": "buster-static -e browser", "benchmark": "node benchmark/promise && node benchmark/map", "prepublish": "npm run browserify && npm run uglify", "preversion": "npm run browserify && npm run uglify", "browserify": "npm run browserify-es6 && npm run browserify-when && npm run browserify-debug", "browserify-es6": "node scripts/browserify.js es6", "browserify-when": "node scripts/browserify.js when", "browserify-debug": "node scripts/browserify.js debug", "uglify": "npm run uglify-es6 && npm run uglify-when", "uglify-es6": "uglifyjs es6-shim/Promise.js --compress --mangle --in-source-map es6-shim/Promise.js.map --source-map es6-shim/Promise.min.js.map -o es6-shim/Promise.min.js", "uglify-when": "uglifyjs dist/browser/when.js --compress --mangle --in-source-map dist/browser/when.js.map --source-map dist/browser/when.min.js.map -o dist/browser/when.min.js" } } node-when-3.7.8+ds/parallel.js000066400000000000000000000020441314733175200161570ustar00rootroot00000000000000/** @license MIT License (c) copyright 2011-2013 original author or authors */ /** * parallel.js * * Run a set of task functions in parallel. All tasks will * receive the same args * * @author Brian Cavalier * @author John Hann */ (function(define) { define(function(require) { var when = require('./when'); var all = when.Promise.all; var slice = Array.prototype.slice; /** * Run array of tasks in parallel * @param tasks {Array|Promise} array or promiseForArray of task functions * @param [args] {*} arguments to be passed to all tasks * @return {Promise} promise for array containing the * result of each task in the array position corresponding * to position of the task in the tasks array */ return function parallel(tasks /*, args... */) { return all(slice.call(arguments, 1)).then(function(args) { return when.map(tasks, function(task) { return task.apply(void 0, args); }); }); }; }); })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); node-when-3.7.8+ds/pipeline.js000066400000000000000000000027441314733175200161770ustar00rootroot00000000000000/** @license MIT License (c) copyright 2011-2013 original author or authors */ /** * pipeline.js * * Run a set of task functions in sequence, passing the result * of the previous as an argument to the next. Like a shell * pipeline, e.g. `cat file.txt | grep 'foo' | sed -e 's/foo/bar/g' * * @author Brian Cavalier * @author John Hann */ (function(define) { define(function(require) { var when = require('./when'); var all = when.Promise.all; var slice = Array.prototype.slice; /** * Run array of tasks in a pipeline where the next * tasks receives the result of the previous. The first task * will receive the initialArgs as its argument list. * @param tasks {Array|Promise} array or promise for array of task functions * @param [initialArgs...] {*} arguments to be passed to the first task * @return {Promise} promise for return value of the final task */ return function pipeline(tasks /* initialArgs... */) { // Self-optimizing function to run first task with multiple // args using apply, but subsequence tasks via direct invocation var runTask = function(args, task) { runTask = function(arg, task) { return task(arg); }; return task.apply(null, args); }; return all(slice.call(arguments, 1)).then(function(args) { return when.reduce(tasks, function(arg, task) { return runTask(arg, task); }, args); }); }; }); })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); node-when-3.7.8+ds/poll.js000066400000000000000000000061441314733175200153360ustar00rootroot00000000000000/** @license MIT License (c) copyright 2012-2013 original author or authors */ /** * poll.js * * Helper that polls until cancelled or for a condition to become true. * * @author Scott Andrews */ (function (define) { 'use strict'; define(function(require) { var when = require('./when'); var attempt = when['try']; var cancelable = require('./cancelable'); /** * Periodically execute the task function on the msec delay. The result of * the task may be verified by watching for a condition to become true. The * returned deferred is cancellable if the polling needs to be cancelled * externally before reaching a resolved state. * * The next vote is scheduled after the results of the current vote are * verified and rejected. * * Polling may be terminated by the verifier returning a truthy value, * invoking cancel() on the returned promise, or the task function returning * a rejected promise. * * Usage: * * var count = 0; * function doSomething() { return count++ } * * // poll until cancelled * var p = poll(doSomething, 1000); * ... * p.cancel(); * * // poll until condition is met * poll(doSomething, 1000, function(result) { return result > 10 }) * .then(function(result) { assert result == 10 }); * * // delay first vote * poll(doSomething, 1000, anyFunc, true); * * @param task {Function} function that is executed after every timeout * @param interval {number|Function} timeout in milliseconds * @param [verifier] {Function} function to evaluate the result of the vote. * May return a {Promise} or a {Boolean}. Rejecting the promise or a * falsey value will schedule the next vote. * @param [delayInitialTask] {boolean} if truthy, the first vote is scheduled * instead of immediate * * @returns {Promise} */ return function poll(task, interval, verifier, delayInitialTask) { var deferred, canceled, reject; canceled = false; deferred = cancelable(when.defer(), function () { canceled = true; }); reject = deferred.reject; verifier = verifier || function () { return false; }; if (typeof interval !== 'function') { interval = (function (interval) { return function () { return when().delay(interval); }; })(interval); } function certify(result) { deferred.resolve(result); } function schedule(result) { attempt(interval).then(vote, reject); if (result !== void 0) { deferred.notify(result); } } function vote() { if (canceled) { return; } when(task(), function (result) { when(verifier(result), function (verification) { return verification ? certify(result) : schedule(result); }, function () { schedule(result); } ); }, reject ); } if (delayInitialTask) { schedule(); } else { // if task() is blocking, vote will also block vote(); } // make the promise cancelable deferred.promise = Object.create(deferred.promise); deferred.promise.cancel = deferred.cancel; return deferred.promise; }; }); })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); node-when-3.7.8+ds/scripts/000077500000000000000000000000001314733175200155145ustar00rootroot00000000000000node-when-3.7.8+ds/scripts/browserify-tests.js000066400000000000000000000011441314733175200214050ustar00rootroot00000000000000var path = require('path'); var fs = require('fs'); var glob = require('glob'); var browserify = require('browserify'); var POSIX_SEP = path.posix ? path.posix.sep : '/'; var ROOT_DIR = path.resolve(__dirname, '..'); var outputFile = path.resolve(ROOT_DIR, 'test', 'browser', 'tests.js'); var entries = glob(path.join(ROOT_DIR, 'test', '**', '*-test.js'), { sync: true }); if (path.sep !== POSIX_SEP) { entries = entries.map(function (entry) { return entry.split(POSIX_SEP).join(path.sep); }); } browserify({ entries: entries }) .external('buster') .bundle() .pipe(fs.createWriteStream(outputFile)); node-when-3.7.8+ds/scripts/browserify.js000066400000000000000000000040131314733175200202430ustar00rootroot00000000000000var exec = require('child_process').exec; var path = require('path'); var fs = require('fs'); var mkdirp = require('mkdirp'); var browserify = require('browserify'); var exorcist = require('exorcist'); var ROOT_DIR = path.resolve(__dirname, '..'); var CONFIGURATIONS = { 'es6': { standaloneName: 'Promise', entries: [ path.resolve(ROOT_DIR, 'es6-shim', 'Promise.browserify-es6.js') ], outputDir: 'es6-shim', outputFilename: 'Promise.js' }, 'when': { standaloneName: 'when', entries: [ path.resolve(ROOT_DIR, 'build', 'when.browserify.js') ], outputDir: path.join('dist', 'browser'), outputFilename: 'when.js' }, 'debug': { standaloneName: 'when', entries: [ path.resolve(ROOT_DIR, 'build', 'when.browserify-debug.js') ], outputDir: path.join('dist', 'browser'), outputFilename: 'when.debug.js' } }; function revParse(callback) { exec('git rev-parse HEAD', function(err, stdout, stderr) { process.stderr.write(stderr); if (err) { callback(err); } else { callback(null, stdout.replace(/(^\s+)|(\s+$)/g, '')); } }); } var configName = process.argv[2]; var config = CONFIGURATIONS[configName]; if (!config) { console.error('Cannot find configuration "' + configName + '"'); process.exit(1); return; } mkdirp(config.outputDir, function(mkdirErr) { if (mkdirErr) { console.error(mkdirErr); process.exit(1); } else { revParse(function(revParseErr, rev) { if (revParseErr) { console.error(revParseErr); process.exit(1); } else { var rootUrl = 'https://raw.githubusercontent.com/cujojs/when/' + rev; var outputMapFile = path.resolve(ROOT_DIR, config.outputDir, config.outputFilename + '.map'); var outputFile = path.resolve(ROOT_DIR, config.outputDir, config.outputFilename); browserify({ entries: config.entries }) .bundle({ standalone: config.standaloneName, detectGlobals: false, debug: true }) .pipe(exorcist(outputMapFile, null, rootUrl, ROOT_DIR)) .pipe(fs.createWriteStream(outputFile)); } }); } }); node-when-3.7.8+ds/sequence.js000066400000000000000000000023031314733175200161710ustar00rootroot00000000000000/** @license MIT License (c) copyright 2011-2013 original author or authors */ /** * sequence.js * * Run a set of task functions in sequence. All tasks will * receive the same args. * * @author Brian Cavalier * @author John Hann */ (function(define) { define(function(require) { var when = require('./when'); var all = when.Promise.all; var slice = Array.prototype.slice; /** * Run array of tasks in sequence with no overlap * @param tasks {Array|Promise} array or promiseForArray of task functions * @param [args] {*} arguments to be passed to all tasks * @return {Promise} promise for an array containing * the result of each task in the array position corresponding * to position of the task in the tasks array */ return function sequence(tasks /*, args... */) { var results = []; return all(slice.call(arguments, 1)).then(function(args) { return when.reduce(tasks, function(results, task) { return when(task.apply(void 0, args), addResult); }, results); }); function addResult(result) { results.push(result); return results; } }; }); })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); node-when-3.7.8+ds/test/000077500000000000000000000000001314733175200150045ustar00rootroot00000000000000node-when-3.7.8+ds/test/all-test.js000066400000000000000000000057121314733175200170740ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var fail = buster.referee.fail; var when = require('../when'); var CorePromise = when.Promise; var resolved = when.resolve; var rejected = when.reject; var sentinel = { value: 'sentinel' }; var other = { value: 'other' }; buster.testCase('when.all', { 'should resolve empty input': function(done) { return when.all([]).then( function(result) { assert.equals(result, []); }, fail ).ensure(done); }, 'should resolve values array': function(done) { var input = [1, 2, 3]; when.all(input).then( function(results) { assert.equals(results, input); }, fail ).ensure(done); }, 'should resolve promises array': function(done) { var input = [resolved(1), resolved(2), resolved(3)]; when.all(input).then( function(results) { assert.equals(results, [1, 2, 3]); }, fail ).ensure(done); }, 'should resolve sparse array input': function(done) { var input = [, 1, , 1, 1 ]; when.all(input).then( function(results) { assert.equals(results, input); }, fail ).ensure(done); }, 'should reject if any input promise rejects': function(done) { var input = [resolved(1), rejected(2), resolved(3)]; when.all(input).then( fail, function(failed) { assert.equals(failed, 2); } ).ensure(done); }, 'should accept a promise for an array': function(done) { var expected, input; expected = [1, 2, 3]; input = resolved(expected); when.all(input).then( function(results) { assert.equals(results, expected); }, fail ).ensure(done); }, 'should resolve to empty array when input promise does not resolve to array': function(done) { when.all(resolved(1)).then( function(result) { assert.equals(result, []); }, fail ).ensure(done); }, 'should report only 1 unhandled rejection': { 'when array contains > 1 rejection': function(done) { /*global setTimeout*/ var origOnUnhandled = CorePromise.onPotentiallyUnhandledRejection; CorePromise.onPotentiallyUnhandledRejection = function() { fail(new Error('should not report unhandled rejection')); }; when.all([rejected(sentinel), resolved(123), rejected(other)]) ['catch'](function(e) { assert.same(e, sentinel); setTimeout(function() { CorePromise.onPotentiallyUnhandledRejection = origOnUnhandled; done(); }, 100); }); }, 'when array contains same rejection multiple times': function(done) { /*global setTimeout*/ var origOnUnhandled = CorePromise.onPotentiallyUnhandledRejection; CorePromise.onPotentiallyUnhandledRejection = function() { fail(new Error('should not report unhandled rejection')); }; var r = rejected(sentinel); when.all([r, r.then()]) ['catch'](function(e) { assert.same(e, sentinel); setTimeout(function() { CorePromise.onPotentiallyUnhandledRejection = origOnUnhandled; done(); }, 100); }); } } }); node-when-3.7.8+ds/test/any-test.js000066400000000000000000000032611314733175200171100ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var refute = buster.refute; var fail = buster.referee.fail; var when = require('../when'); var resolved = when.resolve; var rejected = when.reject; function contains(array, item) { for(var i=array.length - 1; i >= 0; --i) { if(array[i] === item) { return true; } } return false; } buster.testCase('when.any', { 'should reject with RangeError': { 'when zero inputs': function() { return when.any([])['catch']( function (e) { assert(e instanceof RangeError); }); }, 'when input promise does not resolve to array': function() { return when.any(when.resolve(1))['catch']( function(e) { assert(e instanceof RangeError); }); } }, 'should reject with all rejected input values if all inputs are rejected': function() { var input = [rejected(1), rejected(2), rejected(3)]; return when.any(input)['catch']( function(result) { assert.equals(result, [1, 2, 3]); } ); }, 'should resolve with an input value': function() { var input = [1, 2, 3]; return when.any(input).then( function(result) { assert(contains(input, result)); }, fail ); }, 'should resolve with a promised input value': function() { var input = [resolved(1), resolved(2), resolved(3)]; return when.any(input).then( function(result) { assert(contains([1, 2, 3], result)); } ); }, 'should accept a promise for an array': function() { var expected, input; expected = [1, 2, 3]; input = resolved(expected); return when.any(input).then( function(result) { refute.equals(expected.indexOf(result), -1); } ); } }); node-when-3.7.8+ds/test/browser/000077500000000000000000000000001314733175200164675ustar00rootroot00000000000000node-when-3.7.8+ds/test/browser/index.html000066400000000000000000000002711314733175200204640ustar00rootroot00000000000000 when.js browser tests node-when-3.7.8+ds/test/browsers.json000066400000000000000000000016761314733175200175570ustar00rootroot00000000000000[ // we don't really care about the platform, but without it the browser may fail to resolve { browserName: 'chrome', platform: 'Windows 8.1' }, { browserName: 'firefox', platform: 'Windows 8.1' }, { browserName: 'internet explorer', version: '11', platform: 'Windows 8.1' }, { browserName: 'internet explorer', version: '10', platform: 'Windows 8' }, { browserName: 'internet explorer', version: '9', platform: 'Windows 7' }, { browserName: 'opera', version: '12', platform: 'Windows 7' }, { browserName: 'opera', version: '11', platform: 'Windows 7' }, { browserName: 'safari', version: '7', platform: 'OS X 10.9' }, { browserName: 'safari', version: '6', platform: 'OS X 10.8' }, { browserName: 'ipad', version: '7.1', platform: 'OS X 10.9' }, { browserName: 'ipad', version: '7', platform: 'OS X 10.9' } ]node-when-3.7.8+ds/test/buster.js000066400000000000000000000004271314733175200166510ustar00rootroot00000000000000exports.node = { environment: 'node', rootPath: '../', tests: [ 'test/**/*-test.js' ] }; exports.browser = { environment: 'browser', rootPath: '..', tests: [ 'test/browser/tests.js' ], resources: [ 'test/browser/es5.js' ], testbed: 'test/browser/index.html' }; node-when-3.7.8+ds/test/callbacks-test.js000066400000000000000000000254021314733175200202410ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var fail = buster.referee.fail; var when = require('../when'); var callbacks = require('../callbacks'); var sentinel = { value: 'sentinel' }; function assertIsPromise(arg) { assert(when.isPromiseLike(arg)); } function async(f, x, thisArg) { setTimeout(function() { f.call(thisArg, x); }); } buster.testCase('when/callbacks', { 'apply': { 'should return a promise': function() { assertIsPromise(callbacks.apply(function() {})); }, 'should preserve thisArg': function() { return callbacks.apply.call(sentinel, function(cb) { assert.same(this, sentinel); cb(); }); }, 'should resolve with the callback arguments': function(done) { var promise = callbacks.apply(function(cb) { cb(sentinel); }); promise.then(function(val) { assert.same(val, sentinel); }, fail).ensure(done); }, 'should resolve with the callback arguments when async': function(done) { var promise = callbacks.apply(function(cb) { async(cb, sentinel); }); promise.then(function(val) { assert.same(val, sentinel); }, fail).ensure(done); }, 'should reject with the errback arguments': function(done) { var promise = callbacks.apply(function(cb, eb){ eb(sentinel); }); promise.then(fail, function(reason) { assert.same(reason, sentinel); }).ensure(done); }, 'should reject with the errback arguments when async': function(done) { var promise = callbacks.apply(function(cb, eb){ async(eb, sentinel); }); promise.then(fail, function(reason) { assert.same(reason, sentinel); }).ensure(done); }, 'should turn exceptions into rejections': function(done) { var error = new Error(); var promise = callbacks.apply(function(){ throw error; }); promise.then(fail, function(reason) { assert.equals(reason, error); }).ensure(done); }, 'should forward its second argument to the function': function(done) { var async = function(a, b, cb/*, eb*/) { cb(a + b); }; var promise = callbacks.apply(async, [10, 15]); promise.then(function(result) { assert.equals(result, 25); }, fail).ensure(done); }, 'should turn multiple callback values into an array': function(done) { var async = function(a, b, cb/*, eb*/) { cb(a * 10, b * 20); }; var promise = callbacks.apply(async, [10, 20]); promise.then(function(results) { assert.equals(results, [100, 400]); }, fail).ensure(done); }, 'should accept promises on the extra arguments': function(done) { var async = function(a, b, cb/*, eb*/) { cb(a + b); }; var promise = callbacks.apply(async, [when(10), 15]); promise.then(function(result) { assert.equals(result, 25); }, fail).ensure(done); } }, 'call': { 'should return a promise': function() { assertIsPromise(callbacks.call(function() {})); }, 'should preserve thisArg': function() { return callbacks.call.call(sentinel, function(cb) { assert.same(this, sentinel); cb(); }); }, 'should resolve with the callback arguments': function(done) { var promise = callbacks.call(function(cb) { cb(sentinel); }); promise.then(function(val) { assert.same(val, sentinel); }, fail).ensure(done); }, 'should resolve with the callback arguments when async': function(done) { var promise = callbacks.call(function(cb) { async(cb, sentinel); }); promise.then(function(val) { assert.same(val, sentinel); }, fail).ensure(done); }, 'should reject with the errback arguments': function(done) { var promise = callbacks.call(function(cb, eb){ eb(sentinel); }); promise.then(fail, function(reason) { assert.same(reason, sentinel); }).ensure(done); }, 'should reject with the errback arguments when async': function(done) { var promise = callbacks.call(function(cb, eb){ async(eb, sentinel); }); promise.then(fail, function(reason) { assert.same(reason, sentinel); }).ensure(done); }, 'should turn exceptions into rejections': function(done) { var error = new Error(); var promise = callbacks.call(function(){ throw error; }); promise.then(fail, function(reason) { assert.equals(reason, error); }).ensure(done); }, 'should forward its extra arguments to the function': function(done) { var async = function(a, b, cb/*, eb*/) { cb(a + b); }; var promise = callbacks.call(async, 10, 15); promise.then(function(result) { assert.equals(result, 25); }, fail).ensure(done); }, 'should turn multiple callback values into an array': function(done) { var async = function(a, b, cb/*, eb*/) { cb(a * 10, b * 20); }; var promise = callbacks.call(async, 10, 20); promise.then(function(results) { assert.equals(results, [100, 400]); }, fail).ensure(done); }, 'should accept promises on the extra arguments': function(done) { var async = function(a, b, cb/*, eb*/) { cb(a + b); }; var promise = callbacks.call(async, when(10), 15); promise.then(function(result) { assert.equals(result, 25); }, fail).ensure(done); } }, 'lift': { 'should return a function': function() { assert.isFunction(callbacks.lift(function() {})); }, 'the returned function': { 'should return a promise': function() { var result = callbacks.lift(function() {}); assertIsPromise(result()); }, 'should preserve thisArg': function() { return callbacks.lift(function(cb) { assert.same(this, sentinel); cb(); }).call(sentinel); }, 'should resolve the promise with the callback value': function(done) { var result = callbacks.lift(function(cb) { cb(10); }); result().then(function(value) { assert.equals(value, 10); }, fail).ensure(done); }, 'should resolve the promise with the callback value when async': function(done) { var result = callbacks.lift(function(cb) { async(cb, sentinel); }); result().then(function(value) { assert.same(value, sentinel); }, fail).ensure(done); }, 'should forward arguments to the original function': function(done) { var result = callbacks.lift(function(a, b, cb) { cb(a + b); }); result(10, 15).then(function(value) { assert.equals(value, 25); }, fail).ensure(done); }, 'should reject the promise with the errback value': function(done) { var error = new Error(); var result = callbacks.lift(function(cb, eb) { eb(error); }); result().then(fail, function(reason) { assert.same(reason, error); }).ensure(done); }, 'should reject the promise with the errback value when async': function(done) { var error = new Error(); var result = callbacks.lift(function(cb, eb) { async(eb, error); }); result().then(fail, function(reason) { assert.same(reason, error); }).ensure(done); }, 'should turn exceptions into rejections': function(done) { var error = new Error(); var result = callbacks.lift(function(){ throw error; }); result().then(fail, function(reason) { assert.equals(reason, error); }).ensure(done); }, 'should turn multiple callback values into an array': function(done) { var result = callbacks.lift(function(a, b, cb/*, eb*/) { cb(a * 10, b * 20); }); result(10, 20).then(function(results) { assert.equals(results, [100, 400]); }, fail).ensure(done); }, 'should accept promises as arguments': function(done) { var result = callbacks.lift(function(a, b, cb/*, eb*/) { cb(a + b); }); result(when(10), 15).then(function(result) { assert.equals(result, 25); }, fail).ensure(done); } }, 'should accept leading arguments': function(done) { function fancySum(x, y, callback) { callback(x + y); } var partiallyApplied = callbacks.lift(fancySum, 5); partiallyApplied(10).then(function(value) { assert.equals(value, 15); }, fail).ensure(done); }, 'should accept promises as leading arguments': function(done) { function fancySum(x, y, callback) { callback(x + y); } var partiallyApplied = callbacks.lift(fancySum, when(5)); partiallyApplied(10).then(function(value) { assert.equals(value, 15); }, fail).ensure(done); } }, 'promisify': { 'should preserve thisArg': function() { return callbacks.promisify(function(cb) { assert.same(this, sentinel); cb(); }, { callback: 0 }).call(sentinel); }, 'should support callbacks in any position': function(done) { function weirdAsync(a, callback, b) { callback(a + b); } var promisified = callbacks.promisify(weirdAsync, { callback: 1 }); promisified(10, 5).then(function(result) { assert.equals(result, 15); }, fail).ensure(done); }, 'should support errbacks in any position': function(done) { function weirdAsync(errback, a, callback, b) { errback(a + b); } var promisified = callbacks.promisify(weirdAsync, { callback: 2, errback: 0 }); promisified(10, 5).then(fail, function(reason) { assert.equals(reason, 15); }).ensure(done); }, 'should turn multiple callback values into an array': function(done) { function invert(cb, eb, a, b) { cb(b, a); } var promisified = callbacks.promisify(invert, { callback: 0, errback: 1 }); promisified(10, 20).then(function(results) { assert.equals(results, [20, 10]); }, fail).ensure(done); }, 'should turn exceptions into rejections': function(done) { var error = new Error(); var result = callbacks.promisify(function(){ throw error; }, {}); result().then(fail, function(reason) { assert.equals(reason, error); }).ensure(done); }, 'should accept promises as arguments': function(done) { var result = callbacks.promisify(function(a, b, cb/*, eb*/) { cb(a + b); }, { callback: -2, errback: -1 }); result(when(10), 15).then(function(result) { assert.equals(result, 25); }, fail).ensure(done); }, 'should understand -1 as "the last argument"': function(done) { function asyncSum(/*n1, n2, n3...errback, callback*/) { arguments[arguments.length - 1](sentinel); } var promisified = callbacks.promisify(asyncSum, { errback: -2, callback: -1 }); promisified(0, 1, 2).then( function(val) { assert.same(val, sentinel); }, fail ).ensure(done); }, 'should understand -2 as "the penultimate argument"': function(done) { function asyncConcat(/*str1, str2, str3...errback, callback*/) { arguments[arguments.length - 2](sentinel); } var promisified = callbacks.promisify(asyncConcat, { errback: -2, callback: -1 }); promisified(0, 1, 2).then( fail, function(val) { assert.same(val, sentinel); } ).ensure(done); } } }); node-when-3.7.8+ds/test/cancelable-test.js000066400000000000000000000034531314733175200203750ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var fail = buster.referee.fail; var when = require('../when'); var cancelable = require('../cancelable'); var sentinel = {}; var other = {}; buster.testCase('when/cancelable', { 'should decorate deferred with a cancel() method': function() { var c = cancelable(when.defer(), function() {}); assert(typeof c.cancel == 'function'); }, 'should propagate a rejection when a cancelable deferred is canceled': function(done) { var c = cancelable(when.defer(), function() { return sentinel; }); c.cancel(); c.promise.then( fail, function(v) { assert.equals(v, sentinel); } ).ensure(done); }, 'should return a promise for canceled value when canceled': function(done) { var c, promise; c = cancelable(when.defer(), function() { return sentinel; }); promise = c.cancel(); promise.then( fail, function(v) { assert.equals(v, sentinel); } ).ensure(done); }, 'should not invoke canceler when rejected normally': function(done) { var c = cancelable(when.defer(), function() { return other; }); c.reject(sentinel); c.cancel(); c.promise.then( fail, function(v) { assert.equals(v, sentinel); } ).ensure(done); }, 'should propagate the unaltered resolution value': function(done) { var c = cancelable(when.defer(), function() { return other; }); c.resolve(sentinel); c.cancel(); c.promise.then( function(val) { assert.same(val, sentinel); }, function(e) { fail(e); } ).ensure(done); }, 'should call progback for cancelable deferred': function(done) { var c = cancelable(when.defer()); c.promise.then(null, null, function (status) { assert.same(status, sentinel); done(); }); c.notify(sentinel); } }); node-when-3.7.8+ds/test/cycle-test.js000066400000000000000000000024241314733175200174200ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var CorePromise = require('../lib/Promise'); function assertCycle(p) { return p.then(buster.referee.fail, function(e) { assert(e instanceof TypeError); }); } buster.testCase('cycle detection', { 'should detect self-cycles': { 'when resolving': function() { /*global setTimeout*/ var p = new CorePromise(function(resolve) { setTimeout(function() { resolve(p); }, 0); }); return assertCycle(p); }, 'when returning from handler': function() { var p = CorePromise.resolve(); p = p.then(function() { return p; }); return assertCycle(p); }, 'when returning resolved from handler': function() { var p = CorePromise.resolve(); p = p.then(function() { return CorePromise.resolve(p); }); return assertCycle(p); } }, 'should detect long cycles': function() { var p1 = new CorePromise(function(resolve) { setTimeout(function() { resolve(p2); }, 0); }); var p2 = new CorePromise(function(resolve) { setTimeout(function() { resolve(p3); }, 0); }); var p3 = new CorePromise(function(resolve) { setTimeout(function() { resolve(p1); }, 0); }); return assertCycle(p3); } }); node-when-3.7.8+ds/test/defer-test.js000066400000000000000000000143461314733175200174140ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var refute = buster.refute; var fail = buster.referee.fail; var when = require('../when'); var sentinel = {}; var other = {}; function fakeResolved(val) { return { then: function(callback) { return fakeResolved(callback ? callback(val) : val); } }; } function fakeRejected(reason) { return { then: function(callback, errback) { return errback ? fakeResolved(errback(reason)) : fakeRejected(reason); } }; } buster.testCase('when.defer', { 'resolve': { 'should fulfill with an immediate value': function(done) { var d = when.defer(); d.promise.then( function(val) { assert.same(val, sentinel); }, fail ).ensure(done); d.resolve(sentinel); }, 'should fulfill with fulfilled promised': function(done) { var d = when.defer(); d.promise.then( function(val) { assert.same(val, sentinel); }, fail ).ensure(done); d.resolve(fakeResolved(sentinel)); }, 'should reject with rejected promise': function(done) { var d = when.defer(); d.promise.then( fail, function(val) { assert.same(val, sentinel); } ).ensure(done); d.resolve(fakeRejected(sentinel)); }, 'should invoke newly added callback when already resolved': function(done) { var d = when.defer(); d.resolve(sentinel); d.promise.then( function(val) { assert.same(val, sentinel); done(); }, fail ).ensure(done); } }, 'reject': { 'should reject with an immediate value': function(done) { var d = when.defer(); d.promise.then( fail, function(val) { assert.same(val, sentinel); } ).ensure(done); d.reject(sentinel); }, 'should reject with fulfilled promised': function(done) { var d, expected; d = when.defer(); expected = fakeResolved(sentinel); d.promise.then( fail, function(val) { assert.same(val, expected); } ).ensure(done); d.reject(expected); }, 'should reject with rejected promise': function(done) { var d, expected; d = when.defer(); expected = fakeRejected(sentinel); d.promise.then( fail, function(val) { assert.same(val, expected); } ).ensure(done); d.reject(expected); }, 'should invoke newly added errback when already rejected': function(done) { var d = when.defer(); d.reject(sentinel); d.promise.then( fail, function (val) { assert.equals(val, sentinel); } ).ensure(done); } }, 'notify': { 'should notify of progress updates': function(done) { var d = when.defer(); d.promise.then( fail, fail, function(val) { assert.same(val, sentinel); done(); } ); d.notify(sentinel); }, 'should propagate progress to downstream promises': function(done) { var d = when.defer(); d.promise .then(fail, fail, function(update) { return update; } ) .then(fail, fail, function(update) { assert.same(update, sentinel); done(); } ); d.notify(sentinel); }, 'should propagate transformed progress to downstream promises': function(done) { var d = when.defer(); d.promise .then(fail, fail, function() { return sentinel; } ) .then(fail, fail, function(update) { assert.same(update, sentinel); done(); } ); d.notify(other); }, 'should propagate caught exception value as progress': function(done) { var d = when.defer(); d.promise .then(fail, fail, function() { throw sentinel; } ) .then(fail, fail, function(update) { assert.same(update, sentinel); done(); } ); d.notify(other); }, 'should forward progress events when intermediary callback (tied to a resolved promise) returns a promise': function(done) { var d, d2; d = when.defer(); d2 = when.defer(); // resolve d BEFORE calling attaching progress handler d.resolve(); d.promise.then( function() { return when.promise(function(resolve, reject, notify) { setTimeout(function() { notify(sentinel); }, 0); }); } ).then(null, null, function onProgress(update) { assert.same(update, sentinel); done(); } ); }, 'should forward progress events when intermediary callback (tied to an unresovled promise) returns a promise': function(done) { var d = when.defer(); d.promise.then( function() { return when.promise(function(resolve, reject, notify) { setTimeout(function() { notify(sentinel); }, 0); }); } ).then(null, null, function onProgress(update) { assert.same(update, sentinel); done(); } ); // resolve d AFTER calling attaching progress handler d.resolve(); }, 'should forward progress when resolved with another promise': function(done) { var d, d2; d = when.defer(); d2 = when.defer(); d.promise .then(fail, fail, function() { return sentinel; } ) .then(fail, fail, function(update) { assert.same(update, sentinel); done(); } ); d.resolve(d2.promise); d2.notify(); }, 'should allow resolve after progress': function(done) { var d = when.defer(); var progressed = false; d.promise.then( function() { assert(progressed); done(); }, fail, function() { progressed = true; } ); d.notify(); d.resolve(); }, 'should allow reject after progress': function(done) { var d = when.defer(); var progressed = false; d.promise.then( fail, function() { assert(progressed); done(); }, function() { progressed = true; } ); d.notify(); d.reject(); }, 'should be indistinguishable after resolution': function() { var d, before, after; d = when.defer(); before = d.notify(sentinel); d.resolve(); after = d.notify(sentinel); assert.same(before, after); } }, 'should return silently on progress when already resolved': function() { var d = when.defer(); d.resolve(); refute.defined(d.notify()); }, 'should return silently on progress when already rejected': function() { var d = when.defer(); d.reject(); refute.defined(d.notify()); } }); node-when-3.7.8+ds/test/delay-test.js000066400000000000000000000026751314733175200174270ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var fail = buster.referee.fail; var when = require('../when'); var delay = require('../delay'); var sentinel = {}; function now() { return (new Date()).getTime(); } buster.testCase('when/delay', { 'should resolve after delay': function(done) { delay(0).then( function() { assert(true); }, fail ).ensure(done); }, 'should resolve with provided value after delay': function(done) { delay(0, sentinel).then( function(val) { assert.same(val, sentinel); done(); }, fail ).ensure(done); }, 'should delay by the provided value': function(done) { var start = now(); delay(100).then( function() { assert((now() - start) > 50); }, fail ).ensure(done); }, 'should resolve after input promise plus delay': function(done) { when.resolve(sentinel).delay(10).then( function(val) { assert.equals(val, sentinel); }, fail ).ensure(done); }, 'should not delay if rejected': function(done) { var d = when.defer(); d.reject(sentinel); d.promise.delay(0).then( fail, function(val) { assert.equals(val, sentinel); } ).ensure(done); }, 'should propagate progress': function(done) { var d = when.defer(); d.promise.delay(0).then(null, null, function(val) { assert.same(val, sentinel); d.resolve(); } ).ensure(done); d.notify(sentinel); } }); node-when-3.7.8+ds/test/else-test.js000066400000000000000000000011571314733175200172530ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var when = require('../when'); var input = {}; var sentinel = { value: 'sentinel' }; buster.testCase('promise.else', { 'should resolve normally if previous promise doesn\'t fail': function () { return when.resolve(input) ['else'](sentinel) .then(function (val) { assert.same(val, input); }); }, 'should resolve with else value if previous promise fails': function () { return when.reject(input) ['else'](sentinel) .then(function (val) { assert.same(val, sentinel); }); } }); node-when-3.7.8+ds/test/filter-test.js000066400000000000000000000045211314733175200176060ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var when = require('../when'); var sentinel = { value: 'sentinel' }; function even(x) { return x % 2 === 0; } function evenPromise(x) { return when(even(x)); } buster.testCase('when.filter', { 'should pass index to predicate as second param': function() { return when.filter(['a','b','c'], function(x, i) { assert(typeof i === 'number'); return true; }); }, 'should filter input values array': function() { var input = [1, 2, 3]; return when.filter(input, even).then( function(results) { assert.equals(input.filter(even), results); }); }, 'should filter input promises array': function() { var input = [1, 2, 3]; return when.filter(input.map(when), even).then( function(results) { assert.equals(input.filter(even), results); }); }, 'should filter input when predicate returns a promise': function() { var input = [1,2,3]; return when.filter(input, evenPromise).then( function(results) { assert.equals(input.filter(even), results); }); }, 'should accept a promise for an array': function() { var input = [1,2,3]; return when.filter(when(input), even).then( function(results) { assert.equals(input.filter(even), results); }); }, 'should fulfill with empty array when input promise fulfills with non-array': function() { return when.filter(when(123), even).then( function(result) { assert.equals(result, []); }); }, 'should reject when input contains rejection': function() { var input = [when(1), when.reject(sentinel), 3]; return when.filter(input, even)['catch']( function(e) { assert.same(e, sentinel); }); }, 'should reject when input is a rejected promise': function() { return when.filter(when.reject(sentinel), even)['catch']( function(e) { assert.same(e, sentinel); }); }, 'should match Array.prototype.filter behavior when predicate modifies array': function() { // Test to match Array.prototype.filter behavior var a = [1, 2, 3, 4]; var b = a.slice(); var expected = b.filter(makePredicate(b)); function makePredicate(a) { return function (n, i){ a[i] = 'fail'; return n % 2 === 0; }; } return when.filter(a, makePredicate(a)).then(function(results) { assert.equals(results, expected); }); } }); node-when-3.7.8+ds/test/flow-test.js000066400000000000000000000133621314733175200172730ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var fail = buster.referee.fail; var CorePromise = require('../when').Promise; var sentinel = { value: 'sentinel' }; var other = { value: 'other' }; var origOnUnhandled = CorePromise.onPotentiallyUnhandledRejection; var origOnHandled = CorePromise.onPotentiallyUnhandledRejectionHandled; buster.testCase('when/lib/flow', { 'otherwise': { 'should be an alias for catch': function() { assert.same(CorePromise.prototype['catch'], CorePromise.prototype.otherwise); } }, 'catch': { 'should catch rejections': function() { return CorePromise.reject(sentinel)['catch'](function(e) { assert.same(e, sentinel); }); }, 'when predicate is provided': { 'and is an Error type match': { 'should only catch errors of same type': function() { var e1 = new TypeError(); return CorePromise.reject(e1)['catch'](SyntaxError, fail) ['catch'](TypeError, function(e) { assert.same(e1, e); }); } }, 'and is a predicate function': { 'should only catch errors of same type': function() { var e1 = new TypeError(); return CorePromise.reject(e1)['catch'](function(e) { return e !== e1; }, fail)['catch'](function(e) { return e === e1; }, function(e) { assert.same(e1, e); }); } }, 'but is not a function': { 'when rejected should reject with a TypeError': function() { return CorePromise.reject(sentinel)['catch'](123, fail) ['catch'](function(e) { assert(e instanceof TypeError); }); }, 'when fulfilled should reject with a TypeError': function() { return CorePromise.resolve(sentinel)['catch'](123, fail) ['catch'](function(e) { assert(e instanceof TypeError); }); } } } }, 'finally': { 'should be an alias for ensure': function() { var p = CorePromise.resolve(); assert.same(p['finally'], p.ensure); } }, 'ensure': { 'should return a promise': function() { assert.isFunction(CorePromise.resolve().ensure().then); }, 'should not suppress unhandled rejection': { tearDown: function() { CorePromise.onPotentiallyUnhandledRejection = origOnUnhandled; CorePromise.onPotentiallyUnhandledRejectionHandled = origOnHandled; }, 'when handler returns non-promise': function(done) { CorePromise.onPotentiallyUnhandledRejection = function() { assert(true); done(); }; CorePromise.reject(sentinel).ensure(function() {}); }, 'when handler returns promise': function(done) { CorePromise.onPotentiallyUnhandledRejection = function() { assert(true); done(); }; CorePromise.reject(sentinel).ensure(function() { return CorePromise.resolve(other); }); }, 'when finally handler throws': function(done) { /*global setTimeout*/ var errors = {}; CorePromise.onPotentiallyUnhandledRejection = function(rej) { errors[rej.errorId] = rej.value; }; CorePromise.onPotentiallyUnhandledRejectionHandled = function(rej) { delete errors[rej.errorId]; }; CorePromise.reject(other).ensure(function() { throw sentinel; }); setTimeout(done(function() { var keys = Object.keys(errors); assert.equals(keys.length, 1); assert.same(errors[keys[0]], sentinel); }), 100); }, 'when finally handler rejects': function(done) { /*global setTimeout*/ var errors = {}; CorePromise.onPotentiallyUnhandledRejection = function(rej) { errors[rej.errorId] = rej.value; }; CorePromise.onPotentiallyUnhandledRejectionHandled = function(rej) { delete errors[rej.errorId]; }; CorePromise.reject(other).ensure(function() { return CorePromise.reject(sentinel); }); setTimeout(done(function() { var keys = Object.keys(errors); assert.equals(keys.length, 1); assert.same(errors[keys[0]], sentinel); }), 100); } }, 'when fulfilled': { 'should ignore callback return value': function() { return CorePromise.resolve(sentinel).ensure( function() { return other; } ).then( function(val) { assert.same(val, sentinel); }, fail ); }, 'should await returned promise': function() { var awaited = false; return CorePromise.resolve(sentinel).ensure(function() { return new CorePromise(function(resolve) { setTimeout(function() { awaited = true; resolve(); }, 1); }); }).then(function() { assert(awaited); }); }, 'should propagate rejection on throw': function() { return CorePromise.resolve(other).ensure( function() { throw sentinel; } ).then( fail, function(val) { assert.same(val, sentinel); } ); } }, 'when rejected': { 'should propagate rejection, ignoring callback return value': function() { return CorePromise.reject(sentinel).ensure( function() { return other; } ).then( fail, function(val) { assert.same(val, sentinel); } ); }, 'should await returned promise': function() { var awaited = false; return CorePromise.resolve(sentinel).ensure(function() { return new CorePromise(function(resolve, reject) { setTimeout(function() { awaited = true; reject(); }, 1); }); })['catch'](function() { assert(awaited); }); }, 'should propagate rejection on throw': function() { return CorePromise.reject(other).ensure( function() { throw sentinel; } ).then( fail, function(val) { assert.same(val, sentinel); } ); } }, 'should ignore non-function': function() { return CorePromise.resolve(true).ensure().then(assert); } } }); node-when-3.7.8+ds/test/fold-test.js000066400000000000000000000025041314733175200172440ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var when = require('../when'); var sentinel = { value: 'sentinel' }; var other = { value: 'other' }; function noop() {} buster.testCase('promise.fold', { 'should pass value and arg': function() { return when.resolve(other).fold(function(a, b) { assert.same(a, sentinel); assert.same(b, other); }, sentinel); }, 'should pairwise combine two promises': function() { return when.resolve(1).fold(function sum(x, y) { return x + y; }, when.resolve(2)).then(function(x){ assert.equals(x, 3); }); }, 'should reject if combine throws': function() { return when.resolve(1).fold(function() { throw sentinel; }, 2)['catch'](function(e){ assert.same(e, sentinel); }); }, 'should reject if combine returns rejection': function() { return when.resolve(1).fold(when.reject, sentinel)['catch'](function(e){ assert.same(e, sentinel); }); }, 'should reject and not call combine': { 'if promise rejects': function() { return when.reject(sentinel).fold(noop, 2)['catch'](function(e){ assert.same(e, sentinel); }); }, 'if arg rejects': function() { return when.resolve(1).fold(noop, when.reject(sentinel)) ['catch'](function(e){ assert.same(e, sentinel); }); } } }); node-when-3.7.8+ds/test/format-test.js000066400000000000000000000021061314733175200176060ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var format = require('../lib/format'); buster.testCase('format', { 'formatError': { 'should format null as string': function() { var s = format.formatError(null); assert.equals(typeof s, 'string'); }, 'should format undefined as string': function() { var s = format.formatError(void 0); assert.equals(typeof s, 'string'); }, 'should be the contents of the stack property of an error': function() { var expected = 'ok'; var e = new Error(); e.stack = expected; var s = format.formatError(e); assert.equals(s, expected); } }, 'formatObject': { 'should JSON.stringify a plain object': function() { var o = {foo: 'bar'}; var s = format.formatObject(o); assert.equals(s, JSON.stringify(o)); } }, 'tryStringify': { 'should return default value when JSON.stringify fails': function() { var o = { circle: null }; o.circle = o; var sentinel = {}; assert.same(sentinel, format.tryStringify(o, sentinel)); } } }); node-when-3.7.8+ds/test/function-test.js000066400000000000000000000201221314733175200201410ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var fail = buster.referee.fail; var when = require('../when'); var fn = require('../function'); var slice = [].slice; var sentinel = { value: 'sentinel' }; function assertIsPromise(something) { var message = 'Object is not a promise'; buster.assert(when.isPromiseLike(something), message); } function functionThatThrows(error) { return function throwing() { throw error; }; } function f(x, y) { return x + y; } // Use instead of Function.prototype.bind, since we need to // test in envs that don't support it function partial(f) { var partialArgs = slice.call(arguments, 1); return function() { return f.apply(void 0, partialArgs.concat(slice.call(arguments))); }; } buster.testCase('when/function', { 'apply': { 'should return a promise': function() { var result = fn.apply(f, [1, 2]); assertIsPromise(result); }, 'should preserve thisArg': function() { return fn.apply.call(sentinel, function() { assert.same(this, sentinel); }); }, 'should accept values for arguments': function(done) { var result = fn.apply(f, [1, 2]); return when(result, function(result) { assert.equals(result, 3); }).ensure(done); }, 'should accept promises for arguments': function(done) { var result = fn.apply(f, [when(1), 2]); return when(result, function(result) { assert.equals(result, 3); }).ensure(done); }, 'should consider the arguments optional': function(done) { function countArgs() { return arguments.length; } fn.apply(countArgs).then(function(argCount) { assert.equals(argCount, 0); }, fail).ensure(done); }, 'should reject the promise when the function throws': function(done) { var error = new Error(); var throwingFn = functionThatThrows(error); fn.apply(throwingFn).then(fail, function(reason) { assert.same(reason, error); }).ensure(done); }, 'should maintain promise flattening semantics': function(done) { function returnsPromise(val) { return when.resolve(10 + val); } fn.apply(returnsPromise, [5]).then(function(value) { assert.equals(value, 15); }, fail).ensure(done); }, 'should accept Arguments instance': function() { var expected = [1, 2, 3]; function f() { assert.equals(slice.call(arguments), expected); } function run() { return fn.apply(f, arguments); } return run.apply(void 0, expected); } }, 'call': { 'should return a promise': function() { var result = fn.call(f, 1, 2); assertIsPromise(result); }, 'should preserve thisArg': function() { return fn.call.call(sentinel, function() { assert.same(this, sentinel); }); }, 'should accept values for arguments': function(done) { var result = fn.call(f, 1, 2); return when(result, function(result) { assert.equals(result, 3); }).ensure(done); }, 'should accept promises for arguments': function(done) { var result = fn.call(f, when(1), 2); return when(result, function(result) { assert.equals(result, 3); }).ensure(done); }, 'should consider the arguments optional': function(done) { function countArgs() { return arguments.length; } fn.call(countArgs).then(function(argCount) { assert.equals(argCount, 0); }, fail).ensure(done); }, 'should reject the promise when the function throws': function(done) { var error = new Error(); var throwingFn = functionThatThrows(error); fn.call(throwingFn).then(fail, function(reason) { assert.same(reason, error); }).ensure(done); }, 'should maintain promise flattening semantics': function(done) { function returnsPromise(val) { return when.resolve(10 + val); } fn.call(returnsPromise, 5).then(function(value) { assert.equals(value, 15); }, fail).ensure(done); } }, 'lift': { 'should return a function': function() { assert.isFunction(fn.lift(f, null)); }, 'the returned function': { 'should return a promise': function() { var result = fn.lift(f); assertIsPromise(result(1, 2)); }, 'should preserve thisArg': function() { return fn.lift(function() { assert.same(this, sentinel); }).call(sentinel); }, 'should resolve the promise to its return value': function(done) { var result = fn.lift(f); result(1, 2).then(function(value) { assert.equals(value, 3); }, fail).ensure(done); }, 'should accept promises for arguments': function(done) { var result = fn.lift(f); result(1, when(2)).then(function(value) { assert.equals(value, 3); }, fail).ensure(done); }, 'should reject the promise upon error': function(done) { var error = new Error(); var throwingFn = functionThatThrows(error); var result = fn.lift(throwingFn); result().then(fail, function(reason) { assert.same(reason, error); }).ensure(done); } }, 'should accept leading arguments': function(done) { var partiallyApplied = fn.lift(f, 5); partiallyApplied(10).then(function(value) { assert.equals(value, 15); }, fail).ensure(done); }, 'should accept promises as leading arguments': function(done) { var partiallyApplied = fn.lift(f, when(5)); partiallyApplied(10).then(function(value) { assert.equals(value, 15); }, fail).ensure(done); } }, 'compose': { 'should return a function': function() { var result = fn.compose(f); assert.isFunction(result); }, 'the returned function': { 'should return a promise': function() { var returnedFunction = fn.compose(f); var result = returnedFunction(); assertIsPromise(result); }, 'should be composed from the passed functions': function(done) { var sumWithFive = partial(f, 5); var sumWithTen = partial(f, 10); var composed = fn.compose(sumWithFive, sumWithTen); composed(15).then(function(value) { assert.equals(value, 30); }, fail).ensure(done); }, 'should pass all its arguments to the first function': function(done) { var sumWithFive = partial(f, 5); var composed = fn.compose(f, sumWithFive); composed(10, 15).then(function(value) { assert.equals(value, 30); }, fail).ensure(done); }, 'should accept promises for arguments': function(done) { var sumWithFive = partial(f, 5); var composed = fn.compose(f, sumWithFive); composed(when(10), 15).then(function(value) { assert.equals(value, 30); }, fail).ensure(done); }, 'should be transparent to returned promises': function(done) { var sumWithTen = partial(f, 10); var promisingSumWithTen = function(arg) { return when.resolve(sumWithTen(arg)); }; var composed = fn.compose(sumWithTen, promisingSumWithTen); composed(10).then(function(value) { assert.equals(value, 30); }, fail).ensure(done); }, 'should reject when the first function throws': function(done) { var error = new Error('Exception should be handled'); var throwing = functionThatThrows(error); var composed = fn.compose(throwing, f); composed(5, 10).then(fail, function(reason) { assert.same(reason, error); }).ensure(done); }, 'should reject when a composed function throws': function(done) { var error = new Error('Exception should be handled'); var throwing = functionThatThrows(error); var composed = fn.compose(f, throwing); composed(5, 10).then(fail, function(reason) { assert.same(reason, error); }).ensure(done); }, 'should reject if a composed function rejects': function(done) { var rejecting = function() { return when.reject('rejected'); }; var composed = fn.compose(f, rejecting); composed(5, 10).then(fail, function(reason) { assert.equals(reason, 'rejected'); }).ensure(done); } }, 'should compose the functions on the given order': function(done) { function a(str) { return str + ' is'; } function b(str) { return str + ' really'; } function c(str) { return str + ' awesome!'; } var composed = fn.compose(a, b, c); composed('when.js').then(function(value) { assert.equals(value, 'when.js is really awesome!'); }, fail).ensure(done); } } }); node-when-3.7.8+ds/test/globalRejectionEvents-test.js000066400000000000000000000047441314733175200226200ustar00rootroot00000000000000/*global process, window, setTimeout*/ var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var CorePromise = require('../lib/Promise'); var sentinel = { value: 'sentinel' }; buster.testCase('global rejection events', { 'on Node': { 'tearDown': function() { if(typeof window !== 'undefined') { return; } process.removeAllListeners('unhandledRejection'); process.removeAllListeners('rejectionHandled'); }, 'should emit unhandledRejection': function(done) { if(typeof window !== 'undefined') { buster.assert(true); done(); return; } function listener(e) { buster.assert.same(e, sentinel); done(); } process.on('unhandledRejection', listener); CorePromise.reject(sentinel); }, 'should emit rejectionHandled': function(done) { if(typeof window !== 'undefined') { buster.assert(true); done(); return; } var r; function unhandled(e, rejection) { buster.assert.same(e, sentinel); r = rejection; } function handled(rejection) { buster.assert.same(rejection, r); done(); } process.on('unhandledRejection', unhandled); process.on('rejectionHandled', handled); var p = CorePromise.reject(sentinel); setTimeout(function() { p.catch(function() {}); }, 10); } }, 'in Browser': { 'should emit unhandledRejection': function(done) { if(typeof window === 'undefined') { buster.assert(true); done(); return; } function listener(e) { window.removeEventListener('unhandledRejection', listener, false); e.preventDefault(); buster.assert.same(e.detail.reason, sentinel); done(); } window.addEventListener('unhandledRejection', listener, false); CorePromise.reject(sentinel); }, 'should emit rejectionHandled': function(done) { if(typeof window === 'undefined') { buster.assert(true); done(); return; } var key; function unhandled(e) { window.removeEventListener('unhandledRejection', unhandled, false); buster.assert.same(e.detail.reason, sentinel); key = e.detail.key; } function handled(e) { window.removeEventListener('rejectionHandled', handled, false); buster.assert.same(e.detail.key, key); done(); } window.addEventListener('unhandledRejection', unhandled, false); window.addEventListener('rejectionHandled', handled, false); var p = CorePromise.reject(sentinel); setTimeout(function() { p.catch(function() {}); }, 10); } } }); node-when-3.7.8+ds/test/guard-test.js000066400000000000000000000056661314733175200174360ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var fail = buster.referee.fail; var when = require('../when'); var guard = require('../guard'); var sentinel = {}; var other = {}; function noop() {} buster.testCase('when/guard', { 'should return a function': function() { assert.isFunction(guard()); }, 'should invoke condition': function() { var condition, guarded; condition = this.spy(); guarded = guard(condition, noop); guarded(); assert.called(condition); }, 'should invoke guarded function after condition promise fulfills': function(done) { var condition, f, guarded; condition = function() { return noop; }; f = this.spy(); guarded = guard(condition, f); guarded(sentinel).then( function() { assert.calledOnce(f); assert.same(f.firstCall.args[0], sentinel); }, fail ).ensure(done); }, 'should notify condition once guarded function settles': function(done) { var condition, notify, guarded; notify = this.spy(); condition = function() { return notify; }; guarded = guard(condition, noop); guarded().then( function() { assert.calledOnce(notify); }, fail ).ensure(done); }, 'should initiate next guarded call after notify': function(done) { var condition, f, guarded; f = this.spy(); condition = function() { return noop; }; guarded = guard(condition, f); guarded(other).then( function() { assert.calledOnce(f); return guarded(sentinel).then(function() { assert.calledTwice(f); assert.same(f.secondCall.args[0], sentinel); }); }, fail ).ensure(done); }, 'n': { 'should create a function': function() { assert.isFunction(guard.n(1)); }, 'should return a promise': function() { var c = guard.n(1); assert.isFunction(c().then); }, 'returned promise should resolve to a function': function(done) { var enter = guard.n(1); enter().then( function(exit) { assert.isFunction(exit); }, fail ).ensure(done); }, 'should allow one execution': function(done) { var enter, value, first, second; enter = guard.n(1); value = sentinel; first = enter(); second = enter(); first.then( function(exit) { return when().delay(100).then(function() { assert.same(value, sentinel); exit(); }); }, fail ); second.then( function() { value = other; } ).ensure(done); }, 'should allow two executions': function(done) { var one, value, first, second, third; one = guard.n(2); value = sentinel; first = one(); second = one(); third = one(); first.then( function() { assert.same(value, sentinel); }, fail ); second.then( function(exit) { return when().delay(100).then(function() { assert.same(value, sentinel); exit(); }); }, fail ); third.then( function() { value = other; } ).ensure(done); } } }); node-when-3.7.8+ds/test/inspect-test.js000066400000000000000000000043001314733175200177610ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var fail = buster.referee.fail; var inspect = require('../lib/decorators/inspect'); var CorePromise = inspect(require('../lib/Promise')); var sentinel = { value: 'sentinel' }; function assertPending(s) { assert.equals(s.state, 'pending'); } function assertFulfilled(s, value) { assert.equals(s.state, 'fulfilled'); assert.same(s.value, value); } function assertRejected(s, reason) { assert.equals(s.state, 'rejected'); assert.same(s.reason, reason); } buster.testCase('inspect', { 'when inspecting promises': { 'should return pending state for pending promise': function() { var promise = new CorePromise(function() {}); assertPending(promise.inspect()); }, 'should immediately return fulfilled state for fulfilled promise': function() { assertFulfilled(CorePromise.resolve(sentinel).inspect(), sentinel); }, 'should return fulfilled state for fulfilled promise': function() { var promise = CorePromise.resolve(sentinel); return promise.then(function() { assertFulfilled(promise.inspect(), sentinel); }); }, 'should immediately return rejected state for rejected promise': function() { assertRejected(CorePromise.reject(sentinel).inspect(), sentinel); }, 'should return rejected state for rejected promise': function() { var promise = CorePromise.reject(sentinel); return promise.then(fail, function() { assertRejected(promise.inspect(), sentinel); }); } }, 'when inspecting thenables': { 'should return pending state for pending thenable': function() { var p = CorePromise.resolve({ then: function() {} }); assertPending(p.inspect()); }, 'should return fulfilled state for fulfilled thenable': function() { var p = CorePromise.resolve({ then: function(fulfill) { fulfill(sentinel); } }); return p.then(function() { assertFulfilled(p.inspect(), sentinel); }); }, 'should return rejected state for rejected thenable': function() { var p = CorePromise.resolve({ then: function(_, rejected) { rejected(sentinel); } }); return p.then(fail, function() { assertRejected(p.inspect(), sentinel); }); } } }); node-when-3.7.8+ds/test/isPromiseLike-test.js000066400000000000000000000020601314733175200210740ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var when = require('../when'); var fakePromise = { then:function () {} }; function assertIsPromiseLike(it) { buster.assert(when.isPromiseLike(it)); } function refuteIsPromiseLike(it) { buster.refute(when.isPromiseLike(it)); } buster.testCase('when.isPromiseLike', { 'should return true for trusted': function() { assertIsPromiseLike(when.resolve()); }, 'should return true for promise': function() { assertIsPromiseLike(fakePromise); }, 'should return false for non-promise': function() { /*jshint -W009, -W010, -W053 */ var inputs = [ 1, 0, 'not a promise', true, false, void 0, null, '', /foo/, {}, new Object(), new RegExp('foo'), new Date(), new Boolean(), [], new Array() ]; for(var i = inputs.length - 1; i >= 0; --i) { refuteIsPromiseLike(inputs[i]); } }, 'should return true for delegated promise': function() { function T() {} T.prototype = fakePromise; assertIsPromiseLike(new T()); } }); node-when-3.7.8+ds/test/iterate-test.js000066400000000000000000000113141314733175200177540ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var refute = buster.refute; var fail = buster.referee.fail; var when = require('../when'); var sentinel = {}; var other = {}; function noop() {} buster.testCase('lib/iterate', { 'unfold': { 'should invoke condition first': function(done) { function condition() { return true; } when.unfold(noop, condition, noop, sentinel).then( function(value) { assert.same(value, sentinel); } ).ensure(done); }, 'should call generator until condition returns truthy': function(done) { function condition(i) { return i === 0; } var unspool = this.spy(function(x) { return [x, x-1]; }); when.unfold(unspool, condition, noop, 3).then( function() { assert.equals(unspool.callCount, 3); } ).ensure(done); }, 'generator': { 'should be allowed to return an array of promises': function(done) { function condition(i) { return i === 0; } var unspool = this.spy(function(x) { return [when.resolve(x), when.resolve(x-1)]; }); when.unfold(unspool, condition, noop, 3).then( function() { assert.equals(unspool.callCount, 3); } ).ensure(done); }, 'should be allowed to return a promise for an array': function(done) { function condition(i) { return i === 0; } var unspool = this.spy(function(x) { return when.resolve([x, x-1]); }); when.unfold(unspool, condition, noop, 3).then( function() { assert.equals(unspool.callCount, 3); } ).ensure(done); }, 'should be allowed to return a promise for an array of promises': function(done) { function condition(i) { return i === 0; } var unspool = this.spy(function(x) { return when.resolve([when.resolve(x), when.resolve(x-1)]); }); when.unfold(unspool, condition, noop, 3).then( function() { assert.equals(unspool.callCount, 3); } ).ensure(done); } }, 'condition': { 'should be allowed to return a promise that fulfills': function(done) { function condition(i) { return when.resolve(i === 0); } var unspool = this.spy(function(x) { return [x, x-1]; }); when.unfold(unspool, condition, noop, 3).then( function() { assert.equals(unspool.callCount, 3); } ).ensure(done); }, 'should abort unfold by returning a rejection': function(done) { function condition() { return when.reject(); } var unspool = this.spy(); when.unfold(unspool, condition, noop, 3).then( fail, function() { refute.called(unspool); } ).ensure(done); } }, 'should call handler with generator result': function(done) { function condition(i) { return i === 0; } var handler = this.spy(); function generator() { return [sentinel, 0]; } when.unfold(generator, condition, handler).then( function() { assert.calledOnceWith(handler, sentinel); } ).ensure(done); }, 'should reject when condition throws': function(done) { var generator = this.spy(); var handler = this.spy(); function condition() { throw sentinel; } when.unfold(generator, condition, handler, other).then( fail, function(e) { refute.called(generator); refute.called(handler); assert.same(e, sentinel); } ).ensure(done); }, 'should reject when generator throws': function(done) { var handler = this.spy(); function condition() { return false; } function generator() { throw sentinel; } when.unfold(generator, condition, handler, other).then( fail, function(e) { refute.called(handler); assert.same(e, sentinel); } ).ensure(done); }, 'should reject when transform throws': function(done) { function condition() { return false; } function transform() { throw sentinel; } function generator() { return [other, other]; } when.unfold(generator, condition, transform, other).then( fail, function(e) { assert.same(e, sentinel); } ).ensure(done); } }, 'iterate': { 'should invoke condition first': function() { var called = false; return when.iterate(function(x) { assert(called); return x; }, function() { refute(called); called = true; return true; }, function(x) { assert(called); return x; }, 0).then(function() { assert(called); }); }, 'should return a promise for ultimate result': function() { return when.iterate(function(x) { return x+1; }, function(x) { return x >= 10; }, function(x) { return x; }, 0).then(function(x) { assert.equals(x, 10); }); } } }); node-when-3.7.8+ds/test/join-test.js000066400000000000000000000023121314733175200172540ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var fail = buster.referee.fail; var when, resolved, rejected; when = require('../when'); resolved = when.resolve; rejected = when.reject; buster.testCase('when.join', { 'should resolve empty input': function(done) { return when.join().then( function(result) { assert.equals(result, []); }, fail ).ensure(done); }, 'should join values': function(done) { when.join(1, 2, 3).then( function(results) { assert.equals(results, [1, 2, 3]); }, fail ).ensure(done); }, 'should join promises array': function(done) { when.join(resolved(1), resolved(2), resolved(3)).then( function(results) { assert.equals(results, [1, 2, 3]); }, fail ).ensure(done); }, 'should join mixed array': function(done) { when.join(resolved(1), 2, resolved(3), 4).then( function(results) { assert.equals(results, [1, 2, 3, 4]); }, fail ).ensure(done); }, 'should reject if any input promise rejects': function(done) { when.join(resolved(1), rejected(2), resolved(3)).then( fail, function(failed) { assert.equals(failed, 2); } ).ensure(done); } }); node-when-3.7.8+ds/test/keys-test.js000066400000000000000000000120051314733175200172700ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var fail = buster.referee.fail; var when = require('../when'); var resolve = when.resolve; var reject = when.reject; var keys = require('../keys'); var sentinel = {}; function assertNoKeys(object) { var key, count = 0; for(key in object) { if(object.hasOwnProperty(key)) { count++; } } assert.equals(count, 0); } buster.testCase('when/keys', { 'all': { 'should resolve empty input': function() { return keys.all({}).then(assertNoKeys); }, 'should resolve input values': function(done) { var input = { a: 1, b: 2, c: 3 }; keys.all(input).then( function(results) { assert.equals(results, input); }, fail ).ensure(done); }, 'should resolve promised keys': function(done) { var input = { a: resolve(1), b: 2, c: resolve(3) }; keys.all(input).then( function(results) { assert.equals(results, { a: 1, b: 2, c: 3 }); }, fail ).ensure(done); }, 'should resolve promise for keys': function(done) { var input = { a: resolve(1), b: 2, c: resolve(3) }; keys.all(resolve(input)).then( function(results) { assert.equals(results, { a: 1, b: 2, c: 3 }); }, fail ).ensure(done); }, 'should reject if key rejects': function(done) { var input = { a: 1, b: reject(sentinel), c: 3 }; keys.all(input).then( fail, function(e) { assert.same(e, sentinel); } ).ensure(done); }, 'should reject if input promise rejects': function(done) { keys.all(reject(sentinel)).then( fail, function(e) { assert.same(e, sentinel); } ).ensure(done); } }, 'map': { 'should pass key as second param': function() { var input = { a:1, b:2, c:3 }; return keys.map(input, function(x, k) { assert(typeof k === 'string' && input.hasOwnProperty(k)); return x; }); }, 'should resolve empty input': function() { return keys.map({}).then(assertNoKeys); }, 'should map keys': function(done) { var input = { a: 1, b: 2, c: 3 }; keys.map(input, function(x) { return x + 1; }).then( function(results) { assert.equals(results, { a: 2, b: 3, c: 4 }); }, fail ).ensure(done); }, 'should map promised keys': function(done) { var input = { a: resolve(1), b: 2, c: resolve(3) }; keys.map(input, function(x) { return x + 1; }).then( function(results) { assert.equals(results, { a: 2, b: 3, c: 4 }); }, fail ).ensure(done); }, 'should map promise for keys': function(done) { var input = { a: resolve(1), b: 2, c: resolve(3) }; keys.map(resolve(input), function(x) { return x + 1; }).then( function(results) { assert.equals(results, { a: 2, b: 3, c: 4 }); }, fail ).ensure(done); }, 'should reject if key rejects': function(done) { var input = { a: 1, b: reject(sentinel), c: 3 }; keys.map(input, function(x) { return x + 1; }).then( fail, function(e) { assert.same(e, sentinel); } ).ensure(done); }, 'should reject if input promise rejects': function(done) { keys.map(reject(sentinel), function(x) { return x + 1; }).then( fail, function(e) { assert.same(e, sentinel); } ).ensure(done); }, 'should reject if reduceFunc rejects': function(done) { var input = { a: 1, b: 2, c: 3 }; keys.map(input, function() { return reject(sentinel); }, 0).then( fail, function(e) { assert.same(e, sentinel); } ).ensure(done); }, 'should reject if reduceFunc throws': function(done) { var input = { a: 1, b: 2, c: 3 }; keys.map(input, function() { throw sentinel; }, 0).then( fail, function(e) { assert.same(e, sentinel); } ).ensure(done); } }, 'settle': { 'should resolve empty input': function() { return keys.settle({}).then(assertNoKeys); }, 'should resolve promise for keys': function(done) { var input = { a:1, b:2, c:3 }; return keys.settle(input).then( function(results) { assert.equals( results, { a: { state: 'fulfilled', value: 1 }, b: { state: 'fulfilled', value: 2 }, c: { state: 'fulfilled', value: 3 } } ); }, fail ).ensure(done); }, 'should resolve promised keys': function(done) { var input = { a: resolve(1), b: 2, c: resolve(3) }; keys.settle(input).then( function(results) { assert.equals( results, { a: { state: 'fulfilled', value: 1 }, b: { state: 'fulfilled', value: 2 }, c: { state: 'fulfilled', value: 3 } } ); }, fail ).ensure(done); }, 'should not reject if key rejects': function(done) { var input = { a: 1, b: reject('reason'), c: 3 }; keys.settle(input).then( function(results) { assert.equals( results, { a: { state: 'fulfilled', value: 1 }, b: { state: 'rejected', reason: 'reason' }, c: { state: 'fulfilled', value: 3 } } ); }, fail ).ensure(done); } } }); node-when-3.7.8+ds/test/liftAll-test.js000066400000000000000000000046171314733175200177160ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var refute = buster.refute; var liftAll = require('../lib/liftAll'); var sentinel = {}; function lift(f) { return function() { return f.apply(this, arguments); }; } buster.testCase('when/lib/liftAll', { 'should call lift for src own methods': function() { var src = { a: this.spy(), b: this.spy() }; var dst = liftAll(lift, void 0, void 0, src); dst.a(1); dst.b(2); assert.calledOnceWith(src.a, 1); assert.calledOnceWith(src.b, 2); }, 'should not call lift for non-functions': function() { var src = { a: this.spy(), c: sentinel }; var dst = liftAll(lift, void 0, void 0, src); assert.same(dst.c, sentinel); }, 'when dst not provided': { 'and src is an object': { 'should lift onto Object.create(src)': function() { var src = { a: this.spy(), b: sentinel }; var dst = liftAll(lift, void 0, void 0, src); refute.same(src, dst); assert.isObject(dst); assert.same(dst.b, sentinel); assert(dst.hasOwnProperty('a')); refute(dst.hasOwnProperty('b')); } }, 'and src is a function': { 'should lift onto a "copy" of src': function() { var src = this.spy(); src.a = this.spy(); var dst = liftAll(lift, void 0, void 0, src); refute.same(src, dst); assert.isFunction(dst); assert(dst.hasOwnProperty('a')); dst.a(); assert.calledOnce(src.a); } } }, 'when dst is provided': { 'when dst is an object': { 'should lift onto dst': function() { var src = { a: function(){}, b: sentinel }; var d = {}; var dst = liftAll(lift, void 0, d, src); assert.same(dst, d); } }, 'when dst is a function': { 'should lift onto dst': function() { var src = { a: function(){}, b: sentinel }; var d = function(){}; var dst = liftAll(lift, void 0, d, src); assert.same(dst, d); } } }, 'when combine is provided': { 'should call combine for all src own methods': function() { function addKey(o, f, k) { o[k+'Test'] = f; return o; } var src = { a: this.spy(), b: this.spy() }; var dst = liftAll(lift, addKey, void 0, src); dst.aTest(1); assert.calledOnceWith(src.a, 1); assert.isFunction(dst.a); refute(dst.hasOwnProperty('a')); dst.bTest(2); assert.calledOnceWith(src.b, 2); assert.isFunction(dst.b); refute(dst.hasOwnProperty('b')); } } }); node-when-3.7.8+ds/test/map-test.js000066400000000000000000000057271314733175200171070ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var fail = buster.referee.fail; var when = require('../when'); var resolved = when.resolve; var reject = when.reject; /*global setInterval,clearInterval*/ function mapper(val) { return val * 2; } function deferredMapper(val) { return when(mapper(val)).delay(Math.random()*10); } function identity(x) { return x; } buster.testCase('when.map', { 'should pass index to predicate as second param': function() { return when.map(['a','b','c'], function(x, i) { assert(typeof i === 'number'); return x; }); }, 'should map input values array': function(done) { var input = [1, 2, 3]; when.map(input, mapper).then( function(results) { assert.equals(results, [2,4,6]); }, fail ).ensure(done); }, 'should map input promises array': function(done) { var input = [resolved(1), resolved(2), resolved(3)]; when.map(input, mapper).then( function(results) { assert.equals(results, [2,4,6]); }, fail ).ensure(done); }, 'should map mixed input array': function(done) { var input = [1, resolved(2), 3]; when.map(input, mapper).then( function(results) { assert.equals(results, [2,4,6]); }, fail ).ensure(done); }, 'should map input when mapper returns a promise': function(done) { var input = [1,2,3]; when.map(input, deferredMapper).then( function(results) { assert.equals(results, [2,4,6]); }, fail ).ensure(done); }, 'should accept a promise for an array': function(done) { when.map(resolved([1, resolved(2), 3]), mapper).then( function(result) { assert.equals(result, [2,4,6]); }, fail ).ensure(done); }, 'should resolve to empty array when input promise does not resolve to an array': function(done) { when.map(resolved(123), mapper).then( function(result) { assert.equals(result, []); }, fail ).ensure(done); }, 'should map input promises when mapper returns a promise': function(done) { var input = [resolved(1),resolved(2),resolved(3)]; when.map(input, mapper).then( function(results) { assert.equals(results, [2,4,6]); }, fail ).ensure(done); }, 'should reject when input contains rejection': function(done) { var input = [resolved(1), reject(2), resolved(3)]; when.map(input, mapper).then( fail, function(result) { assert.equals(result, 2); } ).ensure(done); }, 'should propagate progress': function() { // Thanks @depeele for this test var input = [_resolver(1), _resolver(2), _resolver(3)]; var ncall = 0; return when.map(input, identity).then( function() { assert.equals(ncall, 6); }, fail, function() { ncall++; } ); function _resolver(id) { return when.promise(function(resolve, reject, notify) { var loop = 0; var timer = setInterval(function () { notify(id); loop++; if (loop === 2) { clearInterval(timer); resolve(id); } }, 1); }); } } }); node-when-3.7.8+ds/test/monitor/000077500000000000000000000000001314733175200164735ustar00rootroot00000000000000node-when-3.7.8+ds/test/monitor/PromiseMonitor-test.js000066400000000000000000000007701314733175200230000ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var fail = buster.referee.fail; var Promise = require('../../lib/Promise'); var PromiseMonitor = require('../../monitor/PromiseMonitor'); buster.testCase('when/monitor/PromiseMonitor', { 'should call reporter.configurePromiseMonitor with self': function() { var spy = this.spy(); var m = new PromiseMonitor({ configurePromiseMonitor: spy }); assert.calledOnceWith(spy, m); } }); node-when-3.7.8+ds/test/monitor/all.js000066400000000000000000000010541314733175200176010ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** * Licensed under the MIT License at: * http://www.opensource.org/licenses/mit-license.php * * @author: Brian Cavalier * @author: John Hann */ (function(define) { 'use strict'; define(function(require) { // require('../../monitor/console'); var when = require('../../when'); var p = when.reject(new Error('fail1')); when.all([p]); }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/test/monitor/deep-chain.js000066400000000000000000000024051314733175200210270ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** * Licensed under the MIT License at: * http://www.opensource.org/licenses/mit-license.php * * @author: Brian Cavalier * @author: John Hann */ (function(define) { 'use strict'; define(function(require) { // require('../../monitor/console'); var Promise = require('../../when').Promise; function f1() { return Promise.resolve(123); } console.log('*** Creating deep promise rejection chain ***'); var p = f1(); p = p.then(ok); p = p.then(ok); // Cause an unhandled rejection deep in the promise chain // It's unhandled because after this statement, p is a // rejected promise but has no onRejected handler // This should be logged p = p.then(reject); // Some time later, handle the rejection // When this happens, p suddenly becomes handled (obviously!), // and this will be logged as well. setTimeout(function() { console.log('*** handling rejection ***'); // p.done(); p.catch(ok); }, 1337); function ok(x) { return x; } function reject(x) { return Promise.reject(new Error('error originates here')); } }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/test/monitor/delay-handled.js000066400000000000000000000005771314733175200215350ustar00rootroot00000000000000(function(define) { 'use strict'; define(function(require) { var when = require('../../when'); var async = require('../../lib/env').asap; var p = when.reject(new Error('TEST FAILED, should not see this')); async(function() { p.catch(function(){}); }); }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/test/monitor/developer-error.js000066400000000000000000000014041314733175200221440ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** * Licensed under the MIT License at: * http://www.opensource.org/licenses/mit-license.php * * @author: Brian Cavalier * @author: John Hann */ (function(define) { 'use strict'; define(function(require) { // require('../../monitor/console'); var Promise = require('../../when').Promise; var p = Promise.resolve(123); p.then(function() { oops(); }); function infiniteRecursion() { infiniteRecursion(); } p.then(infiniteRecursion); var notAFunction = {}; function tryToCallNotAFunction() { notAFunction(); } p.then(tryToCallNotAFunction); }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/test/monitor/done.js000066400000000000000000000013351314733175200177600ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** * Licensed under the MIT License at: * http://www.opensource.org/licenses/mit-license.php * * @author: Brian Cavalier * @author: John Hann */ (function(define) { 'use strict'; define(function(require) { // require('../../monitor/console'); var Promise = require('../../when').Promise; Promise.resolve(123) .then(function(x) { // throw x; throw new Error(x); // return Promise.reject(x); // foo(); // throw new TypeError(x); }) // .then(void 0, function() { console.log(123);}) .done(console.log); }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/test/monitor/index.html000066400000000000000000000006021314733175200204660ustar00rootroot00000000000000 node-when-3.7.8+ds/test/monitor/lift-node.js000066400000000000000000000002601314733175200207100ustar00rootroot00000000000000//require('../../monitor/console'); var node = require('../../node'); function test(cb) { throw new Error('fail'); // cb(new Error('fail')); } var f = node.lift(test); f();node-when-3.7.8+ds/test/monitor/map.js000066400000000000000000000013031314733175200176030ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** * Licensed under the MIT License at: * http://www.opensource.org/licenses/mit-license.php * * @author: Brian Cavalier * @author: John Hann */ (function(define) { 'use strict'; define(function(require) { // require('../../monitor/console'); var when = require('../../when'); var p = when.reject(new Error('fail1')); // when.map(p, function(x){return x;}); when.map([p], function(x){return x;}); // when.map([123], fail); function fail(x){ throw new Error('map failed'); } }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/test/monitor/multiple-escapes.js000066400000000000000000000014761314733175200223150ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** * Licensed under the MIT License at: * http://www.opensource.org/licenses/mit-license.php * * @author: Brian Cavalier * @author: John Hann */ (function(define) { 'use strict'; define(function(require) { // require('../../monitor/console'); var Promise = require('../../when').Promise; var i = 1; var p = new Promise(function(_, reject) { setTimeout(reject.bind(null, new Error(i++)), 1); }); var p = new Promise(function(_, reject) { setTimeout(reject.bind(null, new Error(i++)), 1); }); var p = new Promise(function(_, reject) { setTimeout(reject.bind(null, new Error(i++)), 1); }); }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/test/monitor/unhandled-begets-unhandled.js000066400000000000000000000014231314733175200242020ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** * Licensed under the MIT License at: * http://www.opensource.org/licenses/mit-license.php * * @author: Brian Cavalier * @author: John Hann */ (function(define) { 'use strict'; define(function(require) { // require('../../monitor/console'); var Promise = require('../../when').Promise; // var Promise = require('../../es6-shim/Promise'); var p = new Promise.reject(new Error('first error')); setTimeout(function() { // console.log('***Begetting new unhandled error now***'); p['catch'](function() { throw new Error('unhandled-begets-unhandled'); }); }, 2000); }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/test/monitor/unhandled-forever.js000066400000000000000000000014111314733175200224360ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** * Licensed under the MIT License at: * http://www.opensource.org/licenses/mit-license.php * * @author: Brian Cavalier * @author: John Hann */ (function(define) { 'use strict'; define(function(require) { // require('../../monitor/console'); var Promise = require('../../when').Promise; function f1() { return new Promise(function(_, reject) { reject(new Error('unhandled-forever')); }); } function f2(p) { return p.then(function() {}); } function f3(p) { return p.then(function() {}); } // f1(); // f2(f1()); f3(f2(f1())); }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/test/monitor/unhandled-handled-later.js000066400000000000000000000015511314733175200234770ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** * Licensed under the MIT License at: * http://www.opensource.org/licenses/mit-license.php * * @author: Brian Cavalier * @author: John Hann */ (function(define) { 'use strict'; define(function(require) { // require('../../monitor/console'); var Promise = require('../../when').Promise; // var Promise = require('bluebird'); function run() { var p = new Promise(function(_, reject) { reject(new Error('unhandled-handled-later')); }); setTimeout(function() { // console.log('***Handling error now***'); p['catch'](function() { /* handled by squelching */ }); }, 1000); } run(); // run(); // run(); // run(); // run(); // run(); // run(); }); }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); })); node-when-3.7.8+ds/test/monitor/unhandledRejectionApi-test.js000066400000000000000000000014631314733175200242510ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var fail = buster.referee.fail; var Promise = require('../../lib/Promise'); function replace(target, method, replacement) { var tmp = target[method]; target[method] = function() { target[method] = tmp; return replacement.apply(this, arguments); }; } buster.testCase('when/unhandledRejectionApi', { 'reject should trigger report': function(done) { replace(Promise, 'onPotentiallyUnhandledRejection', function () { assert(true); done(); }); new Promise(function (_, reject) { reject(); }); }, 'Promise.reject should trigger report': function(done) { replace(Promise, 'onPotentiallyUnhandledRejection', function () { assert(true); done(); }); Promise.reject(); } }); node-when-3.7.8+ds/test/node-test.js000066400000000000000000000260451314733175200172530ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var refute = buster.refute; var fail = buster.referee.fail; var when = require('../when'); var nodefn = require('../node'); var sentinel = { value: 'sentinel' }; var other = { value: 'other' }; function assertIsPromise(something) { var message = 'Object is not a promise'; buster.assert(when.isPromiseLike(something), message); } buster.testCase('when/node', { 'apply': { 'should return promise': function() { assertIsPromise(nodefn.apply(function() {})); }, 'should preserve thisArg': function() { return nodefn.apply.call(sentinel, function(cb) { assert.same(this, sentinel); cb(null); }); }, 'the returned promise': { 'should be resolved with the 2nd arg to the callback': function() { function async(cb) { setTimeout(function() { cb(null, sentinel); }, 100); } var promise = nodefn.apply(async); return promise.then(function(value) { assert.same(value, sentinel); }); }, 'should be rejected with the 1st arg to the callback': function() { function async(cb) { cb(other); } var promise = nodefn.apply(async); return promise.then(fail, function(reason) { assert.same(reason, other); }); }, 'should be resolved to an array for multi-arg callbacks': function() { function async(cb) { cb(null, 10, 20, 30); } var promise = nodefn.apply(async); return promise.then(function(values) { assert.equals(values, [10, 20, 30]); }); } }, 'should forward an array of args to the function': function() { function async(x, y, cb) { cb(null, x + y); } var promise = nodefn.apply(async, ['a', 'b']); return promise.then(function(value) { assert.equals(value, 'ab'); }); }, 'should handle promises on the args array': function() { function async(x, y, cb) { cb(null, x + y); } var promise = nodefn.apply(async, [when('a'), 'b']); return promise.then(function(value) { assert.equals(value, 'ab'); }); } }, 'call': { 'should return promise': function() { assertIsPromise(nodefn.call(function() {})); }, 'should preserve thisArg': function() { return nodefn.call.call(sentinel, function(cb) { assert.same(this, sentinel); cb(null); }); }, 'the returned promise': { 'should be resolved with the 2nd arg to the callback': function() { function async(cb) { cb(null, sentinel); } var promise = nodefn.call(async); return promise.then(function(value) { assert.same(value, sentinel); }); }, 'should be rejected with the 1st arg to the callback': function() { function async(cb) { cb(sentinel); } var promise = nodefn.call(async); return promise.then(fail, function(reason) { assert.same(reason, sentinel); }); }, 'should be resolved to an array for multi-arg callbacks': function() { function async(cb) { cb(null, 10, 20, 30); } var promise = nodefn.call(async); return promise.then(function(values) { assert.equals(values, [10, 20, 30]); }); } }, 'should forward extra arguments to the function': function() { function async(x, y, cb) { cb(null, x + y); } var promise = nodefn.call(async, 'a', 'b'); return promise.then(function(value) { assert.equals(value, 'ab'); }); }, 'should handle promises on the args array': function() { function async(x, y, cb) { cb(null, x + y); } var promise = nodefn.call(async, when('a'), 'b'); return promise.then(function(value) { assert.equals(value, 'ab'); }); } }, 'lift': { 'should return a function': function() { assert.isFunction(nodefn.lift(function() {})); }, 'should preserve thisArg': function() { return nodefn.lift(function(cb) { assert.same(this, sentinel); cb(null); }).call(sentinel); }, 'the returned function': { 'should return a promise': function() { var result = nodefn.lift(function() {}); assertIsPromise(result()); }, 'should resolve the promise with the callback value': function() { var result = nodefn.lift(function(callback) { callback(null, sentinel); }); return result().then(function(value) { assert.same(value, sentinel); }); }, 'should handle promises as arguments': function() { var result = nodefn.lift(function(x, callback) { callback(null, x); }); return result(when(sentinel)).then(function(value) { assert.same(value, sentinel); }); }, 'should reject the promise with the error argument': function() { var result = nodefn.lift(function(callback) { callback(sentinel); }); return result().then(fail, function(reason) { assert.same(reason, sentinel); }); }, 'should resolve the promise to an array for mult-args': function() { var result = nodefn.lift(function(callback) { callback(null, 10, 20, 30); }); return result().then(function(values) { assert.equals(values, [10, 20, 30]); }); } }, 'should accept leading arguments': function() { function async(x, y, callback) { callback(null, x + y); } var partiallyApplied = nodefn.lift(async, 'a'); return partiallyApplied('b').then(function(value) { assert.equals(value, 'ab'); }, fail); }, 'should accept promises as leading arguments': function() { function async(x, y, callback) { callback(null, x + y); } var partiallyApplied = nodefn.lift(async, when('a')); return partiallyApplied('b').then(function(value) { assert.equals(value, 'ab'); }); } }, 'createCallback': { 'should return a function': function() { assert.isFunction(nodefn.createCallback({})); }, 'the returned function': { 'should resolve the resolver when called without errors': function() { var deferred = when.defer(); var callback = nodefn.createCallback(deferred.resolver); callback(null, 10); return deferred.promise.then(function(value) { assert.equals(value, 10); }, fail); }, 'should reject the resolver when called with errors': function(done) { var deferred = when.defer(); var callback = nodefn.createCallback(deferred.resolver); callback(sentinel); return deferred.promise.then(fail, function(reason) { assert.same(reason, sentinel); }).done(done); }, 'should pass multiple arguments as an array': function() { var deferred = when.defer(); var callback = nodefn.createCallback(deferred.resolver); callback(null, 10, 20, 30); return deferred.promise.then(function(value) { assert.equals(value, [10, 20, 30]); }); } } }, 'bindCallback': { 'should return a promise': function () { assert.isFunction(nodefn.bindCallback(when.resolve(true), function(){}).then); }, 'should register callback as callback': function (done) { function callback(_, val) { assert.same(val, sentinel); done(); } return nodefn.bindCallback( when.resolve(sentinel), callback ); }, 'should register callback as errback': function (done) { function callback(err) { assert.same(err, sentinel); done(); } return nodefn.bindCallback( when.reject(sentinel), callback ); }, 'should handle null values': function () { return nodefn.bindCallback( when.resolve(sentinel), null ).then(function (value) { assert.same(value, sentinel); }); }, 'returned promise': { 'should be fulfilled with the original value': function (done) { function callback() { return other; } return nodefn.bindCallback( when.resolve(sentinel), callback ).then(function (value) { assert.same(value, sentinel); }).ensure(done); }, 'should be rejected with the original error': function (done) { function callback() { return other; } return nodefn.bindCallback( when.reject(sentinel), callback ).then(fail, function (reason) { assert.same(reason, sentinel); }).ensure(done); }, 'should fire onFulfilled before the callback': function (done) { var callbackRan = false; function callback() { callbackRan = true; } return nodefn.bindCallback( when.resolve(sentinel), callback ).then(function (value) { assert.same(value, sentinel); refute(callbackRan); }).ensure(done); }, 'should fire onRejected before the callback': function (done) { var callbackRan = false; function callback() { callbackRan = true; } return nodefn.bindCallback( when.reject(sentinel), callback ).then(fail, function (reason) { assert.same(reason, sentinel); refute(callbackRan); }).ensure(done); } } }, 'liftCallback': { 'should return a function': function () { assert.isFunction(nodefn.liftCallback(function(){})); }, 'wrapped callback': { 'should return a promise': function () { var lifted = nodefn.liftCallback(function(){}); assert.isFunction(lifted(when.resolve(true)).then); }, 'should register callback as callback': function (done) { function callback(_, val) { assert.same(val, sentinel); done(); } var lifted = nodefn.liftCallback(callback); return lifted(when.resolve(sentinel)); }, 'should register callback as errback': function (done) { function callback(err) { assert.same(err, sentinel); done(); } var lifted = nodefn.liftCallback(callback); return lifted(when.reject(sentinel)); }, 'should handle null values': function () { var lifted = nodefn.liftCallback(null); return lifted(when.resolve(sentinel)).then(function (value) { assert.same(value, sentinel); }); }, 'returned promise': { 'should be fulfilled with the original value': function (done) { function callback() { return other; } var lifted = nodefn.liftCallback(callback); return lifted(when.resolve(sentinel)).then(function (value) { assert.same(value, sentinel); }).ensure(done); }, 'should be rejected with the original error': function (done) { function callback() { return other; } var lifted = nodefn.liftCallback(callback); return lifted(when.reject(sentinel)).then(fail, function (reason) { assert.same(reason, sentinel); }).ensure(done); }, 'should fire onFulfilled before the callback': function (done) { var callbackRan = false; function callback() { callbackRan = true; } var lifted = nodefn.liftCallback(callback); return lifted(when.resolve(sentinel)).then(function (value) { assert.same(value, sentinel); refute(callbackRan); }).ensure(done); }, 'should fire onRejected before the callback': function (done) { var callbackRan = false; function callback() { callbackRan = true; } var lifted = nodefn.liftCallback(callback); return lifted(when.reject(sentinel)).then(fail, function (reason) { assert.same(reason, sentinel); refute(callbackRan); }).ensure(done); } } } } }); node-when-3.7.8+ds/test/parallel-test.js000066400000000000000000000024231314733175200201140ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var when = require('../when'); var parallel = require('../parallel'); function createTask(y) { return function() { return y; }; } function expectArgs(expected) { return function() { var args = Array.prototype.slice.call(arguments); assert.equals(args, expected); }; } buster.testCase('when/parallel', { 'should execute all tasks': function() { return parallel([createTask(1), createTask(2), createTask(3)]).then( function(result) { assert.equals(result, [1, 2, 3]); } ); }, 'should resolve to empty array when no tasks supplied': function() { return parallel([], 1, 2, 3).then( function(result) { assert.equals(result, []); } ); }, 'should pass args to all tasks': function(done) { var expected, tasks; expected = [1, 2, 3]; tasks = [expectArgs(expected), expectArgs(expected), expectArgs(expected)]; parallel.apply(void 0, [tasks].concat(expected)).ensure(done); }, 'should accept promises for args': function(done) { var expected, tasks; expected = [1, 2, 3]; tasks = [expectArgs(expected), expectArgs(expected), expectArgs(expected)]; parallel.apply(void 0, [tasks].concat(expected.map(when))).ensure(done); } }); node-when-3.7.8+ds/test/pipeline-test.js000066400000000000000000000026411314733175200201270ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var when = require('../when'); var pipeline = require('../pipeline'); function createTask(y) { return function(x) { return x + y; }; } buster.testCase('when/pipeline', { 'should execute tasks in order': function() { return pipeline([createTask('b'), createTask('c'), createTask('d')], 'a').then( function(result) { assert.equals(result, 'abcd'); } ); }, 'should resolve to initial args when no tasks supplied': function() { return pipeline([], 'a', 'b').then( function(result) { assert.equals(result, ['a', 'b']); } ); }, 'should resolve to empty array when no tasks and no args supplied': function() { return pipeline([]).then( function(result) { assert.equals(result, []); } ); }, 'should pass args to initial task': function() { var expected, tasks; expected = [1, 2, 3]; tasks = [this.spy()]; return pipeline.apply(null, [tasks].concat(expected)).then( function() { assert.calledOnceWith.apply(assert, tasks.concat(expected)); } ); }, 'should allow initial args to be promises': function() { var expected, tasks; expected = [1, 2, 3]; tasks = [this.spy()]; return pipeline.apply(null, [tasks].concat([when(1), when(2), when(3)])).then( function() { assert.calledOnceWith.apply(assert, tasks.concat(expected)); } ); } }); node-when-3.7.8+ds/test/poll-test.js000066400000000000000000000055311314733175200172710ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var fail = buster.referee.fail; var when = require('../when'); var poll = require('../poll'); function failIfCalled(done, message) { return function () { fail(message || 'should never be called'); done(); }; } buster.testCase('when/poll', { 'should poll until canceled': function (done) { var i, p, progback; i = 0; p = poll(function () { i += 1; return i; }, 10); progback = this.spy(function (result) { assert.equals(i, result); }); p.then( failIfCalled(done, 'should never be resolved'), function () { assert(progback.called); done(); }, progback ); when().delay(100).then(p.cancel); }, 'should poll with interval function': function (done) { var countdown, interval; countdown = 3; interval = this.spy(function () { return when().delay(10); }); poll(function () {}, interval, function () { countdown -= 1; return countdown === 0; }).then( function () { assert(interval.calledTwice); done(); }, failIfCalled(done, 'should never be rejected') ); }, 'should be canceled by rejected work': function (done) { var p = poll(when.reject, 10); p.then( failIfCalled(done, 'should never be resolved'), function () { assert(true); done(); }, failIfCalled(done, 'should never receive progress') ); }, 'should poll with delayed start': function (done) { var i, p, progback; i = 0; p = poll(function () { i += 1; return i; }, 10, function (result) { return result === 2; }, true); progback = this.spy(function (result) { assert.equals(result, 1); }); p.then( function (result) { assert.equals(result, 2); assert(progback.called); done(); }, failIfCalled(done), progback ); }, 'should keep polling from rejected verification, stop for resolved verification': function (done) { var i, p, progback; i = 0; p = poll(function () { i += 1; return i; }, 10, function () { return i < 3 ? when.reject() : when.resolve(true); }); progback = this.spy(function (result) { assert.equals(result, i); }); p.then( function (result) { assert.equals(result, 3); assert(progback.calledTwice); done(); }, failIfCalled(done, 'should never be rejected'), progback ); }, 'should keep polling from falsey resolved verification, stop for truthy resolved verification': function (done) { var i, p, progback; i = 0; p = poll(function () { i += 1; return i; }, 10, function (result) { return result < 3 ? when.resolve(false) : when.resolve(true); }); progback = this.spy(function (result) { assert.equals(result, i); }); p.then( function (result) { assert.equals(result, 3); assert(progback.calledTwice); done(); }, failIfCalled(done, 'should never be rejected'), progback ); } }); node-when-3.7.8+ds/test/promise-test.js000066400000000000000000000421141314733175200177770ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var refute = buster.refute; var fail = buster.referee.fail; var when = require('../when'); var CorePromise = when.Promise; var sentinel = { value: 'sentinel' }; var other = { value: 'other' }; var slice = Array.prototype.slice; // In case of testing in an environment without Object.isFrozen //var isFrozen = Object.isFrozen || function() { return true; }; function f() {} function assertPending(s) { assert.equals(s.state, 'pending'); } function assertFulfilled(s, value) { assert.equals(s.state, 'fulfilled'); assert.same(s.value, value); } function assertRejected(s, reason) { assert.equals(s.state, 'rejected'); assert.same(s.reason, reason); } buster.testCase('promise', { // TODO: Reinstate when v8 Object.freeze() performance is sane // 'should be frozen': function() { // assert(isFrozen(defer().promise)); // }, 'done': { setUp: function() { this.origOnFatalRejection = CorePromise.onFatalRejection; }, tearDown: function() { CorePromise.onFatalRejection = this.origOnFatalRejection; }, 'should return undefined': function() { refute.defined(when.resolve().done(f, f)); refute.defined(when.reject().done(f, f)); }, 'when fulfilled': { 'should invoke handleValue': function(done) { when.resolve(sentinel).done(function(x) { assert.same(x, sentinel); done(); }); }, 'should be fatal': { 'when handleValue throws': function(done) { var p = when.resolve(); CorePromise.onFatalRejection = function testFatal(e) { assert.same(e.value, sentinel); done(); }; p.done(function() { throw sentinel; }); }, 'when handleValue rejects': function(done) { var p = when.resolve(); CorePromise.onFatalRejection = function testFatal(e) { assert.same(e.value, sentinel); done(); }; p.done(function() { return when.reject(sentinel); }); } } }, 'when rejected': { 'should invoke handleFatalError': function(done) { when.reject(sentinel).done(null, function(e) { assert.same(e, sentinel); done(); }); }, 'should be fatal': { 'when no handleFatalError provided': function(done) { var p = when.reject(sentinel); CorePromise.onFatalRejection = function testFatal(e) { assert.same(e.value, sentinel); done(); }; p.done(); }, 'when handleFatalError throws': function(done) { var p = when.reject(other); CorePromise.onFatalRejection = function testFatal(e) { assert.same(e.value, sentinel); done(); }; p.done(void 0, function() { throw sentinel; }); }, 'when handleFatalError rejects': function(done) { var p = when.reject(); CorePromise.onFatalRejection = function testFatal(e) { assert.same(e.value, sentinel); done(); }; p.done(void 0, function() { return when.reject(sentinel); }); } } } }, 'then': { 'should return a promise': function() { assert.isFunction(when.defer().promise.then().then); }, 'should allow a single callback function': function() { assert.isFunction(when.defer().promise.then(f).then); }, 'should allow a callback and errback function': function() { assert.isFunction(when.defer().promise.then(f, f).then); }, 'should allow a callback, errback, and progback function': function() { assert.isFunction(when.defer().promise.then(f, f, f).then); }, 'should allow null and undefined': function() { assert.isFunction(when.defer().promise.then().then); assert.isFunction(when.defer().promise.then(null).then); assert.isFunction(when.defer().promise.then(null, null).then); assert.isFunction(when.defer().promise.then(null, null, null).then); assert.isFunction(when.defer().promise.then(void 0).then); assert.isFunction(when.defer().promise.then(void 0, void 0).then); assert.isFunction(when.defer().promise.then(void 0, void 0, void 0).then); }, 'should allow functions and null or undefined to be mixed': function() { assert.isFunction(when.defer().promise.then(f, null).then); assert.isFunction(when.defer().promise.then(f, null, null).then); assert.isFunction(when.defer().promise.then(null, f).then); assert.isFunction(when.defer().promise.then(null, f, null).then); assert.isFunction(when.defer().promise.then(null, null, f).then); }, 'should ignore non-functions': { 'when fulfillment handler': { 'is empty string': function(done) { when.resolve(true).then('').then(assert, fail).ensure(done); }, 'is false': function(done) { when.resolve(true).then(false).then(assert, fail).ensure(done); }, 'is true': function(done) { when.resolve(true).then(true).then(assert, fail).ensure(done); }, 'is object': function(done) { when.resolve(true).then({}).then(assert, fail).ensure(done); }, 'is falsey': function(done) { when.resolve(true).then(0).then(assert, fail).ensure(done); }, 'is truthy': function(done) { when.resolve(true).then(1).then(assert, fail).ensure(done); } }, 'when rejection handler': { 'is empty string': function(done) { when.reject(true).then(null, '').then(fail, assert).ensure(done); }, 'is false': function(done) { when.reject(true).then(null, false).then(fail, assert).ensure(done); }, 'is true': function(done) { when.reject(true).then(null, true).then(fail, assert).ensure(done); }, 'is object': function(done) { when.reject(true).then(null, {}).then(fail, assert).ensure(done); }, 'is falsey': function(done) { when.reject(true).then(null, 0).then(fail, assert).ensure(done); }, 'is truthy': function(done) { when.reject(true).then(null, 1).then(fail, assert).ensure(done); } }, 'when progress handler': { 'is empty string': function(done) { var d = when.defer(); d.promise.then(null, null, '').then(fail, fail, assert).then(null, null, done); d.notify(true); }, 'is false': function(done) { var d = when.defer(); d.promise.then(null, null, false).then(fail, fail, assert).then(null, null, done); d.notify(true); }, 'is true': function(done) { var d = when.defer(); d.promise.then(null, null, true).then(fail, fail, assert).then(null, null, done); d.notify(true); }, 'is object': function(done) { var d = when.defer(); d.promise.then(null, null, {}).then(fail, fail, assert).then(null, null, done); d.notify(true); }, 'is falsey': function(done) { var d = when.defer(); d.promise.then(null, null, 0).then(fail, fail, assert).then(null, null, done); d.notify(true); }, 'is truthy': function(done) { var d = when.defer(); d.promise.then(null, null, 1).then(fail, fail, assert).then(null, null, done); d.notify(true); } } } }, 'should preserve object whose valueOf() differs from original object': function(done) { var d, expected; d = when.defer(); expected = new Date(); d.promise.then( function(val) { assert.same(val, expected); }, fail ).ensure(done); d.resolve(expected); }, 'should forward result when callback is null': function(done) { var d = when.defer(); d.promise.then( null, fail ).then( function(val) { assert.equals(val, 1); }, fail ).ensure(done); d.resolve(1); }, 'should forward callback result to next callback': function(done) { var d = when.defer(); d.promise.then( function(val) { return val + 1; }, fail ).then( function(val) { assert.equals(val, 2); }, fail ).ensure(done); d.resolve(1); }, 'should forward undefined': function(done) { var d = when.defer(); d.promise.then( function() { // intentionally return undefined }, fail ).then( function(val) { refute.defined(val); }, fail ).ensure(done); d.resolve(1); }, 'should forward undefined rejection value': function(done) { var d = when.defer(); d.promise.then( fail, function() { // presence of rejection handler is enough to switch back // to resolve mode, even though it returns undefined. // The ONLY way to propagate a rejection is to re-throw or // return a rejected promise; } ).then( function(val) { refute.defined(val); }, fail ).ensure(done); d.reject(1); }, 'should forward promised callback result value to next callback': function(done) { var d = when.defer(); d.promise.then( function(val) { var d = when.defer(); d.resolve(val + 1); return d.promise; }, fail ).then( function(val) { assert.equals(val, 2); }, fail ).ensure(done); d.resolve(1); }, 'should switch from callbacks to errbacks when callback returns a rejection': function(done) { var d = when.defer(); d.promise.then( function(val) { var d = when.defer(); d.reject(val + 1); return d.promise; }, fail ).then( fail, function(val) { assert.equals(val, 2); } ).ensure(done); d.resolve(1); }, 'when an exception is thrown': { 'a resolved promise': { 'should reject if the exception is a value': function(done) { var d = when.defer(); d.promise.then( function() { throw sentinel; }, fail ).then( fail, function(val) { assert.same(val, sentinel); } ).ensure(done); d.resolve(); }, 'should reject if the exception is a resolved promise': function(done) { var d, expected; d = when.defer(); expected = when.resolve(); d.promise.then( function() { throw expected; }, fail ).then( fail, function(val) { assert.same(val, expected); } ).ensure(done); d.resolve(); }, 'should reject if the exception is a rejected promise': function(done) { var d, expected; d = when.defer(); expected = when.reject(); d.promise.then( function() { throw expected; }, fail ).then( fail, function(val) { assert.same(val, expected); } ).ensure(done); d.resolve(); } }, 'a rejected promise': { 'should reject if the exception is a value': function(done) { var d = when.defer(); d.promise.then( null, function() { throw sentinel; } ).then( fail, function(val) { assert.same(val, sentinel); } ).ensure(done); d.reject(); }, 'should reject if the exception is a resolved promise': function(done) { var d, expected; d = when.defer(); expected = when.resolve(); d.promise.then( null, function() { throw expected; } ).then( fail, function(val) { assert.same(val, expected); } ).ensure(done); d.reject(); }, 'should reject if the exception is a rejected promise': function(done) { var d, expected; d = when.defer(); expected = when.reject(); d.promise.then( null, function() { throw expected; } ).then( fail, function(val) { assert.same(val, expected); } ).ensure(done); d.reject(); } } }, 'should switch from errbacks to callbacks when errback does not explicitly propagate': function(done) { var d = when.defer(); d.promise.then( fail, function(val) { return val + 1; } ).then( function(val) { assert.equals(val, 2); }, fail ).ensure(done); d.reject(1); }, 'should switch from errbacks to callbacks when errback returns a resolution': function(done) { var d = when.defer(); d.promise.then( fail, function(val) { var d = when.defer(); d.resolve(val + 1); return d.promise; } ).then( function(val) { assert.equals(val, 2); }, fail ).ensure(done); d.reject(1); }, 'should propagate rejections when errback returns a rejection': function(done) { var d = when.defer(); d.promise.then( fail, function(val) { var d = when.defer(); d.reject(val + 1); return d.promise; } ).then( fail, function(val) { assert.equals(val, 2); } ).ensure(done); d.reject(1); }, 'should call progback': function(done) { var expected, d; expected = {}; d = when.defer(); d.promise.then(null, null, function (status) { assert.same(status, expected); done(); }); d.notify(expected); }, 'catch': { 'should be an alias for otherwise': function() { var p = when.resolve(); assert.same(p['catch'], p.otherwise); } }, 'otherwise': { 'should return a promise': function() { assert.isFunction(when.defer().promise.otherwise().then); }, 'should register errback': function() { return when.reject(sentinel).otherwise( function(val) { assert.same(val, sentinel); }); } }, 'yield': { 'should return a promise': function() { assert.isFunction(when.defer().promise.yield().then); }, 'should fulfill with the supplied value': function() { return when.resolve(other).yield(sentinel).then( function(value) { assert.same(value, sentinel); } ); }, 'should fulfill with the value of a fulfilled promise': function() { return when.resolve(other).yield(when.resolve(sentinel)).then( function(value) { assert.same(value, sentinel); } ); }, 'should reject with the reason of a rejected promise': function() { return when.resolve(other).yield(when.reject(sentinel)).then( fail, function(reason) { assert.same(reason, sentinel); } ); } }, 'tap': { 'should return a promise': function() { assert.isFunction(when.defer().promise.tap().then); }, 'should fulfill with the original value': function() { return when.resolve(sentinel).tap(function() { return other; }).then(function(value) { assert.same(value, sentinel); }); }, 'should reject with thrown exception if tap function throws': function() { return when.resolve(other).tap(function() { throw sentinel; }).then(fail, function(value) { assert.same(value, sentinel); }); }, 'should reject with rejection reason if tap function rejects': function() { return when.resolve(other).tap(function() { return when.reject(sentinel); }).then(fail, function(value) { assert.same(value, sentinel); }); } }, 'spread': { 'should return a promise': function() { assert.isFunction(when.defer().promise.spread().then); }, 'should apply onFulfilled with array as argument list': function() { var expected = [1, 2, 3]; return when.resolve(expected).spread(function() { assert.equals(slice.call(arguments), expected); }); }, 'should preserve thisArg': function() { return when.resolve([]).withThis(sentinel).spread(function() { assert.equals(this, sentinel); }); }, 'should resolve array contents': function() { var expected = [when.resolve(1), 2, when.resolve(3)]; return when.resolve(expected).spread(function() { assert.equals(slice.call(arguments), [1, 2, 3]); }); }, 'should reject if any item in array rejects': function() { var expected = [when.resolve(1), 2, when.reject(3)]; return when.resolve(expected) .spread(fail) .then(fail, function() { assert(true); }); }, 'when input is a promise': { 'should apply onFulfilled with array as argument list': function() { var expected = [1, 2, 3]; return when.resolve(when.resolve(expected)).spread(function() { assert.equals(slice.call(arguments), expected); }); }, 'should resolve array contents': function() { var expected = [when.resolve(1), 2, when.resolve(3)]; return when.resolve(when.resolve(expected)).spread(function() { assert.equals(slice.call(arguments), [1, 2, 3]); }); }, 'should reject if input is a rejected promise': function() { var expected = when.reject([1, 2, 3]); return when.resolve(expected) .spread(fail) .then(fail, function() { assert(true); }); } } }, 'inspect': { 'when inspecting promises': { 'should return pending state for pending promise': function() { var promise = when.promise(function() {}); assertPending(promise.inspect()); }, 'should return fulfilled state for fulfilled promise': function() { var promise = when.resolve(sentinel); return promise.then(function() { assertFulfilled(promise.inspect(), sentinel); }); }, 'should return rejected state for rejected promise': function() { var promise = when.reject(sentinel); return promise.then(fail, function() { assertRejected(promise.inspect(), sentinel); }); } }, 'when inspecting thenables': { 'should return pending state for pending thenable': function() { var p = when({ then: function() {} }); assertPending(p.inspect()); }, 'should return fulfilled state for fulfilled thenable': function() { var p = when({ then: function(fulfill) { fulfill(sentinel); } }); return p.then(function() { assertFulfilled(p.inspect(), sentinel); }); }, 'should return rejected state for rejected thenable': function() { var p = when({ then: function(_, rejected) { rejected(sentinel); } }); return p.then(fail, function() { assertRejected(p.inspect(), sentinel); }); } } } }); node-when-3.7.8+ds/test/promises-aplus-adapter.js000066400000000000000000000005021314733175200217400ustar00rootroot00000000000000(function() { 'use strict'; if(typeof exports === 'object') { var when = require('../when'); // Silence potentially unhandled rejections when.Promise.onPotentiallyUnhandledRejection = function() {}; exports.resolved = when.resolve; exports.rejected = when.reject; exports.deferred = when.defer; } })(); node-when-3.7.8+ds/test/race-test.js000066400000000000000000000043671314733175200172430ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var fail = buster.referee.fail; var CorePromise = require('../lib/Promise'); var sentinel = { value: 'sentinel' }; var fulfilled = CorePromise.resolve(sentinel); var never = CorePromise.never(); function delayReject(ms) { /*global setTimeout*/ return new CorePromise(function(resolve, reject) { setTimeout(function() { reject(sentinel); }, ms); }); } buster.testCase('CorePromise.race', { 'should return empty race for length 0': function() { assert.equals(never, CorePromise.race([])); }, 'should reject with TypeError when passed a non-iterable (array in es5)': function() { return CorePromise.race(null).then(fail, function(e) { assert(e instanceof TypeError); }); }, 'should be identity for length 1': { 'when fulfilled with value': function() { return CorePromise.race([sentinel]).then(function(x) { assert.same(x, sentinel); }); }, 'when fulfilled via promise': function() { return CorePromise.race([fulfilled]).then(function(x) { assert.same(x, sentinel); }); }, 'when rejected': function() { var rejected = CorePromise.reject(sentinel); return CorePromise.race([rejected]) .then(void 0, function(x) { assert.same(x, sentinel); }); } }, 'should be commutative': { 'when fulfilled': function() { return CorePromise.race([fulfilled, never]).then(function(x) { return CorePromise.race([never, fulfilled]).then(function(y) { assert.same(x, y); }); }); }, 'when rejected': function() { var rejected = CorePromise.reject(sentinel); return CorePromise.race([rejected, never]).then(void 0, function(x) { return CorePromise.race([never, rejected]).then(void 0, function(y) { assert.same(x, y); }); }); } }, 'should fulfill when winner fulfills': function() { return CorePromise.race([delayReject(1), delayReject(1), fulfilled]) .then(function(x) { assert.same(x, sentinel); }, fail); }, 'should reject when winner rejects': function() { var rejected = CorePromise.reject(sentinel); return CorePromise.race([fulfilled.delay(1), fulfilled.delay(1), rejected]) .then(fail, function(x) { assert.same(x, sentinel); }); } }); node-when-3.7.8+ds/test/reduce-test.js000066400000000000000000000154031314733175200175710ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var fail = buster.referee.fail; var when = require('../when'); function plus(sum, val) { return sum + val; } function later(val) { return when(val).delay(Math.random()*10); } buster.testCase('when.reduce', { 'reduceRight': { 'should reduce from the right': function() { return when.reduceRight(['a', later('b'), when.resolve('c')], plus).then( function(result) { assert.equals(result, 'cba'); }); }, 'should reduce from the right with initial value': function() { return when.reduceRight(['a', later('b'), when.resolve('c')], plus, 'z').then( function(result) { assert.equals(result, 'zcba'); }); }, 'should reduce values with initial promise': function() { return when.reduceRight([1,2,3], plus, when.resolve(1)).then( function(result) { assert.equals(result, 7); }); }, 'should reduce promised values without initial value': function() { var input = [when.resolve(1), when.resolve(2), when.resolve(3)]; return when.reduceRight(input, plus).then( function(result) { assert.equals(result, 6); }); }, 'should reduce promised values with initial value': function() { var input = [when.resolve(1), when.resolve(2), when.resolve(3)]; return when.reduceRight(input, plus, 1).then( function(result) { assert.equals(result, 7); }); }, 'should reduce promised values with initial promise': function() { var input = [when.resolve(1), when.resolve(2), when.resolve(3)]; return when.reduceRight(input, plus, when.resolve(1)).then( function(result) { assert.equals(result, 7); }); }, 'should reduce empty input with initial value': function() { var input = []; return when.reduceRight(input, plus, 1).then( function(result) { assert.equals(result, 1); }); }, 'should reduce empty input with initial promise': function() { return when.reduceRight([], plus, when.resolve(1)).then( function(result) { assert.equals(result, 1); }); }, 'should reject when input contains rejection': function() { var input = [when.resolve(1), when.reject(2), when.resolve(3)]; return when.reduceRight(input, plus, when.resolve(1)).then( fail, function(result) { assert.equals(result, 2); }); }, 'should reject with TypeError when input is empty and no initial value or promise provided': function() { return when.reduceRight([], plus).then( fail, function(e) { assert(e instanceof TypeError); }); }, 'should allow sparse array input without initial': function() { return when.reduceRight([ , , 1, , 1, 1], plus).then( function (result) { assert.equals(result, 3); }); }, 'should allow sparse array input with initial': function() { return when.reduceRight([ , , 1, , 1, 1], plus, 1).then( function(result) { assert.equals(result, 4); }); }, 'should fulfill with initial when input promise does not fulfill with array': function() { return when.reduceRight(when.resolve(123), plus, 1).then( function(result) { assert.equals(result, 1); }); }, 'should provide correct basis value': function() { function insert(arr, val, i) { arr[i] = val; return arr; } return when.reduceRight([when(1), when(2), when(3)], insert, []).then( function(result) { assert.equals(result, [1,2,3]); }); } }, 'reduce': { 'should reduce values without initial value': function() { return when.reduce([1,2,3], plus).then( function(result) { assert.equals(result, 6); }); }, 'should reduce values with initial value': function() { return when.reduce([1,2,3], plus, 1).then( function(result) { assert.equals(result, 7); }); }, 'should reduce values with initial promise': function() { return when.reduce([1,2,3], plus, when.resolve(1)).then( function(result) { assert.equals(result, 7); }); }, 'should reduce promised values without initial value': function() { var input = [when.resolve(1), when.resolve(2), when.resolve(3)]; return when.reduce(input, plus).then( function(result) { assert.equals(result, 6); }); }, 'should reduce promised values with initial value': function() { var input = [when.resolve(1), when.resolve(2), when.resolve(3)]; return when.reduce(input, plus, 1).then( function(result) { assert.equals(result, 7); }); }, 'should reduce promised values with initial promise': function() { var input = [when.resolve(1), when.resolve(2), when.resolve(3)]; return when.reduce(input, plus, when.resolve(1)).then( function(result) { assert.equals(result, 7); }); }, 'should reduce empty input with initial value': function() { var input = []; return when.reduce(input, plus, 1).then( function(result) { assert.equals(result, 1); }); }, 'should reduce empty input with initial promise': function() { return when.reduce([], plus, when.resolve(1)).then( function(result) { assert.equals(result, 1); }); }, 'should reject when input contains rejection': function() { var input = [when.resolve(1), when.reject(2), when.resolve(3)]; return when.reduce(input, plus, when.resolve(1)).then( fail, function(result) { assert.equals(result, 2); }); }, 'should reject with TypeError when input is empty and no initial value or promise provided': function() { return when.reduce([], plus).then( fail, function(e) { assert(e instanceof TypeError); }); }, 'should allow sparse array input without initial': function() { return when.reduce([ , , 1, , 1, 1], plus).then( function (result) { assert.equals(result, 3); }); }, 'should allow sparse array input with initial': function() { return when.reduce([ , , 1, , 1, 1], plus, 1).then( function(result) { assert.equals(result, 4); }); }, 'should reduce in input order': function() { return when.reduce([later(1), when(2), when(3)], plus, '').then( function(result) { assert.equals(result, '123'); }); }, 'should accept a promise for an array': function() { return when.reduce(when.resolve([1, 2, 3]), plus, '').then( function(result) { assert.equals(result, '123'); }); }, 'should fulfill with initial when input promise does not fulfill with array': function() { return when.reduce(when.resolve(123), plus, 1).then( function(result) { assert.equals(result, 1); }); }, 'should provide correct basis value': function() { function insert(arr, val, i) { arr[i] = val; return arr; } return when.reduce([when(1), when(2), when(3)], insert, []).then( function(result) { assert.equals(result, [1,2,3]); }); } } }); node-when-3.7.8+ds/test/reject-test.js000066400000000000000000000016431314733175200175770ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var fail = buster.referee.fail; var when = require('../when'); buster.testCase('when.reject', { 'should reject an immediate value': function(done) { var expected = 123; when.reject(expected).then( fail, function(value) { assert.equals(value, expected); } ).ensure(done); }, 'should reject a resolved promise': function(done) { var expected, d; expected = 123; d = when.defer(); d.resolve(expected); when.reject(d.promise).then( fail, function(value) { assert.same(value, d.promise); } ).ensure(done); }, 'should reject a rejected promise': function(done) { var expected, d; expected = 123; d = when.defer(); d.reject(expected); when.reject(d.promise).then( fail, function(value) { assert.equals(value, d.promise); } ).ensure(done); } }); node-when-3.7.8+ds/test/resolve-test.js000066400000000000000000000102061314733175200177750ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var fail = buster.referee.fail; var when = require('../when'); var sentinel = { value: 'sentinel' }; var other = { value: 'other' }; function hasGetters() { try { return Object.defineProperty({}, 'a', { get: function() { return 1; } }).a === 1; } catch (ex) {} } buster.testCase('when.resolve', { 'should resolve an immediate value': function(done) { var expected = 123; when.resolve(expected).then( function(value) { assert.equals(value, expected); }, fail ).ensure(done); }, 'should resolve a resolved promise': function(done) { var expected, d; expected = 123; d = when.defer(); d.resolve(expected); when.resolve(d.promise).then( function(value) { assert.equals(value, expected); }, fail ).ensure(done); }, 'should reject a rejected promise': function(done) { var expected, d; expected = 123; d = when.defer(); d.reject(expected); when.resolve(d.promise).then( fail, function(value) { assert.equals(value, expected); } ).ensure(done); }, 'should preserve implicit order': function() { var result = []; var resolveA; var a = new when.Promise(function() { resolveA = arguments[0]; }); var c = a.then(function() { result.push(1); }); var resolveB; var b = new when.Promise(function() { resolveB = arguments[0]; }); // There is a very subtle implicit ordering between // resolving a with b, a's handlers, and b's handlers. // It seems that a reasonable order should be: // b handlers run before a handlers added in the same stack b.then(function() { result.push(2); }); resolveA(b); b.then(function() { result.push(3); }); resolveB(); return c.then(function() { assert.equals(result, [2,3,1]); }); }, 'when assimilating untrusted thenables': { 'should trap exceptions during assimilation': function(done) { when.resolve({ then: function() { throw sentinel; } }).then( fail, function(val) { assert.same(val, sentinel); } ).ensure(done); }, 'should ignore exceptions after fulfillment': function(done) { when.resolve({ then: function(onFulfilled) { onFulfilled(sentinel); throw other; } }).then( function(val) { assert.same(val, sentinel); }, fail ).ensure(done); }, 'should ignore exceptions after rejection': function(done) { when.resolve({ then: function(_, onRejected) { onRejected(sentinel); throw other; } }).then( fail, function(val) { assert.same(val, sentinel); } ).ensure(done); }, 'should assimilate thenable used as fulfillment value': function(done) { when.resolve({ then: function(onFulfilled) { onFulfilled({ then: function(onFulfilled) { onFulfilled(sentinel); } }); throw other; } }).then( function(val) { assert.same(val, sentinel); }, fail ).ensure(done); }, 'should call untrusted then only after stack clears': function(done) { var value, p, spy; // value = intentionally undefined spy = this.spy(); p = when.resolve({ then: function(fulfill) { spy(value); fulfill(); } }).then(function() { assert.calledWith(spy, sentinel); }).ensure(done); value = sentinel; }, 'should assimilate thenables provided as fulfillment arg': function(done) { when.resolve({ then: function(fulfill) { fulfill({ then: function(fulfill) { fulfill(sentinel); } }); } }).then(function(value) { assert.same(value, sentinel); }).ensure(done); }, 'should reject if accessing thenable.then throws': function(done) { var result, thenable; if(hasGetters()) { thenable = {}; Object.defineProperty(thenable, 'then', { get: function() { throw sentinel; } }); result = when.resolve(thenable).then( fail, function(e) { assert.same(e, sentinel); } ).ensure(done); } else { // Non-ES5 env, no need to test pathological getters/proxies assert(true); done(); } } } }); node-when-3.7.8+ds/test/sauce.js000066400000000000000000000152271314733175200164510ustar00rootroot00000000000000#!/usr/bin/env node /* * Copyright 2013 the original author or authors * @license MIT, see LICENSE.txt for details * * @author Scott Andrews * @author Brian Cavalier * Original code from cujojs/test-support by Scott, heavily * modified by Brian for use in cujojs/when */ var fs = require('fs'); var path = require('path'); var childProcess = require('child_process'); var json5 = require('json5'); var optimist = require('optimist'); var webdriver = require('wd'); var sauceConnect = require('sauce-connect-launcher'); var rest = require('rest'); var interceptor = require('rest/interceptor'); var basicAuthInterceptor = require('rest/interceptor/basicAuth'); var mimeInterceptor = require('rest/interceptor/mime'); var pathPrefixInterceptor = require('rest/interceptor/pathPrefix'); var when = require('../when'); var opts = optimist .boolean('m') .alias('m', 'manual') .describe('m', 'Opens a tunnel for manual test drives') .options('u', { alias: 'user', default: process.env.SAUCE_USERNAME || process.env.SELENIUM_USERNAME, demand: true, describe: 'Sauce Labs username, can be defined as an env var SAUCE_USERNAME' }) .options('p', { alias : 'pass', default : process.env.SAUCE_ACCESS_KEY || process.env.SELENIUM_PASSWORD, demand: true, describe: 'Sauce Labs access key, can be defined as an env var SAUCE_ACCESS_KEY' }) .options('remote-host', { default: process.env.SAUCE_HOST || process.env.SELENIUM_HOST || 'ondemand.saucelabs.com', describe: 'Hostname of Sauce Labs service' }) .options('remote-port', { default: process.env.SAUCE_PORT || process.env.SELENIUM_PORT || 80, describe: 'Port of Sauce Labs service' }) .options('port', { default: process.env.PORT || 8080, describe: 'Local port to run tunneled service, must be a tunnelable port' }) .options('b', { alias: 'browsers', default: path.join(__dirname, 'browsers.json'), describe: 'path to browsers.json' }) .options('t', { alias: 'timeout', default: process.env.SAUCE_JOB_TIMEOUT || 300, // 5 mins describe: 'Timeout per browser run, in seconds' }) .argv; opts.b = opts.browsers = json5.parse( fs.readFileSync(path.resolve(opts.browsers)).toString() ); drive(opts); /** * Distributed in browser testing with Sauce Labs */ function drive(opts) { /*jshint maxcomplexity:6*/ 'use strict'; var suiteFailed = false; var username = opts.user; var accessKey = opts.pass; var travisJobNumber = process.env.TRAVIS_JOB_NUMBER || ''; var travisCommit = process.env.TRAVIS_COMMIT || ''; var tunnelIdentifier = travisJobNumber || Math.floor(Math.random() * 10000); if (travisJobNumber && !/\.1$/.test(travisJobNumber)) { // give up this is not the primary job for the build return; } var projectName; try { projectName = require('../package.json').name; } catch (e) { projectName = 'unknown'; } var sauceRestClient = rest.wrap(mimeInterceptor, { mime: 'application/json' }) .wrap(basicAuthInterceptor, { username: username, password: accessKey }) .wrap(pathPrefixInterceptor, { prefix: 'http://saucelabs.com/rest/v1' }); var passedStatusInterceptor = interceptor({ request: function (passed, config) { return { method: 'put', path: '/{username}/jobs/{jobId}', params: { username: config.username, jobId: config.jobId }, entity: { passed: passed } }; } }); // must use a port that sauce connect will tunnel var buster = launchBuster(); console.log('Opening tunnel to Sauce Labs'); sauceConnect({ username: username, accessKey: accessKey, tunnelIdentifier: tunnelIdentifier, 'no_progress': true }, function (err, tunnel) { if (err) { // some tunnel error occur as a normal result of testing console.error(err.stack || err); return; } console.log('Sauce Labs tunnel is ready for traffic'); if (opts.manual) { // let the user run test manually, hold the tunnel open until this process is killed return; } runAutomatedTests(tunnel); }); function launchBuster() { var buster = childProcess.spawn('npm', ['run', 'browser-test'], { stdio: 'pipe' }); buster.stderr.on('data', function(data) { console.error(String(data)); }); buster.on('error', function(e) { console.error(e.stack || e); }); return buster; } function runAutomatedTests (tunnel) { var browser = webdriver.promiseChainRemote( opts['remote-host'], opts['remote-port'], username, accessKey); browser.on('status', function (info) { console.log('\x1b[36m%s\x1b[0m', info); }); browser.on('command', function (meth, path) { console.log(' > \x1b[33m%s\x1b[0m: %s', meth, path); }); var outcome = opts.browsers.reduce(function (result, env) { return when(result, function () { return testWith(browser, env); }); }, void 0); outcome.finally(function () { console.log('Stopping buster'); buster.kill(); console.log('Closing tunnel to Sauce Labs'); tunnel.close(); process.exit(suiteFailed ? 1 : 0); }).done(); } function initEnvironment (environment) { environment.name = projectName + ' - ' + (travisJobNumber ? travisJobNumber + ' - ' : '') + environment.browserName + ' ' + (environment.version || 'latest') + ' on ' + (environment.platform || 'any platform'); environment.build = travisJobNumber ? travisJobNumber + ' - ' + travisCommit : 'manual'; environment['tunnel-identifier'] = tunnelIdentifier; environment['max-duration'] = opts.timeout; // most info is below the fold, so images are not helpful, html source is environment['record-video'] = false; environment['record-screenshots'] = false; environment['capture-html'] = true; return environment; } function testWith(browser, environment) { var updateEnvironmentPassedStatus; return browser.init(initEnvironment(environment)) .then(function(sessionID) { console.log('Testing ' + environment.name); updateEnvironmentPassedStatus = sauceRestClient.wrap(passedStatusInterceptor, { username: username, jobId: sessionID }); return sessionID; }) .setImplicitWaitTimeout(3e4) .get('http://127.0.0.1:' + opts.port + '/') .elementByCssSelector('.stats h2') .text() .then(function(text) { environment.passed = /ok/i.test(text); }) .catch(function(e) { console.log(e.stack); environment.passed = false; environment.error = e; suiteFailed = true; }) .quit(function() { if (!environment.passed) { suiteFailed = true; } console.log((environment.passed ? 'PASS' : 'FAIL') + ' ' + environment.name); if (suiteFailed && updateEnvironmentPassedStatus) { return updateEnvironmentPassedStatus(false).thenReject(environment.error); } else { return updateEnvironmentPassedStatus(environment.passed); } }); } } node-when-3.7.8+ds/test/sequence-test.js000066400000000000000000000030611314733175200201270ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var when = require('../when'); var sequence = require('../sequence'); var sentinel = { value: 'sentinel' }; function createTask(y) { return function() { return y; }; } function expectArgs(expected) { return function() { var args = Array.prototype.slice.call(arguments); assert.equals(args, expected); }; } buster.testCase('when/sequence', { 'should execute tasks in order': function() { return sequence([createTask(1), createTask(2), createTask(3)]).then( function(result) { assert.equals(result, [1, 2, 3]); } ); }, 'should resolve to empty array when no tasks supplied': function() { return sequence([], 1, 2, 3).then( function(result) { assert.equals(result, []); } ); }, 'should pass args to all tasks': function(done) { var expected, tasks; expected = [1, 2, 3]; tasks = [expectArgs(expected), expectArgs(expected), expectArgs(expected)]; return sequence.apply(null, [tasks].concat(expected)).ensure(done); }, 'should accept promises for args': function(done) { var expected, tasks; expected = [1, 2, 3]; tasks = [expectArgs(expected), expectArgs(expected), expectArgs(expected)]; expected = [when(1), when(2), when(3)]; return sequence.apply(null, [tasks].concat(expected)).ensure(done); }, 'should reject if task throws': function() { return sequence([function () { return 1; }, function () { throw sentinel; }])['catch'](function (e) { assert.same(e, sentinel); }); } }); node-when-3.7.8+ds/test/settle-test.js000066400000000000000000000041651314733175200176250ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var refute = buster.refute; var fail = buster.referee.fail; var when = require('../when'); var sentinel = {}; function assertFulfilled(s, value) { assert.equals(s.state, 'fulfilled'); assert.same(s.value, value); } function assertRejected(s, reason) { assert.equals(s.state, 'rejected'); assert.same(s.reason, reason); } buster.testCase('when.settle', { 'should settle empty array': function() { return when.settle([]).then(function(settled) { assert.equals(settled.length, 0); }); }, 'should reject if promise for input array rejects': function() { return when.settle(when.reject(sentinel)).then( fail, function(reason) { assert.same(reason, sentinel); } ); }, 'should settle values': function() { var array = [0, 1, sentinel]; return when.settle(array).then(function(settled) { assertFulfilled(settled[0], 0); assertFulfilled(settled[1], 1); assertFulfilled(settled[2], sentinel); }); }, 'should settle promises': function() { var array = [0, when.resolve(sentinel), when.reject(sentinel)]; return when.settle(array).then(function(settled) { assertFulfilled(settled[0], 0); assertFulfilled(settled[1], sentinel); assertRejected(settled[2], sentinel); }); }, 'returned promise should fulfill once all inputs settle': function() { /*global setTimeout*/ var array, p1, p2, resolve, reject; p1 = when.promise(function(r) { resolve = r; }); p2 = when.promise(function(_, r) { reject = r; }); array = [0, p1, p2]; setTimeout(function() { resolve(sentinel); }, 0); setTimeout(function() { reject(sentinel); }, 0); return when.settle(array).then(function(settled) { assertFulfilled(settled[0], 0); assertFulfilled(settled[1], sentinel); assertRejected(settled[2], sentinel); }); }, 'should not report unhandled rejection for rejected inputs': function(done) { var P = when.Promise; var spy = P.onPotentiallyUnhandledRejection = this.spy(); when.settle([when.reject()]); setTimeout(function() { refute.called(spy); done(); }, 10); } }); node-when-3.7.8+ds/test/some-test.js000066400000000000000000000047241314733175200172710ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var fail = buster.referee.fail; var when = require('../when'); function contains(array, value) { for(var i = array.length-1; i >= 0; i--) { if(array[i] === value) { return true; } } return false; } function isSubset(subset, superset) { var i, subsetLen; subsetLen = subset.length; if (subsetLen > superset.length) { return false; } for(i = 0; i number of inputs': { 'for base case of zero inputs': function() { return when.some([], 1)['catch']( function (e) { assert(e instanceof RangeError); }); }, 'for m inputs requesting n > m winners': function() { var input = [1,,2]; return when.some(input, input.length+1)['catch']( function (e) { assert(e instanceof RangeError); }); } }, 'when input promise does not resolve to array': function() { return when.some(when.resolve(1), 1)['catch']( function(e) { assert(e instanceof RangeError); }); } }, 'should reject with all rejected input values if resolving howMany becomes impossible': function() { var input = [when.resolve(1), when.reject(2), when.reject(3)]; return when.some(input, 2).then( fail, function(failed) { assert.equals(failed, [2, 3]); }); }, 'should resolve values array': function() { var input = [1, 2, 3]; return when.some(input, 2).then( function(results) { assert(isSubset(results, input)); }); }, 'should resolve promises array': function() { var input = [when.resolve(1), when.resolve(2), when.resolve(3)]; return when.some(input, 2).then( function(results) { assert(isSubset(results, [1, 2, 3])); }); }, 'should resolve sparse array input': function() { var input = [, 1, , 2, 3 ]; return when.some(input, 2).then( function(results) { assert(isSubset(results, input)); }); }, 'should accept a promise for an array': function() { var expected, input; expected = [1, 2, 3]; input = when.resolve(expected); return when.some(input, 2).then( function(results) { assert.equals(results.length, 2); }); }, 'should resolve to empty array when n is zero': function() { return when.some([1,2,3], 0).then(function(result) { assert.equals(result, []); }); } }); node-when-3.7.8+ds/test/timeout-test.js000066400000000000000000000046241314733175200200130ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var fail = buster.referee.fail; var CorePromise = require('../lib/Promise'); var TimeoutError = require('../lib/TimeoutError'); var timeout = require('../timeout'); var sentinel = {}; function FakePromise() { this.then = function() { return this; }; } buster.testCase('when/timeout', { 'should reject with TimeoutError': function(done) { timeout(10, new FakePromise()).then( fail, function(e) { assert(e instanceof TimeoutError); } ).ensure(done); }, 'should not timeout when rejected before timeout': function(done) { timeout(10, CorePromise.reject(sentinel)).then( fail, function(val) { assert.same(val, sentinel); } ).ensure(done); }, 'should not timeout when resolved before timeout': function(done) { timeout(10, CorePromise.resolve(sentinel)).then( function(val) { assert.same(val, sentinel); }, fail ).ensure(done); }, 'promise.timeout': { 'should reject with TimeoutError': function() { return CorePromise.never().timeout(0).then( fail, function(e) { assert(e instanceof TimeoutError); } ); }, 'should pattern match': function() { return CorePromise.never().timeout(0).catch(TimeoutError, function(e) { assert(e instanceof TimeoutError); }); }, 'should reject after timeout with the provided reason': function() { return CorePromise.never().timeout(0, sentinel).then( fail, function(e) { assert.same(e, sentinel); } ); }, 'should reject after timeout with default reason when undefined': function() { return CorePromise.never().timeout(0, void 0).then( fail, function(e) { assert(e instanceof TimeoutError); } ); }, 'should not timeout when rejected before timeout': function() { return CorePromise.reject(sentinel).timeout(0).then( fail, function(val) { assert.same(val, sentinel); } ); }, 'should not timeout when resolved before timeout': function() { return CorePromise.resolve(sentinel).timeout(0).then( function(val) { assert.same(val, sentinel); } ); }, 'should propagate progress': function(done) { return new CorePromise(function(resolve, _, notify) { notify(sentinel); }) .timeout(10) .then(void 0, void 0, function(x) { assert.same(x, sentinel); done(); }); } } }); node-when-3.7.8+ds/test/unfold/000077500000000000000000000000001314733175200162735ustar00rootroot00000000000000node-when-3.7.8+ds/test/unfold/list-test.js000066400000000000000000000014711314733175200205640ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var list = require('../../unfold/list'); var sentinel = {}; function noop() {} buster.testCase('when/unfold/list', { 'should produce an empty list when proceed returns truthy immediately': function(done) { function condition() { return true; } list(noop, condition, sentinel).then( function(value) { assert.equals(value, []); } ).ensure(done); }, 'should produce a list of N elements': function(done) { var len = 3; function condition(i) { return i == len; } function generate(x) { return [x, x+1]; } list(generate, condition, 0).then( function(result) { assert.equals(result.length, len); assert.equals(result, [0, 1, 2]); } ).ensure(done); } }); node-when-3.7.8+ds/test/unhandledRejection-test.js000066400000000000000000000010331314733175200221210ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var unhandledRejection = require('../lib/decorators/unhandledRejection'); buster.testCase('unhandledRejection', { 'should not fail if JSON.stringify throws': function() { var fixture = unhandledRejection({}); var circle = { self: void 0 }; circle.self = circle; buster.refute.exception(function() { fixture.onPotentiallyUnhandledRejection({ id: 'JSON.stringify circular ref test', handled: false, value: circle }); }); } }); node-when-3.7.8+ds/test/when-test.js000066400000000000000000000075551314733175200172740ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var refute = buster.refute; var fail = buster.referee.fail; var when = require('../when'); function identity(val) { return val; } function constant(val) { return function() { return val; }; } var sentinel = {}; var other = {}; var fakePromise = new FakePromise(); // Untrusted, non-Promises/A-compliant promise function FakePromise(val) { this.then = function (cb) { if (cb) { cb(val); } return this; }; } buster.testCase('when', { 'should return a promise for a value': function() { var result = when(1); assert(typeof result.then == 'function'); }, 'should return a promise for a promise': function() { var result = when(fakePromise); assert(typeof result.then == 'function'); }, 'should not return the input promise': function() { var result = when(fakePromise, identity); assert(typeof result.then == 'function'); refute.same(result, fakePromise); }, 'should return a promise that forwards for a value': function() { var result = when(1, constant(2)); assert(typeof result.then == 'function'); return result.then( function(val) { assert.equals(val, 2); }, fail ); }, 'should invoke fulfilled handler asynchronously for value': function() { var val = other; try { return when({}, function() { assert.same(val, sentinel); }); } finally { val = sentinel; } }, 'should invoke fulfilled handler asynchronously for fake promise': function() { var val = other; try { return when(fakePromise, function() { assert.same(val, sentinel); }); } finally { val = sentinel; } }, 'should invoke fulfilled handler asynchronously for resolved promise': function() { var val = other; try { return when(when.resolve(), function() { assert.same(val, sentinel); }); } finally { val = sentinel; } }, 'should invoke rejected handler asynchronously for rejected promise': function() { var val = other; try { return when(when.reject(), fail, function() { assert.same(val, sentinel); } ); } finally { val = sentinel; } }, 'should support deep nesting in promise chains': function() { var d, result; d = when.defer(); d.resolve(false); result = when(when(d.promise.then(function(val) { var d = when.defer(); d.resolve(val); return when(d.promise.then(identity), identity).then( function(val) { return !val; } ); }))); return result.then( function(val) { assert(val); }, fail ); }, 'should return a resolved promise for a resolved input promise': function() { return when(when.resolve(true)).then( function(val) { assert(val); }, fail ); }, 'should assimilate untrusted promises':function () { var untrusted, result; // unstrusted promise should never be returned by when() untrusted = new FakePromise(); result = when(untrusted); refute.equals(result, untrusted); refute(result instanceof FakePromise); }, 'should assimilate intermediate promises returned by callbacks':function () { var result; // untrusted promise returned by an intermediate // handler should be assimilated result = when(1, function (val) { return new FakePromise(val + 1); } ).then( function (val) { assert.equals(val, 2); }, fail ); refute(result instanceof FakePromise); return result; }, 'should assimilate intermediate promises and forward results':function () { var untrusted, result; untrusted = new FakePromise(1); result = when(untrusted, function (val) { return new FakePromise(val + 1); }); refute.equals(result, untrusted); refute(result instanceof FakePromise); return when(result, function (val) { assert.equals(val, 2); return new FakePromise(val + 1); } ).then( function (val) { assert.equals(val, 3); }, fail ); } }); node-when-3.7.8+ds/test/with-test.js000066400000000000000000000056501314733175200173000ustar00rootroot00000000000000var buster = typeof window !== 'undefined' ? window.buster : require('buster'); var assert = buster.assert; var CorePromise = require('../lib/Promise'); var sentinel = { value: 'sentinel' }; buster.testCase('promise.with', { 'should set thisArg': function() { return CorePromise.resolve()['with'](sentinel).then(function() { assert.same(this, sentinel); }); }, 'should set thisArg when rejected': function() { return CorePromise.reject()['with'](sentinel).then(void 0, function() { assert.same(this, sentinel); }); }, 'should set thisArg for derived promises': function() { return CorePromise.resolve()['with'](sentinel).then(function(x) { return x; }).then(function() { assert.same(this, sentinel); }); }, 'should set thisArg for derived promises when rejected': function() { return CorePromise.resolve()['with'](sentinel).then(function(x) { throw x; }).then(void 0, function() { assert.same(this, sentinel); }); }, 'when called with no args': { 'should set default thisArg': function() { var expected; return CorePromise.resolve().then(function() { expected = this; }) ['with'](sentinel).then(function() { assert.same(this, sentinel); }) ['with']().then(function() { assert.same(this, expected); }); }, 'should set default thisArg when rejected': function() { var expected; return CorePromise.resolve().then(function() { expected = this; }) ['with'](sentinel).then(function() { assert.same(this, sentinel); throw sentinel; }) ['with']().then(void 0, function() { assert.same(this, expected); }); }, 'should set default thisArg for derived promises': function() { var expected; return CorePromise.resolve().then(function() { expected = this; }) ['with'](sentinel).then(function() { assert.same(this, sentinel); }) ['with']().then(function(x) { return x; }) .then(function() { assert.same(this, expected); }); }, 'should set default thisArg for derived promises when rejected': function() { var expected; return CorePromise.resolve().then(function() { expected = this; }) ['with'](sentinel).then(function() { assert.same(this, sentinel); }) ['with']().then(function(x) { throw x; }) .then(void 0, function() { assert.same(this, expected); }); } }, 'when called with non-object': { 'should mimic Function.prototype.call behavior': function() { var thisArg = 123; var expected = (function() { return this; }).call(thisArg); return CorePromise.resolve()['with'](thisArg).then(function() { assert.equals(this, expected); }); }, 'should mimic Function.prototype.call behavior when rejected': function() { var thisArg = 123; var expected = (function() { return this; }).call(thisArg); return CorePromise.reject()['with'](thisArg).then(void 0, function() { assert.equals(this, expected); }); } } }); node-when-3.7.8+ds/timeout.js000066400000000000000000000011771314733175200160570ustar00rootroot00000000000000/** @license MIT License (c) copyright 2011-2013 original author or authors */ /** * timeout.js * * Helper that returns a promise that rejects after a specified timeout, * if not explicitly resolved or rejected before that. * * @author Brian Cavalier * @author John Hann */ (function(define) { define(function(require) { var when = require('./when'); /** * @deprecated Use when(trigger).timeout(ms) */ return function timeout(msec, trigger) { return when(trigger).timeout(msec); }; }); })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); node-when-3.7.8+ds/unfold.js000066400000000000000000000005611314733175200156540ustar00rootroot00000000000000/** @license MIT License (c) copyright B Cavalier & J Hann */ /** * unfold * @author: brian@hovercraftstudios.com */ (function(define) { define(function(require) { /** * @deprecated Use when.unfold */ return require('./when').unfold; }); })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); } ); node-when-3.7.8+ds/unfold/000077500000000000000000000000001314733175200153145ustar00rootroot00000000000000node-when-3.7.8+ds/unfold/list.js000066400000000000000000000017331314733175200166310ustar00rootroot00000000000000/** @license MIT License (c) copyright B Cavalier & J Hann */ (function(define) { define(function(require) { var unfold = require('../when').unfold; /** * @deprecated * Given a seed and generator, produces an Array. Effectively the * dual (opposite) of when.reduce() * @param {function} generator function that generates a value (or promise * for a value) to be placed in the resulting array * @param {function} condition given a seed, must return truthy if the unfold * should continue, or falsey if it should terminate * @param {*|Promise} seed any value or promise * @return {Promise} resulting array */ return function list(generator, condition, seed) { var result = []; return unfold(generator, condition, append, seed)['yield'](result); function append(value, newSeed) { result.push(value); return newSeed; } }; }); })(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }); node-when-3.7.8+ds/when.js000066400000000000000000000177151314733175200153370ustar00rootroot00000000000000/** @license MIT License (c) copyright 2010-2014 original author or authors */ /** * Promises/A+ and when() implementation * when is part of the cujoJS family of libraries (http://cujojs.com/) * @author Brian Cavalier * @author John Hann */ (function(define) { 'use strict'; define(function (require) { var timed = require('./lib/decorators/timed'); var array = require('./lib/decorators/array'); var flow = require('./lib/decorators/flow'); var fold = require('./lib/decorators/fold'); var inspect = require('./lib/decorators/inspect'); var generate = require('./lib/decorators/iterate'); var progress = require('./lib/decorators/progress'); var withThis = require('./lib/decorators/with'); var unhandledRejection = require('./lib/decorators/unhandledRejection'); var TimeoutError = require('./lib/TimeoutError'); var Promise = [array, flow, fold, generate, progress, inspect, withThis, timed, unhandledRejection] .reduce(function(Promise, feature) { return feature(Promise); }, require('./lib/Promise')); var apply = require('./lib/apply')(Promise); // Public API when.promise = promise; // Create a pending promise when.resolve = Promise.resolve; // Create a resolved promise when.reject = Promise.reject; // Create a rejected promise when.lift = lift; // lift a function to return promises when['try'] = attempt; // call a function and return a promise when.attempt = attempt; // alias for when.try when.iterate = Promise.iterate; // DEPRECATED (use cujojs/most streams) Generate a stream of promises when.unfold = Promise.unfold; // DEPRECATED (use cujojs/most streams) Generate a stream of promises when.join = join; // Join 2 or more promises when.all = all; // Resolve a list of promises when.settle = settle; // Settle a list of promises when.any = lift(Promise.any); // One-winner race when.some = lift(Promise.some); // Multi-winner race when.race = lift(Promise.race); // First-to-settle race when.map = map; // Array.map() for promises when.filter = filter; // Array.filter() for promises when.reduce = lift(Promise.reduce); // Array.reduce() for promises when.reduceRight = lift(Promise.reduceRight); // Array.reduceRight() for promises when.isPromiseLike = isPromiseLike; // Is something promise-like, aka thenable when.Promise = Promise; // Promise constructor when.defer = defer; // Create a {promise, resolve, reject} tuple // Error types when.TimeoutError = TimeoutError; /** * Get a trusted promise for x, or by transforming x with onFulfilled * * @param {*} x * @param {function?} onFulfilled callback to be called when x is * successfully fulfilled. If promiseOrValue is an immediate value, callback * will be invoked immediately. * @param {function?} onRejected callback to be called when x is * rejected. * @param {function?} onProgress callback to be called when progress updates * are issued for x. @deprecated * @returns {Promise} a new promise that will fulfill with the return * value of callback or errback or the completion value of promiseOrValue if * callback and/or errback is not supplied. */ function when(x, onFulfilled, onRejected, onProgress) { var p = Promise.resolve(x); if (arguments.length < 2) { return p; } return p.then(onFulfilled, onRejected, onProgress); } /** * Creates a new promise whose fate is determined by resolver. * @param {function} resolver function(resolve, reject, notify) * @returns {Promise} promise whose fate is determine by resolver */ function promise(resolver) { return new Promise(resolver); } /** * Lift the supplied function, creating a version of f that returns * promises, and accepts promises as arguments. * @param {function} f * @returns {Function} version of f that returns promises */ function lift(f) { return function() { for(var i=0, l=arguments.length, a=new Array(l); i