native-promise-only
Advanced tools
Comparing version 0.0.0-a to 0.0.1-a
@@ -1,2 +0,5 @@ | ||
// Native Promise Only - (c) 2014 Kyle Simpson - MIT License | ||
/*! Native Promise Only | ||
v0.0.1-a (c) Kyle Simpson | ||
MIT License: http://getify.mit-license.org | ||
*/ | ||
@@ -76,20 +79,36 @@ (function UMD(name,context,definition){ | ||
function resolve(msg) { | ||
if (this.state !== 0) { | ||
var _then, self, obj; | ||
if (this.def) { | ||
if (this.triggered) { | ||
return; | ||
} | ||
this.triggered = true; | ||
self = this.def; | ||
} | ||
else { | ||
self = this; | ||
} | ||
if (self.state !== 0) { | ||
return; | ||
} | ||
var _then; | ||
obj = { | ||
def: self, | ||
triggered: false | ||
}; | ||
try { | ||
if ((_then = isThenable(msg))) { | ||
_then.call(msg,resolve.bind(this),reject.bind(this)); | ||
_then.call(msg,resolve.bind(obj),reject.bind(obj)); | ||
} | ||
else { | ||
this.msg = msg; | ||
this.state = 1; | ||
schedule(notify.bind(this)); | ||
self.msg = msg; | ||
self.state = 1; | ||
schedule(notify.bind(self)); | ||
} | ||
} | ||
catch (err) { | ||
reject.call(this,err); | ||
reject.call(obj,err); | ||
} | ||
@@ -108,23 +127,22 @@ } | ||
function reject(msg) { | ||
if (this.state !== 0) { | ||
return; | ||
} | ||
var self; | ||
var _then; | ||
try { | ||
if ((_then = isThenable(msg))) { | ||
_then.call(msg,resolve.bind(this),reject.bind(this)); | ||
if (this.def) { | ||
if (this.triggered) { | ||
return; | ||
} | ||
else { | ||
this.msg = msg; | ||
this.state = 2; | ||
schedule(notify.bind(this)); | ||
} | ||
this.triggered = true; | ||
self = this.def; | ||
} | ||
catch (err) { | ||
this.msg = err; | ||
this.state = 2; | ||
schedule(notify.bind(this)); | ||
else { | ||
self = this; | ||
} | ||
if (self.state !== 0) { | ||
return; | ||
} | ||
self.msg = msg; | ||
self.state = 2; | ||
schedule(notify.bind(self)); | ||
} | ||
@@ -142,4 +160,4 @@ | ||
function then(success,failure) { | ||
this.success.push(isFunction(success) ? success : function(m){ return m; }); | ||
this.failure.push(isFunction(failure) ? failure : function(m){ throw m; }); | ||
this.success.push(isFunction(success) ? success : function __default_success__(m){ return m; }); | ||
this.failure.push(isFunction(failure) ? failure : function __default_failure__(m){ throw m; }); | ||
@@ -146,0 +164,0 @@ var p = new Promise(function __Promise__(resolve,reject){ |
{ | ||
"name": "native-promise-only", | ||
"version": "0.0.0-a", | ||
"version": "0.0.1-a", | ||
"description": "Native Promise Only: A polyfill for native ES6 Promises **only**, nothing else.", | ||
"main": "./lib/npo.src.js", | ||
"main": "./npo.js", | ||
"scripts": { | ||
"test": "promises-aplus-tests test_adapter.js" | ||
"test": "promises-aplus-tests test_adapter.js", | ||
"build": "./build.js" | ||
}, | ||
"devDependencies": { | ||
"promises-aplus-tests": "*" | ||
"promises-aplus-tests": "*", | ||
"uglify-js": "~2.4.8" | ||
}, | ||
@@ -12,0 +14,0 @@ "repository": { |
# Native Promise Only (NPO) | ||
A polyfill for native ES6 Promises that deviates as little as possible from the strict spec definition (no add-ons). | ||
A polyfill for native ES6 Promises that as close as possible (no extensions) to the strict spec definitions. | ||
## Intent | ||
The aim of this project is to be the smallest (and maybe the fastest!?) polyfill for Promises, staying as close as possible to what's specified in both [Promises/A+](http://promisesaplus.com) and the upcoming ES6 specification (**link needed**). | ||
An equally important goal is to avoid exposing any capability for promise-state to be mutated externally. The next section explains the trade-offs of that balance. | ||
## Known Limitations | ||
A promise object **will be** an instance of the `Promise` object: | ||
On the bright side, a promise object from this polyfill **will be** an instance of the `Promise` constructor, which makes identification of genuine promises easier: | ||
@@ -15,3 +21,3 @@ ```js | ||
However, these promise instances don't inherit (delegate to) a meaningful `Promise.prototype` object. That is: | ||
However, these promise instances don't inherit (delegate to) a *meaningful* `Promise.prototype` object for their methods. That is: | ||
@@ -25,21 +31,88 @@ ```js | ||
As such, these promises are not really "sub-classable" in the ES6 `class` / `extends` sense, though theoretically you should be able to do that in ES6. | ||
As such, these promises are not really "sub-classable" in the ES6 `class` / `extends` sense, though theoretically you should be able to do that in ES6 with the built-in Promises. | ||
The reason for this deviation is that there's a choice between having delegated methods on the `.prototype` or having private state. Since **the spirit of promises was always to ensure trustability** -- that they were immutable to everyone except the initial resolver/deferred -- private state is a critically important feature to preserve. | ||
The reason for this deviation is that there's a choice between having delegated methods on the `.prototype` or having private state. Since **the spirit of promises was always to ensure trustability** -- that promises were immutable (from the outside) to everyone except the initial resolver/deferred -- private state is a critically important feature to preserve. | ||
Many other ES6 promise shims/libs seem to have forgotten that important point, as many of them either expose the state publicly on the object instance or provide public accessor methods which can externally mutate a promise's state. Both of these deviations are intolerable in my opinion, so this library chose the opposite trade-off: loss of ES6 sub-classing. | ||
Many other ES6 promise shims/libs seem to have forgotten that important point, as many of them either expose the state publicly on the object instance or provide public accessor methods which can externally mutate a promise's state. Both of these deviations are **intolerable** in my opinion, so this library chose the opposite trade-off: *no ES6 sub-classing*. | ||
## Test Compliance | ||
Any trade-off is a shame, but this one is the least of a few evils, and probably won't prove to limit very many, as there are only a limited number of use-cases for `extend`ing `Promise` in the ES6 sub-class sense. | ||
This polyfill/shim is aiming to be "spec compliant" in the sense of passing all tests in the [Promises/A+ Test Suite](https://github.com/promises-aplus/promises-tests). | ||
## ES5 Assumption | ||
Test status at present: | ||
This polyfill assumes various ES5 capabilities, such as `Function#bind` and `Array#forEach`. If you need to use this polyfill in older JS environments, make sure to provide polyfills/shims [such as these](https://github.com/es-shims/es5-shim). | ||
*Native Promise Only* needs (all of which have compliant ES5 shims): | ||
* `Array.isArray` | ||
* `Array#forEach` | ||
* `Array#some` | ||
* `Function#bind` | ||
## Usage | ||
To use this polyfill in the browser, include the "npo.js" file with your site's scripts. It's a polyfill, which means it will not overwrite `Promise` if it exists as a global already, so it's safe to include unconditionally. | ||
To use with AMD, import the "npo.js" file module. | ||
To use the polyfill in node, run: | ||
``` | ||
824 passing | ||
48 failing | ||
npm install native-promise-only | ||
``` | ||
Then require the module into your node code like this: | ||
``` | ||
var Promise = require("native-promise-only"); | ||
``` | ||
Other than the above "Known Limitations" discussion and some browser bugs (such as [these](https://gist.github.com/getify/bd11ccf1eff2efdac0fb)) which **this polyfill doesn't have**, your promises should operate the same in all JS environments. | ||
Exactly like native promises, here's a quick example of how you create and use the polyfilled promises: | ||
```js | ||
var p = new Promise(function(resolve,reject){ | ||
setTimeout(function(){ | ||
resolve("Yay!"); | ||
},100); | ||
}); | ||
p.then(function(msg){ | ||
console.log(msg); // Yay! | ||
}); | ||
``` | ||
For more on how to use and enjoy native (or polyfilled!) promises, check out [JavaScript Promises](http://www.html5rocks.com/en/tutorials/es6/promises/) by [Jake Archibald](http://twitter.com/jaffathecake). | ||
## Still Want More? | ||
This project intentionally adheres pretty strictly to the narrow core of [Promises/A+](http://promisesaplus.com) as adopted/implemented by ES6 into the native `Promise()` mechanism. | ||
But it's quite likely that you will experience a variety of scenarios in which using *only* native promises might be tedious, limiting, or more trouble than it's worth. There's good reason why most other **Promises/A+** "compliant" libs are actually superset extensions on the narrow core: **because async flow-control is often quite complex in the real world.** | ||
*Native Promise Only* will not add any of these extra flourishes. Sorry. | ||
**However, I have another project**: [asynquence](http://github.com/getify/asynquence) (async + sequence). It's an abstraction on top of the promises concept (promises are hidden inside), designed to drastically improve the readability and expressiveness of your async flow-control code. | ||
You simply express your async flow-control and *asynquence* creates and chains all the promises for you underneath. **Super simple.** | ||
*asynquence* has a custom implementation for the hidden "promises" it uses, and as such does not need native `Promises`, nor does it need/include this polyfill. | ||
Get your feet wet with native promises first, but then when you go looking for something more, consider [asynquence](http://github.com/getify/asynquence) (which is vastly more powerful and is still only 2k!). | ||
## Tests/Compliance | ||
<a href="http://promisesaplus.com/" float="right"> | ||
<img src="http://promisesaplus.com/assets/logo-small.png" alt="Promises/A+ logo" | ||
title="Promises/A+ 1.1 compliant" align="right" /> | ||
</a> | ||
*Native Promise Only* is "spec compliant" in the sense of passing all tests in the [Promises/A+ Test Suite](https://github.com/promises-aplus/promises-tests). | ||
To run the test suite after cloning this repo, run `npm install` to install the dev-dependencies, then run `npm test`. | ||
However, there are definitely other tests that need to be added, for example testing the `Promise()` constructor's behavior, as well as the `Promise.*` static helpers (`resolve(..)`, `reject(..)`, `all(..)`, and `race(..)`), none of which are covered by Promises/A+ test suite. | ||
Developing a more comprehensive test-suite to augment the Promises/A+ test suite **is now another primary goal** of this project. | ||
## License | ||
@@ -46,0 +119,0 @@ |
// Adapter for "promises-aplus-tests" test runner | ||
var Promise = require(__dirname + "/lib/npo.src.js"); | ||
var path = require("path"); | ||
var Promise = require(path.join(__dirname,"/npo.js")); | ||
@@ -5,0 +6,0 @@ module.exports.deferred = function __deferred__() { |
195
tests.js
@@ -17,104 +17,137 @@ var Promise = require("./lib/npo.src.js"); | ||
delay("Hello World") | ||
.then(function(msg){ | ||
console.log(msg); | ||
return msg; | ||
}) | ||
.then(function(msg){ | ||
return delay(msg.toUpperCase()); | ||
}) | ||
.then(function(msg){ | ||
console.log(msg); | ||
}); | ||
// delay("Hello World") | ||
// .then(function(msg){ | ||
// console.log(msg); | ||
// return msg; | ||
// }) | ||
// .then(function(msg){ | ||
// return delay(msg.toUpperCase()); | ||
// }) | ||
// .then(function(msg){ | ||
// console.log(msg); | ||
// }); | ||
Promise.race([ | ||
delay("Hello"), | ||
delay("World") | ||
]) | ||
.then(function(msgs){ | ||
console.log(msgs); | ||
}); | ||
// Promise.race([ | ||
// delay("Hello"), | ||
// delay("World") | ||
// ]) | ||
// .then(function(msgs){ | ||
// console.log(msgs); | ||
// }); | ||
var x = Promise.resolve(2); | ||
// var x = Promise.resolve(2); | ||
var p = x.then(function(){ | ||
return 5; | ||
}); | ||
// var p = x.then(function(){ | ||
// return 5; | ||
// }); | ||
var p2 = x.then(function(){ | ||
return p2; | ||
}); | ||
// var p2 = x.then(function(){ | ||
// return p2; | ||
// }); | ||
p.then(function(msg){ | ||
console.log("p:" + msg); | ||
}, | ||
function(err){ | ||
console.log("p-err:" + err); | ||
}); | ||
// p.then(function(msg){ | ||
// console.log("p:" + msg); | ||
// }, | ||
// function(err){ | ||
// console.log("p-err:" + err); | ||
// }); | ||
p2.then(function(msg){ | ||
console.log("p2:" + msg); | ||
}, | ||
function(err){ | ||
console.log("p2-err:" + err); | ||
}); | ||
// p2.then(function(msg){ | ||
// console.log("p2:" + msg); | ||
// }, | ||
// function(err){ | ||
// console.log("p2-err:" + err); | ||
// }); | ||
Promise.reject(42).then(null,null).then(null,function(reason){ | ||
console.log("reason:" + reason); | ||
}); // reason:42 | ||
// Promise.reject(42).then(null,null).then(null,function(reason){ | ||
// console.log("reason:" + reason); | ||
// }); // reason:42 | ||
Promise.reject(42).then(5,null).then(null,function(reason){ | ||
console.log("reason:" + reason); | ||
}); // reason:42 | ||
// Promise.reject(42).then(5,null).then(null,function(reason){ | ||
// console.log("reason:" + reason); | ||
// }); // reason:42 | ||
Promise.reject(42).then(null,5).then(null,function(reason){ | ||
console.log("reason:" + reason); | ||
}); // TypeError: number is not a function | ||
// Promise.reject(42).then(null,5).then(null,function(reason){ | ||
// console.log("reason:" + reason); | ||
// }); // TypeError: number is not a function | ||
// ************* | ||
// // ************* | ||
Promise.resolve(42).then(null,null).then(function(msg){ | ||
console.log("msg:" + msg); | ||
},null); // msg:42 | ||
// Promise.resolve(42).then(null,null).then(function(msg){ | ||
// console.log("msg:" + msg); | ||
// },null); // msg:42 | ||
Promise.resolve(42).then(null,5).then(function(msg){ | ||
console.log("msg:" + msg); | ||
},null); // msg:42 | ||
// Promise.resolve(42).then(null,5).then(function(msg){ | ||
// console.log("msg:" + msg); | ||
// },null); // msg:42 | ||
Promise.resolve(42).then(5,null).then(function(msg){ | ||
console.log("msg:" + msg); | ||
},null); // (nothing printed) | ||
// Promise.resolve(42).then(5,null).then(function(msg){ | ||
// console.log("msg:" + msg); | ||
// },null); // (nothing printed) | ||
var dummy = { dummy: "dummy" }; // we fulfill or reject with this when we don't intend to test against it | ||
var sentinel = { sentinel: "sentinel" }; // a sentinel fulfillment value to test for with strict equality | ||
// var dummy = { dummy: "dummy" }; // we fulfill or reject with this when we don't intend to test against it | ||
// var sentinel = { sentinel: "sentinel" }; // a sentinel fulfillment value to test for with strict equality | ||
function thenable(value) { | ||
return { | ||
then: function (onFulfilled) { | ||
onFulfilled(value); | ||
} | ||
}; | ||
} | ||
// function thenable(value) { | ||
// return { | ||
// then: function (onFulfilled) { | ||
// onFulfilled(value); | ||
// } | ||
// }; | ||
// } | ||
function yFactory() { | ||
return thenable(sentinel); | ||
} | ||
// function yFactory() { | ||
// return thenable(sentinel); | ||
// } | ||
function xFactory() { | ||
return { | ||
then: function (resolvePromise) { | ||
resolvePromise(yFactory()); | ||
} | ||
}; | ||
} | ||
// function xFactory() { | ||
// return { | ||
// then: function (resolvePromise) { | ||
// resolvePromise(yFactory()); | ||
// } | ||
// }; | ||
// } | ||
var promise = Promise.resolve(dummy).then(function() { | ||
return xFactory(); | ||
}); | ||
// var promise = Promise.resolve(dummy).then(function() { | ||
// return xFactory(); | ||
// }); | ||
promise.then(function onPromiseFulfilled(value) { | ||
console.log(value === sentinel); | ||
}); | ||
// promise.then(function onPromiseFulfilled(value) { | ||
// console.log(value === sentinel); | ||
// }); | ||
//var p1 = new Promise(function(resolve,reject){ | ||
// setTimeout(reject,1000,"reject-p1"); | ||
//}); | ||
var inner = { | ||
then: function(s,f) { | ||
console.log("inner.then"); | ||
setTimeout(s,500,"inner.then"); | ||
} | ||
}; | ||
var outer = { | ||
then: function(s,f) { | ||
console.log("outer.then"); | ||
console.log("first call to s()"); | ||
s(inner); | ||
console.log("now throwing"); | ||
throw "booyah"; | ||
} | ||
}; | ||
var p2 = Promise.resolve(outer) | ||
.then( | ||
function(msg){ | ||
console.log("msg:" + msg); | ||
}, | ||
function(reason){ | ||
console.log("err:" + reason); | ||
} | ||
); | ||
Sorry, the diff of this file is not supported yet
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
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
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
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
18485
8
395
121
2
2
1