Last active
January 3, 2016 18:46
-
-
Save yaegaki/79fefacd303239b79d6b to your computer and use it in GitHub Desktop.
simple promise
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
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