Comparing version 3.0.1 to 3.1.0
148
index.js
@@ -1,105 +0,69 @@ | ||
var nextTick | ||
'use strict' | ||
if (typeof setImmediate === 'function') { // IE >= 10 & node.js >= 0.10 | ||
nextTick = function(fn){ setImmediate(fn) } | ||
} else if (typeof process !== 'undefined' && process && typeof process.nextTick === 'function') { // node.js before 0.10 | ||
nextTick = function(fn){ process.nextTick(fn) } | ||
} else { | ||
nextTick = function(fn){ setTimeout(fn, 0) } | ||
} | ||
//This file contains then/promise specific extensions to the core promise API | ||
var Promise = require('./core.js') | ||
var nextTick = require('./lib/next-tick') | ||
module.exports = Promise | ||
function Promise(fn) { | ||
if (!(this instanceof Promise)) return new Promise(fn) | ||
if (typeof fn !== 'function') throw new TypeError('not a function') | ||
var state = null | ||
var delegating = false | ||
var value = null | ||
var deferreds = [] | ||
var self = this | ||
this.then = function(onFulfilled, onRejected) { | ||
return new Promise(function(resolve, reject) { | ||
handle(new Handler(onFulfilled, onRejected, resolve, reject)) | ||
}) | ||
} | ||
/* Static Functions */ | ||
function handle(deferred) { | ||
if (state === null) { | ||
deferreds.push(deferred) | ||
return | ||
} | ||
nextTick(function() { | ||
var cb = state ? deferred.onFulfilled : deferred.onRejected | ||
if (cb === null) { | ||
(state ? deferred.resolve : deferred.reject)(value) | ||
return | ||
} | ||
var ret | ||
try { | ||
ret = cb(value) | ||
} | ||
catch (e) { | ||
deferred.reject(e) | ||
return | ||
} | ||
deferred.resolve(ret) | ||
Promise.from = function (value) { | ||
if (value instanceof Promise) return value | ||
return new Promise(function (resolve) { resolve(value) }) | ||
} | ||
Promise.denodeify = function (fn) { | ||
return function () { | ||
var self = this | ||
var args = Array.prototype.slice.call(arguments) | ||
return new Promise(function (resolve, reject) { | ||
args.push(function (err, res) { | ||
if (err) reject(err) | ||
else resolve(res) | ||
}) | ||
fn.apply(self, args) | ||
}) | ||
} | ||
function resolve(newValue) { | ||
if (delegating) | ||
return | ||
resolve_(newValue) | ||
} | ||
function resolve_(newValue) { | ||
if (state !== null) | ||
return | ||
try { //Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure | ||
if (newValue === self) throw new TypeError('A promise cannot be resolved with itself.') | ||
if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) { | ||
var then = newValue.then | ||
if (typeof then === 'function') { | ||
delegating = true | ||
then.call(newValue, resolve_, reject_) | ||
return | ||
} | ||
} | ||
Promise.nodeify = function (fn) { | ||
return function () { | ||
var args = Array.prototype.slice.call(arguments) | ||
var callback = typeof args[args.length - 1] === 'function' ? args.pop() : null | ||
try { | ||
return fn.apply(this, arguments).nodeify(callback) | ||
} catch (ex) { | ||
if (callback == null) { | ||
return new Promise(function (resolve, reject) { reject(ex) }) | ||
} else { | ||
nextTick(function () { | ||
callback(ex) | ||
}) | ||
} | ||
state = true | ||
value = newValue | ||
finale() | ||
} catch (e) { reject_(e) } | ||
} | ||
} | ||
} | ||
function reject(newValue) { | ||
if (delegating) | ||
return | ||
reject_(newValue) | ||
} | ||
/* Prototype Methods */ | ||
function reject_(newValue) { | ||
if (state !== null) | ||
return | ||
state = false | ||
value = newValue | ||
finale() | ||
} | ||
function finale() { | ||
for (var i = 0, len = deferreds.length; i < len; i++) | ||
handle(deferreds[i]) | ||
deferreds = null | ||
} | ||
try { fn(resolve, reject) } | ||
catch(e) { reject(e) } | ||
Promise.prototype.done = function (onFulfilled, onRejected) { | ||
var self = arguments.length ? this.then.apply(this, arguments) : this | ||
self.then(null, function (err) { | ||
nextTick(function () { | ||
throw err | ||
}) | ||
}) | ||
} | ||
Promise.prototype.nodeify = function (callback) { | ||
if (callback == null) return this | ||
function Handler(onFulfilled, onRejected, resolve, reject){ | ||
this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null | ||
this.onRejected = typeof onRejected === 'function' ? onRejected : null | ||
this.resolve = resolve | ||
this.reject = reject | ||
} | ||
this.then(function (value) { | ||
nextTick(function () { | ||
callback(null, value) | ||
}) | ||
}, function (err) { | ||
nextTick(function () { | ||
callback(err) | ||
}) | ||
}) | ||
} |
{ | ||
"name": "promise", | ||
"version": "3.0.1", | ||
"version": "3.1.0", | ||
"description": "Bare bones Promises/A+ implementation", | ||
@@ -8,3 +8,4 @@ "main": "index.js", | ||
"test": "mocha -R spec --timeout 200 --slow 99999", | ||
"test-resolve": "mocha test/resolver-tests.js -R spec --timeout 200 --slow 999999" | ||
"test-resolve": "mocha test/resolver-tests.js -R spec --timeout 200 --slow 999999", | ||
"test-extensions": "mocha test/extensions-tests.js -R spec --timeout 200 --slow 999999" | ||
}, | ||
@@ -19,5 +20,5 @@ "repository": { | ||
"promises-aplus-tests": "*", | ||
"better-assert": "~1.0", | ||
"mocha": "~1.9" | ||
"better-assert": "*", | ||
"mocha": "*" | ||
} | ||
} |
112
Readme.md
@@ -1,2 +0,1 @@ | ||
[![Build Status](https://travis-ci.org/then/promise.png)](https://travis-ci.org/then/promise) | ||
<a href="http://promises-aplus.github.com/promises-spec"><img src="http://promises-aplus.github.com/promises-spec/assets/logo-small.png" align="right" /></a> | ||
@@ -9,2 +8,6 @@ # promise | ||
[![Build Status](https://travis-ci.org/then/promise.png)](https://travis-ci.org/then/promise) | ||
[![Dependency Status](https://gemnasium.com/then/promise.png)](https://gemnasium.com/then/promise) | ||
[![NPM version](https://badge.fury.io/js/promise.png)](http://badge.fury.io/js/promise) | ||
## Installation | ||
@@ -16,10 +19,6 @@ | ||
Client: | ||
## Usage | ||
$ component install then/promise | ||
The example below shows how you can load the promise library (in a way that works on both client and server). It then demonstrates creating a promise from scratch. You simply call `new Promise(fn)`. There is a complete specification for what is returned by this method in [Promises/A+](http://promises-aplus.github.com/promises-spec/). | ||
## API | ||
In the example below shows how you can load the promise library (in a way that works on both client and server). It then demonstrates creating a promise from scratch. You simply call `new Promise(fn)`. There is a complete specification for what is returned by this method in [Promises/A+](http://promises-aplus.github.com/promises-spec/). | ||
```javascript | ||
@@ -29,9 +28,98 @@ var Promise = require('promise'); | ||
var promise = new Promise(function (resolve, reject) { | ||
get('http://www.google.com', function (err, res) { | ||
if (err) reject(err); | ||
else resolve(res); | ||
}); | ||
get('http://www.google.com', function (err, res) { | ||
if (err) reject(err); | ||
else resolve(res); | ||
}); | ||
}); | ||
``` | ||
## API | ||
Before all examples, you will need: | ||
```js | ||
var Promise = require('promise'); | ||
``` | ||
### Promise(resolver) | ||
This creates and returns a new promise. The `new` keyword before `Promise` is optional. `resolver` must be a function. The `resolver` function is passed two arguments: | ||
1. `resolve` should be called with a single argument. If it is called with a non-promise value then the promise is fulfilled with that value. If it is called with a promise (A) then the returned promise takes on the state of that new promise (A). | ||
2. `reject` should be called with a single argument. The returned promise will be rejected with that argument. | ||
### Static Functions | ||
These methods are invoked by calling `Promise.methodName`. | ||
#### Promise.from(value) | ||
Converts values and foreign promises into Promises/A+ promises. If you pass it a value then it returns a Promise for that value. If you pass it something that is close to a promise (such as a jQuery attempt at a promise) it returns a Promise that takes on the state of `value` (rejected or fulfilled). | ||
#### Promise.denodeify(fn) | ||
Takes a function which accepts a node style callback and returns a new function that returns a promise instead. | ||
e.g. | ||
```javascript | ||
var fs = require('fs') | ||
var read = Promise.denodeify(fs.readFile) | ||
var write = Promise.denodeify(fs.writeFile) | ||
var p = read('foo.json', 'utf8') | ||
.then(function (str) { | ||
return write('foo.json', JSON.stringify(JSON.parse(str), null, ' '), 'utf8') | ||
}) | ||
``` | ||
#### Promise.nodeify(fn) | ||
The twin to `denodeify` is useful when you want to export an API that can be used by people who haven't learnt about the brilliance of promises yet. | ||
```javascript | ||
module.exports = Promise.nodeify(awesomeAPI) | ||
function awesomeAPI(a, b) { | ||
return download(a, b) | ||
} | ||
``` | ||
If the last argument passed to `module.exports` is a function, then it will be treated like a node.js callback and not parsed on to the child function, otherwise the API will just return a promise. | ||
### Prototype Methods | ||
These methods are invoked on a promise instance by calling `myPromise.methodName` | ||
### Promise#then(onFulfilled, onRejected) | ||
This method follows the [Promises/A+ spec](http://promises-aplus.github.io/promises-spec/). It explains things very clearly so I recommend you read it. | ||
Either `onFulfilled` or `onRejected` will be called and they will not be called more than once. They will be passed a single argument and will always be called asynchronously (in the next turn of the event loop). | ||
If the promise is fulfilled then `onFulfilled` is called. If the promise is rejected then `onRejected` is called. | ||
The call to `.then` also returns a promise. If the handler that is called returns a promise, the promise returned by `.then` takes on the state of that returned promise. If the handler that is called returns a value that is not a promise, the promise returned by `.then` will be fulfilled with that value. If the handler that is called throws an exception then the promise returned by `.then` is rejected with that exception. | ||
#### Promise#done(onFulfilled, onRejected) | ||
The same semantics as `.then` except that it does not return a promise and any exceptions are re-thrown so that they can be logged (crashing the applicaiton in non-browser environments) | ||
#### Promise#nodeify(callback) | ||
If `callback` is `null` or `undefined` it just returns `this`. If `callback` is a function it is called with rejection reason as the first argument and result as the second argument (as per the node.js convention). | ||
This lets you write API functions that look like: | ||
```javascript | ||
funciton awesomeAPI(foo, bar, callback) { | ||
return internalAPI(foo, bar) | ||
.then(parseResult) | ||
.then(null, retryErrors) | ||
.nodeify(callback) | ||
} | ||
``` | ||
People who use typical node.js style callbacks will be able to just pass a callback and get the expected behavior. The enlightened people can not pass a callback and will get awesome promises. | ||
## Extending Promises | ||
@@ -89,3 +177,1 @@ | ||
MIT | ||
![viewcount](https://viewcount.jepso.com/count/then/promise.png) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
13770
7
155
174
1