Last active
December 16, 2015 11:18
-
-
Save teramako/5426245 to your computer and use it in GitHub Desktop.
テキトウに Promise 実装。WeakMap とか for-of とか、その他 ECMAScript 6th 機能を使っているので、一般には使えないけど。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* @example 1 | |
* Promise.when( | |
* asyncFunc1(), | |
* asyncFunc2() | |
* ).then( | |
* function done (p1, p2){ console.log("resolved: ", p1.isResolved, p2.isResolved); }, | |
* function reject(p1, p2){ console.log("rejected: ", p2.isRejected, p2.isRejected); } | |
* ); | |
* function asycFunc1 () { | |
* var p = Promise(); | |
* setTimeout(function() { | |
* console.log("promise 1: resolved"); | |
* p.resolve(); | |
* }, ~~(Math.random() * 1500)); | |
* } | |
* function asyncFunc2 () { | |
* var p = Promise(); | |
* setTimeout(function() { | |
* console.log("promise 2: reject"); | |
* p.reject(); | |
* }, ~~(Math.random() * 1500)); | |
* } | |
* | |
* @example 2: extends Promise | |
* function ExPromise() { | |
* Promise.call(this); | |
* } | |
* ExPromise.prototype = Object.create(Promise.prototype); | |
* ExPromise.prototype.do = function (delay) { | |
* setTimeout(function (self) { | |
* console.group("ExPromise.do"); | |
* //... | |
* console.log("ExPromise.do: done"); | |
* console.groupEnd(); | |
* self.resolve(); | |
* }, delay, this); | |
* return this; | |
* }; | |
* | |
* var ep = new ExPromise; | |
* ep.do().then(function() { // thisBinding is the instance | |
* console.log("ep: done", "Result:" + this.isResolved); | |
* }); | |
*/ | |
;(function (id, factory) { | |
if (typeof define === "function") { // RequireJS | |
define(factory); | |
} else if (typeof require === "function") { // CommonJS | |
factory.call(this, require, exports, module); | |
} else { | |
factory(null, this); | |
if (String(this) === "[object BackstagePass]") { // JSM | |
this.EXPORTED_SYMBOLS = [id]; | |
} | |
} | |
}).call(this, "Promise", function Promise (require, exports, module) { | |
"use strict"; | |
var promiseMap = WeakMap(); | |
var argumentsMap = WeakMap(); | |
function mixin (aTarget, aSource) { | |
var desc, key; | |
for (key of Object.getOwnPropertyNames(aSource)) { | |
desc = Object.getOwnPropertyDescriptor(aSource, key); | |
desc.enumerable = false; | |
Object.defineProperty(aTarget, key, desc); | |
} | |
return aTarget; | |
} | |
function PromiseInternal () { | |
return Object.create(PromiseInternal.prototype, { | |
status: { value: undefined, writable: true }, | |
onCompletes: { value: [], writable: true }, | |
onFails: { value: [], writable: true }, | |
}); | |
} | |
mixin(PromiseInternal.prototype, { | |
fire: function PI_fire (aContext = null) { | |
if (this.status == null) | |
return aContext; | |
var callbacks = this.status ? this.onCompletes : this.onFails; | |
var args = argumentsMap.get(this) || []; | |
this.onCompletes = []; | |
this.onFails = []; | |
for (var cb of callbacks) { | |
cb.apply(aContext, args); | |
} | |
return aContext; | |
}, | |
setStatus: function PI_setStatusAndFire (aStatus, aArgs = [], aContext = null) { | |
this.status = aStatus; | |
argumentsMap.set(this, aArgs); | |
return this.fire(aContext); | |
}, | |
setCallbacks: function PI_setCallbacks (aStatus, aCallbacks, aContext = null) { | |
var prop = aStatus ? "onCompletes" : "onFails"; | |
this[prop] = this[prop].concat(aCallbacks); | |
return this.fire(aContext); | |
}, | |
}); | |
function Promise (aContext = null) { | |
"use strict"; | |
var p = this ? this : Object.create(Promise.prototype); | |
promiseMap.set(p, PromiseInternal()); | |
return p; | |
} | |
mixin(Promise.prototype, { | |
then: function Promise_then (aOnComplete, aOnFail) { | |
var promise = promiseMap.get(this); | |
if (typeof aOnComplete === "function") | |
promise.onCompletes.push(aOnComplete); | |
if (typeof aOnFail === "function") | |
promise.onFails.push(aOnFail); | |
return promise.fire(this); | |
}, | |
get isResolved () { return promiseMap.get(this).status === true; }, | |
get isRejected () { return promiseMap.get(this).status === false; }, | |
done: function Promise_done (...aCallbacks) { | |
return promiseMap.get(this).setCallbacks(true, aCallbacks, this); | |
}, | |
fail: function Promise_fail (...aCallbacks) { | |
return promiseMap.get(this).setCallbacks(false, aCallbacks, this); | |
}, | |
resolve: function Promise_resolve (...args) { | |
promiseMap.get(this).setStatus(true, args, this); | |
return this; | |
}, | |
reject: function Promise_reject (...args) { | |
promiseMap.get(this).setStatus(false, args, this); | |
return this; | |
}, | |
}); | |
Promise.when = function Promise_when (...aArgs) { | |
var promiseManager = Promise(); | |
var promises = []; | |
for (var p of aArgs) { | |
if (!(p instanceof Promise)) { | |
p = new Promise(); | |
p.resolve(); | |
} | |
promises.push(p); | |
p.then( | |
function onResolve () { | |
if (promises.every(function(p){ return p.isResolved; })) | |
promiseManager.resolve.apply(promiseManager, aArgs); | |
}, | |
function onReject () { | |
promiseManager.reject.apply(promiseManager, aArgs); | |
} | |
); | |
} | |
return promiseManager; | |
}; | |
exports.Promise = Promise; | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment