Skip to content

Instantly share code, notes, and snippets.

@yaegaki
Last active January 3, 2016 18:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yaegaki/79fefacd303239b79d6b to your computer and use it in GitHub Desktop.
Save yaegaki/79fefacd303239b79d6b to your computer and use it in GitHub Desktop.
simple promise
function Promise(callback, immudiate) {
// Promiseとcallbackを関連付ける
this.callback = callback;
// immudiateにfalse以外のものが渡されたとき(引数を一つしか渡さなかった場合も)はすぐにinvokeを呼び出す
if (immudiate !== false) {
this.invoke();
}
}
// Promiseに関連付けられた関数を実行する
// 関数を呼ぶときに引数としてthis.resolveを渡す
Promise.prototype.invoke = function() {
if (this.callback != null) {
// this.callbackに渡す関数が呼び出されると現在のPromiseが完了し
// 次のPromiseがinvokeされる
//
// bindは関数とthisを束縛する
// bindを使用しない場合はresolveの内部で使用しているthisがWindowを示すようになってしまう(場合によるが)
// 参考:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
this.callback(this.resolve.bind(this));
}
};
Promise.prototype.resolve = function() {
this.done = true;
// resolveしたときにすでにthis.doneCalbackが設定されている場合はdoneCallbackを実行する
if (this.doneCallback != null) {
this.doneCallback();
}
};
Promise.prototype.then = function (callback) {
// 次のPromiseを作成
// 第二引数にtrueを渡すことですぐにcallbackが実行されないようにする
// (promise.invokeが呼ばれたときにcallbackが実行されるようにする)
var promise = new Promise(callback, false);
// すでに現在のPromiseが完了している場合は次のpromise.invokeを実行する
if (this.done) {
promise.invoke();
} else {
// そうでない場合は現在のPromiseがresolveしたときに次のpromise.invokeが呼び出されるように設定する
this.doneCallback = promise.invoke.bind(promise);
}
return promise;
};
// 1秒ごとにカウントアップする
new Promise(resolve => {
console.log(1);
setTimeout(resolve, 1000);
}).then(resolve => {
console.log(2);
setTimeout(resolve, 1000);
}).then(resolve => {
console.log(3);
setTimeout(resolve, 1000);
});
// 上記の処理をわかりやすいように変数に代入する
var promise1 = new Promise(resolve1 => {
console.log(1);
setTimeout(resolve1, 1000);
});
var promise2 = promise1.then(resolve2 => {
console.log(2);
setTimeout(resolve2, 1000);
});
var promise3 = promise2.then(resolve3 => {
console.log(3);
setTimeout(resolve3, 1000);
});
/*
## 上記の処理の流れ
promise1を作成する
promise1.invokeがPromiseから呼び出される
promise1に渡した関数がpromise1.invokeから呼び出される
promise1に渡した関数がresolve1を1秒後に呼び出すように設定する
~1秒後~
resolve1がsetTimeoutから呼び出される
promise1.doneCallbackがresolve1から呼び出される
promise2.invokeがpromise1.doneCallbackから呼び出される(実質promise2.invokeとpromise1.doneCallbackは同じ)
promise2に渡した関数がpromise2.invokeから呼び出される
promise2に渡した関数がresolve2を1秒後に呼び出すように設定する
~1秒後~
resolve2がsetTimeoutから呼び出される
promise2.doneCallbackがresolve2から呼び出される
promise3.invokeがpromise2.doneCallbackから呼び出される(実質promise3.invokeとpromise2.doneCallbackは同じ)
promise3に渡した関数がpromise3.invokeから呼び出される
promise3に渡した関数がresolve3を1秒後に呼び出すように設定する
~1秒後~
resolve3がsetTimeoutから呼び出される
promise3に対してthenを呼び出していないのでここで終了する
## 呼ばれた関数のスタックは以下のような感じ
new Promise
-> promise1.invoke
-> promise1に渡した関数
-> setTimeout
setTimeout
-> resolve1
-> promise1.doneCallback
-> promise2.invoke
-> promise2に渡した関数
-> setTimeout
setTimeout
-> resolve2
-> promise2.doneCallback
-> promise3.invoke
-> promise3に渡した関数
-> setTimeout
setTimeout
-> resolve3
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment