Last active
March 21, 2016 02:28
-
-
Save gaogao-9/a2a1f29d3c5ff201c668 to your computer and use it in GitHub Desktop.
イベントを賢く捌く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
const eventMap = new WeakMap(); | |
const asyncOnSymbol = Symbol("asyncOn"); | |
const asyncOffSymbol = Symbol("asyncOff"); | |
function asyncOn(type, asyncFunc, useCapture){ | |
const undefined = void 0; | |
if(eventMap.has(asyncFunc)) return; | |
return new Promise((resolve, reject)=>{ | |
const _this = this; | |
eventMap.set(asyncFunc, onEventHandler); | |
this.addEventListener(type, onEventHandler, useCapture); | |
function onEventHandler(eve){ | |
let promise; | |
try{ | |
const promiseOrResult = asyncFunc.call(this, eve); | |
// 通常関数だった場合はそのまま処理を終える | |
if(!(promiseOrResult instanceof Promise)){ | |
const result = promiseOrResult; | |
// 値が返って無ければ何もしない(=> イベントを継続する) | |
if(result === undefined) return result; | |
// 値が返っていたら、自分自身のイベント登録を解除する | |
_this[asyncOffSymbol](type, asyncFunc, useCapture); | |
// そして、Promiseを完了させる | |
resolve(result); | |
return; | |
} | |
// Promiseなら後続処理に回す | |
promise = promiseOrResult; | |
} | |
catch(err){ | |
// 何らかの例外が発生した場合、そのイベントの解除を試みる | |
_this[asyncOffSymbol](type, asyncFunc, useCapture); | |
// そして、Promiseを完了させる | |
reject(err); | |
return; | |
} | |
promise | |
.then(result=>{ | |
// 値が返って無ければ何もしない(=> イベントを継続する) | |
if(result === undefined) return; | |
// 値が返っていたら、自分自身のイベント登録を解除する | |
_this[asyncOffSymbol](type, asyncFunc, useCapture); | |
// そして、Promiseを完了させる | |
resolve(result); | |
}) | |
.catch(err=>{ | |
// 何らかの例外が発生した場合、そのイベントの解除を試みる | |
_this[asyncOffSymbol](type, asyncFunc, useCapture); | |
// そして、Promiseを完了させる | |
reject(err); | |
}); | |
} | |
}); | |
} | |
function asyncOff(type, asyncFunc, useCapture){ | |
const onEventHandler = eventMap.get(asyncFunc); | |
if(!onEventHandler) return; | |
eventMap.delete(asyncFunc); | |
this.removeEventListener(type, onEventHandler, useCapture); | |
} | |
Object.defineProperties(EventTarget.prototype, { | |
[asyncOnSymbol]: { | |
value: asyncOn, | |
}, | |
[asyncOffSymbol]: { | |
value: asyncOff, | |
}, | |
}); | |
module.exports = {on: asyncOnSymbol, off: asyncOffSymbol}; |
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
// 使用例 | |
const {on, off} = require("asyncEvent.js"); | |
// 同期処理の実行例 | |
document[on]("click", function(eve){ | |
console.log("同期処理の実行"); | |
}, false).catch(err=>{ | |
// エラーが発生したたらcatchでつなげて取得できる | |
console.error(err.stack); | |
}); | |
// 同期処理の実行例(1回だけ実行されるイベント) | |
document[on]("click", function(eve){ | |
console.log("1回だけ実行される同期処理の実行"); | |
// undefined以外の値を返した段階で、このイベントが自動的に終了する | |
return "sync done"; | |
}, false).then(data=>{ | |
// thenでつなげたものは、イベントが終了した時に返した値になる | |
console.log(data); // "sync done" | |
}).catch(err=>{ | |
// エラーが発生したたらcatchでつなげて取得できる | |
console.error(err.stack); | |
}); | |
// 非同期処理の実行例 | |
document[on]("click", async function(eve){ | |
console.log("非同期処理の実行(1秒待ちます)"); | |
await new Promise(resolve=>setTimeout(resolve, 1000)); | |
console.log("非同期処理の実行(1秒経ちました)"); | |
}, false).catch(err=>{ | |
// エラーが発生したたらcatchでつなげて取得できる | |
console.error(err.stack); | |
}); | |
// 非同期処理の実行例(1回だけ実行されるイベント) | |
document[on]("click", async function asyncOneCallback(eve){ | |
// 非同期が絡む場合、2回発火しないように明示的にイベントを解除する必要がある | |
document[off]("click", asyncOneCallback, false); | |
console.log("1回だけ実行される非同期処理の実行(2秒待ちます)"); | |
await new Promise(resolve=>setTimeout(resolve, 2000)); | |
console.log("1回だけ実行される非同期処理の実行(2秒経ちました"); | |
return "async done"; | |
}, false).then(data=>{ | |
// thenでつなげたものは、イベントが終了した時に返した値になる | |
console.log(data); // "async done" | |
}).catch(err=>{ | |
// エラーが発生したたらcatchでつなげて取得できる | |
console.error(err.stack); | |
}); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment