UNPKG

bluebird

Version:

Full featured Promises/A+ implementation with exceptionally good performance

142 lines (133 loc) 4.46 kB
/** * 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;