Skip to content

Instantly share code, notes, and snippets.

@teramako
Last active December 16, 2015 11:18
Show Gist options
  • Save teramako/5426245 to your computer and use it in GitHub Desktop.
Save teramako/5426245 to your computer and use it in GitHub Desktop.
テキトウに Promise 実装。WeakMap とか for-of とか、その他 ECMAScript 6th 機能を使っているので、一般には使えないけど。
/*
* @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