bluebird
Version:
Full featured Promises/A+ implementation with exceptionally good performance
142 lines (133 loc) • 4.46 kB
JavaScript
/**
* Copyright (c) 2013 Petka Antonov
*
* 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:</p>
*
* 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.
*/
"use strict";
var ASSERT = require("./assert.js");
var util = require( "./util.js" );
var async = require( "./async.js" );
var errorObj = util.errorObj;
function Thenable() {
this.errorObj = errorObj;
this.__id__ = 0;
this.treshold = 1000;
this.thenableCache = new Array( this.treshold );
this.promiseCache = new Array( this.treshold );
this._compactQueued = false;
}
Thenable.prototype.couldBe = function Thenable$couldBe( ret ) {
if( ret === null ||
typeof ret === "undefined" ||
typeof ret === "string" ||
typeof ret === "boolean" ||
typeof ret === "number" ) {
return false;
}
var id = ret.__id_$thenable__;
if( typeof id === "number" &&
this.thenableCache[id] !== void 0 ) {
return true;
}
return ("then" in ret);
};
Thenable.prototype.is = function Thenable$is( ret, ref ) {
var id = ret.__id_$thenable__;
if( typeof id === "number" &&
this.thenableCache[id] !== void 0 ) {
ref.ref = this.thenableCache[id];
ref.promise = this.promiseCache[id];
return true;
}
return this._thenableSlowCase( ret, ref );
};
Thenable.prototype.addCache = function Thenable$_addCache( thenable, promise ) {
var id = this.__id__;
this.__id__ = id + 1;
var descriptor = this._descriptor( id );
Object.defineProperty( thenable, "__id_$thenable__", descriptor );
this.thenableCache[id] = thenable;
this.promiseCache[id] = promise;
if( this.thenableCache.length > this.treshold &&
!this._compactQueued) {
this._compactQueued = true;
async.invokeLater( this._compactCache, this, void 0 );
}
};
Thenable.prototype.deleteCache = function Thenable$deleteCache( thenable ) {
var id = thenable.__id_$thenable__;
if( id === -1 ) {
return;
}
this.thenableCache[id] = void 0;
this.promiseCache[id] = void 0;
thenable.__id_$thenable__ = -1;};
var descriptor = {
value: 0,
enumerable: false,
writable: true,
configurable: true
};
Thenable.prototype._descriptor = function Thenable$_descriptor( id ) {
descriptor.value = id;
return descriptor;
};
Thenable.prototype._compactCache = function Thenable$_compactCache() {
var arr = this.thenableCache;
var promiseArr = this.promiseCache;
var skips = 0;
var j = 0;
for( var i = 0, len = arr.length; i < len; ++i ) {
var item = arr[ i ];
if( item === void 0 ) {
skips++;
}
else {
promiseArr[ j ] = promiseArr[ i ];
item.__id_$thenable__ = j;
arr[ j++ ] = item;
}
}
var newId = arr.length - skips;
if( newId === this.__id__ ) {
this.treshold *= 2;
}
else for( var i = newId, len = arr.length; i < len; ++i ) {
promiseArr[ j ] = arr[ i ] = void 0;
}
this.__id__ = newId;
this._compactQueued = false;
};
Thenable.prototype._thenableSlowCase =
function Thenable$_thenableSlowCase( ret, ref ) {
try {
var then = ret.then;
if( typeof then === "function" ) {
ref.ref = then;
return true;
}
return false;
}
catch(e) {
this.errorObj.e = e;
ref.ref = this.errorObj;
return true;
}
};
module.exports = Thenable;