package/package.json000644 000767 000024 0000001376 12561270447013036 0ustar00000000 000000 { "name": "native-promise-only", "version": "0.8.1", "description": "Native Promise Only: A polyfill for native ES6 Promises **only**, nothing else.", "main": "./lib/npo.src.js", "scripts": { "test": "promises-aplus-tests test_adapter.js", "build": "./build.js" }, "devDependencies": { "promises-aplus-tests": "latest", "uglify-js": "~2.4.8" }, "repository": { "type": "git", "url": "git://github.com/getify/native-promise-only.git" }, "keywords": [ "ES6", "Promise", "async", "promises-aplus" ], "bugs": { "url": "https://github.com/getify/native-promise-only/issues", "email": "getify@gmail.com" }, "homepage": "http://github.com/getify/native-promise-only", "author": "Kyle Simpson ", "license": "MIT" } package/.npmignore000644 000767 000024 0000000030 12332250024012512 0ustar00000000 000000 node_modules .gitignore package/README.md000644 000767 000024 0000016600 12424741070012014 0ustar00000000 000000 # Native Promise Only (NPO) A polyfill for native ES6 Promises as close as possible (no extensions) to the strict spec definitions. ## Intent The aim of this project is to be the smallest polyfill for Promises, staying as close as possible to what's specified in both [Promises/A+](http://promisesaplus.com) and the [upcoming ES6 specification](http://people.mozilla.org/~jorendorff/es6-draft.html#sec-promise-objects). An equally important goal is to avoid exposing any capability for promise-state to be mutated externally. The [Known Limitations](#known-limitations) section below explains the trade-offs of that balance. ## Usage To use this polyfill in the browser, include the "npo.js" file (see the instructions in [Tests/Compliance section](#testscompliance) below for how to build "npo.js" if you don't have it already) 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 install the polyfill via bower, run: ``` bower install native-promise-only ``` To install the polyfill via npm, run: ``` npm install native-promise-only ``` Then require the module into your node code: ```js require("native-promise-only"); ``` Notice that using the module in this way, we don't assign the module's public API to any variable. **We don't need to**, because it's a polyfill that intentionally patches the global environment (in this case to the `Promise` name) once included. If you *want* to also have a reference pointing to the same `Promise` global, you *can also* assign the return value from the `require(..)` statement, but it's strongly recommended that you use the same `Promise` name so as to not create confusion: ```js var Promise = require("native-promise-only"); // Promise === global.Promise; // true! ``` Other than the below [Known Limitations](#known-limitations) discussion and some browser bugs (such as [these](https://gist.github.com/getify/bd11ccf1eff2efdac0fb)) which **this polyfill doesn't suffer from**, 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 promises, check these blog posts out: 1. Back-story on the hows and whys behind promises (chaining, errors, etc): [multi-part blog post series "Promises"](http://blog.getify.com/promises-part-1/) by [getify](http://twitter.com/getify) (me). 2. Using and enjoying native promises: [JavaScript Promises](http://www.html5rocks.com/en/tutorials/es6/promises/) by [Jake Archibald](http://twitter.com/jaffathecake). ## Known Limitations A promise object from this polyfill **will be** an instance of the `Promise` constructor, which makes identification of genuine promises easier: ```js var p = new Promise(..); p instanceof Promise; // true ``` However, these promise instances don't inherit (delegate to) a *meaningful* `Promise.prototype` object for their methods (there is one, it's just mostly empty). Consider: ```js var p = new Promise(..); Object.getOwnPropertyNames( p ); // [ then, catch ] Object.getOwnPropertyNames( Promise.prototype ); // [ constructor ] ``` 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. To read a full explanation of why, read [Part 3: The Trust Problem](http://blog.getify.com/promises-part-3/) of my blog post series on Promises. Briefly, 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: *no ES6 sub-classing*. 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. ## 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](http://blog.getify.com/promises-part-5/) 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 internal "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](http://davidwalsh.name/asynquence-part-1) and is still only ~2k!). ## Tests/Compliance Promises/A+ logo *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 all tests: 1. Either git-clone this repo or run `npm install native-promise-only`, and then switch into that project root. 2. Run `npm install` in the project root to install the dev-dependencies. 3. If you didn't get *native-promise-only* from npm, then from the project root, run `./build.js` or `node build.js` or `npm run build` to generate the minified "npo.js" in the project root. 4. Finally, run `npm test`. **Note:** Other tests need to be added, such as testing the `Promise()` constructor's behavior, as well as the `Promise.*` static helpers (`resolve(..)`, `reject(..)`, `all(..)`, and `race(..)`), none of which are covered by the 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 The code and all the documentation are released under the MIT license. http://getify.mit-license.org/ package/build.js000744 000767 000024 0000001050 12345175057012174 0ustar00000000 000000 #!/usr/bin/env node var fs = require("fs"), path = require("path"), exec = require("child_process").exec, ugly = require("uglify-js"), result ; console.log("*** Building ***"); console.log("Minifying to npo.js."); try { result = ugly.minify(path.join(__dirname,"lib","npo.src.js"),{ mangle: true, compress: true, output: { comments: /^!/ } }); fs.writeFileSync( path.join(__dirname,"npo.js"), result.code + "\n", { encoding: "utf8" } ); console.log("Complete."); } catch (err) { console.error(err); process.exit(1); } package/test_adapter.js000644 000767 000024 0000001006 12535624312013546 0ustar00000000 000000 // Adapter for "promises-aplus-tests" test runner var path = require("path"); var Promise = require(path.join(__dirname,"lib","npo.src.js")); module.exports.deferred = function __deferred__() { var o = {}; o.promise = new Promise(function __Promise__(resolve,reject){ o.resolve = resolve; o.reject = reject; }); return o; }; module.exports.resolved = function __resolved__(val) { return Promise.resolve(val); }; module.exports.rejected = function __rejected__(reason) { return Promise.reject(reason); }; package/lib/npo.src.js000644 000767 000024 0000017661 12561270415013235 0ustar00000000 000000 /*! Native Promise Only v0.8.1 (c) Kyle Simpson MIT License: http://getify.mit-license.org */ (function UMD(name,context,definition){ // special form of UMD for polyfilling across evironments context[name] = context[name] || definition(); if (typeof module != "undefined" && module.exports) { module.exports = context[name]; } else if (typeof define == "function" && define.amd) { define(function $AMD$(){ return context[name]; }); } })("Promise",typeof global != "undefined" ? global : this,function DEF(){ /*jshint validthis:true */ "use strict"; var builtInProp, cycle, scheduling_queue, ToString = Object.prototype.toString, timer = (typeof setImmediate != "undefined") ? function timer(fn) { return setImmediate(fn); } : setTimeout ; // dammit, IE8. try { Object.defineProperty({},"x",{}); builtInProp = function builtInProp(obj,name,val,config) { return Object.defineProperty(obj,name,{ value: val, writable: true, configurable: config !== false }); }; } catch (err) { builtInProp = function builtInProp(obj,name,val) { obj[name] = val; return obj; }; } // Note: using a queue instead of array for efficiency scheduling_queue = (function Queue() { var first, last, item; function Item(fn,self) { this.fn = fn; this.self = self; this.next = void 0; } return { add: function add(fn,self) { item = new Item(fn,self); if (last) { last.next = item; } else { first = item; } last = item; item = void 0; }, drain: function drain() { var f = first; first = last = cycle = void 0; while (f) { f.fn.call(f.self); f = f.next; } } }; })(); function schedule(fn,self) { scheduling_queue.add(fn,self); if (!cycle) { cycle = timer(scheduling_queue.drain); } } // promise duck typing function isThenable(o) { var _then, o_type = typeof o; if (o != null && ( o_type == "object" || o_type == "function" ) ) { _then = o.then; } return typeof _then == "function" ? _then : false; } function notify() { for (var i=0; i 0) { schedule(notify,self); } } } catch (err) { reject.call(new MakeDefWrapper(self),err); } } function reject(msg) { var self = this; // already triggered? if (self.triggered) { return; } self.triggered = true; // unwrap if (self.def) { self = self.def; } self.msg = msg; self.state = 2; if (self.chain.length > 0) { schedule(notify,self); } } function iteratePromises(Constructor,arr,resolver,rejecter) { for (var idx=0; idx