Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

First commit.

  • Loading branch information...
commit d93cee741317a8888d8d3d4c7d267a3c227edb19 0 parents
@rkatic authored
Showing with 320 additions and 0 deletions.
  1. +1 −0  .gitignore
  2. +263 −0 p.js
  3. +20 −0 package.json
  4. +12 −0 test/adapter.js
  5. +24 −0 test/perf.js
1  .gitignore
@@ -0,0 +1 @@
+node_modules
263 p.js
@@ -0,0 +1,263 @@
+;(function( factory ){
+ if ( typeof module !== "undefined" && module.exports ) {
+ module.exports = factory();
+
+ } else if ( typeof define !== "undefined" ) {
+ define( factory );
+
+ } else {
+ P = factory();
+ }
+})(function() {
+ "use strict";
+
+ var
+ // linked list with head node - used as a queue of tasks
+ // f: task, w: ticks required, n: next node
+ head = { f: null, w: 0, n: null }, tail = head,
+
+ // vars for tick re-usage
+ lastIsSafe = false, pendingTicks = 0, neededTicks = 0,
+ requestTick, // requestTick( onTick, 0 ) is the only valid usage!
+
+ // window or worker
+ wow = ot(typeof window) && window || ot(typeof worker) && worker;
+
+ function onTick() {
+ --pendingTicks;
+ while ( head.n ) {
+ head = head.n;
+ neededTicks -= head.w;
+ var f = head.f;
+ head.f = null;
+ f();
+ }
+ lastIsSafe = false;
+ }
+
+ function runLater( f, couldThrow ) {
+ var w = 0;
+ if ( !lastIsSafe && ++neededTicks > pendingTicks ) {
+ ++pendingTicks;
+ requestTick( onTick, 0 );
+ w = 1;
+ };
+ tail = tail.n = { f: f, w: w, n: null };
+ lastIsSafe = couldThrow !== true;
+ }
+
+ function ot( type ) {
+ return type === "object" || type === "function";
+ }
+
+ function ft( type ) {
+ return type === "function";
+ }
+
+
+ if ( ot(typeof process) && process && ft(typeof process.nextTick) ) {
+ requestTick = process.nextTick;
+
+ } else if ( wow && ft(typeof wow.setImmediate) ) {
+ requestTick = function( cb ) {
+ wow.setImmediate( cb );
+ };
+
+ } else if ( ft(typeof MessageChannel) ) {
+ var channel = new MessageChannel();
+ channel.port1.onmessage = onTick;
+ requestTick = function() {
+ channel.port2.postMessage(0);
+ };
+
+ } else {
+ requestTick = setTimeout;
+
+ if ( wow && ot(typeof Image) && Image ) {
+ (function(){
+ var c = 0;
+
+ var requestTickViaImage = function( cb ) {
+ var img = new Image();
+ img.onerror = cb;
+ img.src = 'data:image/png,';
+ };
+
+ try {
+ requestTickViaImage(function() {
+ if ( --c === 0 ) {
+ requestTick = requestTickViaImage;
+ }
+ });
+ ++c;
+ } catch (e) {}
+
+ c && setTimeout(function() {
+ c = 0;
+ }, 0);
+ })();
+ }
+ }
+
+ //__________________________________________________________________________
+
+ function each( arr, cb ) {
+ for ( var i = 0, l = arr.length; i < l; ++i ) {
+ cb( arr[i], i );
+ }
+ }
+
+ var P = resolve;
+ P.prototype = Promise.prototype;
+
+ P.defer = defer;
+ function defer() {
+ var pending = [],
+ rejected = false,
+ value;
+
+ function then( onFulfilled, onRejected ) {
+ var def = defer();
+
+ function onReslved() {
+ var func = rejected ? onRejected : onFulfilled;
+
+ if ( typeof func !== "function" ) {
+ if ( rejected ) {
+ def.reject( value );
+ return;
+ }
+ func = void 0;
+ }
+
+ try {
+ def.resolve( func ? func(value) : value );
+ } catch ( ex ) {
+ def.reject( ex );
+ }
+ }
+
+ if ( pending ) {
+ pending.push( onReslved );
+
+ } else {
+ runLater( onReslved );
+ }
+
+ return def.promise;
+ }
+
+ function resolve( val ) {
+ if ( pending ) {
+ if ( !rejected && val && typeof val.then === "function" ) {
+ val.then( resolve, reject );
+
+ } else {
+ value = val;
+ each( pending, runLater );
+ pending = null;
+ }
+ }
+ }
+
+ // should never throw!!!
+ function reject( error ) {
+ if ( pending ) {
+ rejected = true;
+ resolve( error );
+ }
+ }
+
+ return {
+ promise: new Promise( then ),
+ resolve: resolve,
+ reject: reject
+ };
+ }
+
+
+ function Promise( then ) {
+ this.then = then;
+ }
+
+ Promise.prototype.done = function( cb, eb ) {
+ var p = this;
+ if ( cb || eb ) {
+ p = p.then( cb, eb );
+ }
+ p.then(null, function( error ) {
+ runLater(function() {
+ if ( P.onerror ) {
+ P.onerror( error );
+ } else {
+ throw error;
+ }
+ }, true);
+ });
+ };
+
+ Promise.prototype.spread = function( cb, eb ) {
+ return this.then(cb && function( values ) {
+ return cb.apply( void 0, values );
+ }, eb);
+ };
+
+ P.resolve = resolve;
+ function resolve( value ) {
+ if ( value instanceof Promise ) {
+ return value;
+ }
+
+ var def = defer();
+ def.resolve( value );
+ return def.promise;
+ }
+
+ P.reject = reject;
+ function reject( value ) {
+ var def = defer();
+ def.reject( value );
+ return def.promise;
+ }
+
+ P.all = all;
+ function all( promises ) {
+ var countDown = promises.length;
+ if ( countDown === 0 ) {
+ return resolve( promises );
+ }
+ var def = defer();
+ each(promises, function( promise, index ) {
+ resolve( promise ).then(function( value ) {
+ promises[ index ] = value;
+ if ( --countDown === 0 ) {
+ def.resolve( promises );
+ }
+ }, def.reject );
+ });
+ return def.promise;
+ }
+
+ P.promise = function( makeOrPromise ) {
+ var def = defer();
+ resolve( makeOrPromise )
+ .then(function( make ) {
+ try {
+ make( def.resolve, def.reject );
+ } catch ( ex ) {
+ def.reject( ex );
+ }
+ }, def.reject);
+ return def.promise;
+ };
+
+ P.onerror = null;
+
+ P.nextTick = function( f ) {
+ runLater( f, true );
+ };
+
+ //P.runLater = runLater;
+
+ return P;
+});
20 package.json
@@ -0,0 +1,20 @@
+{
+ "name": "p-promise",
+ "version": "0.0.1",
+ "description": "Simple promise-a library.",
+ "main": "p.js",
+ "scripts": {
+ "test": "promises-aplus-tests test/adapter",
+ "prepublish": "uglifyjs p.js > p.min.js"
+ },
+ "keywords": [
+ "promise",
+ "promises"
+ ],
+ "author": "rkatic",
+ "license": "MIT",
+ "devDependencies": {
+ "promises-aplus-tests": "*",
+ "uglify-js": "*"
+ }
+}
12 test/adapter.js
@@ -0,0 +1,12 @@
+
+var P = require('../p');
+
+exports.pending = function() {
+ var def = P.defer();
+ def.fulfill = def.resolve;
+ return def;
+};
+
+exports.fulfilled = P.resolve;
+
+exports.rejected = P.reject;
24 test/perf.js
@@ -0,0 +1,24 @@
+
+var P = require('../p');
+var task = function(){};
+
+function testOne( name, f, n ) {
+ var time = process.hrtime();
+
+ while ( n-- ) {
+ f( task );
+ }
+
+ var diff = process.hrtime( time );
+ console.log( "%s: %d ns", name, diff[0] * 1e9 + diff[1] );
+}
+
+module.exports = function( n ) {
+ testOne('nextTick', process.nextTick, n);
+
+ P.setSafe(false);
+ testOne('runLater (unsafe)', P.runLater, n);
+
+ P.setSafe(true);
+ testOne('runLater (safe)', P.runLater, n);
+}
Please sign in to comment.
Something went wrong with that request. Please try again.