Closed7
eventをPromiseで扱ってみる
callback
JSを扱っているとcallbackがよく出てくる
document
.getElementById('hoge')
.addEventListener(() => console.log('this is callback'))
のような感じでEventHandlingでよく使う
Promise
Promise オブジェクトは非同期処理の最終的な完了処理 (もしくは失敗) およびその結果の値を表現します。
MDNより
というように非同期処理の結果を表現するための値としてPromiseが使われる
よく使われるのは fetch API とか
fetch('url')
.then(x => x.json())
.then(x => console.log(x))
みたいな
callbackも同様に非同期の文脈で扱われることがある
var oReq = new XMLHttpRequest();
oReq.addEventListener('load', () => {
console.log(this.responseText);
});
oReq.open('GET', 'url');
oReq.send();
みたいな
callbackをPromiseに
Node.jsの標準ライブラリには非同期な処理でcallbackを使うことが多く、それをPromiseにしたくなるときがある
const fs = require('fs')
fs.readFile('/etc/passwd', (err, data) => {
if (err) throw err;
console.log(data);
});
これを
const fs = require('fs')
const readFile = (path) => new Promise((res, rej) => {
fs.readFile(path, (err, data) => {
if (err) {
rej(err);
return;
}
res(data)
})
})
readFile('/etc/passwd')
.then(x => console.log(x))
みたいな感じにしたくなる
async/await
Promiseにしたモチベーションに async/await を使いたいというものがある。
これは、非同期な処理を同期的な書き方でできるもの
promise.then(x => promiseFunc(x)).then(x => console.log(x))
みたいな処理を
const x = await promise
const y = await promiseFunc(x)
console.log(x)
みたいに書ける
本題
Eventも広義には非同期じゃない?ということでPromiseにしてみる
Promiseになったものがこちら
const event = (dom, eventName) => {
const handler = {
listener: null,
emit(e) {
if (this.listener) {
this.listener(e)
}
},
listen(fn) {
this.listener = fn
}
}
dom.addEventListener(eventName, e => handler.emit(e))
return () => new Promise((res, rej) => {
handler.listen(e => res(e))
})
}
実装はとりあえずどうでも良くて使い方
以下の処理をやってみる
- clickしたら透明度を0.5にする
- 1000ms待つ
- 透明度を1にする
css animation使えばいいじゃんとかは言っちゃいけない
比較のために普通に addEventListener
を使って
const b = () => {
const target = document.getElementById('target')
let flag = false
target.addEventListener('click', async () => {
if (flag) {
return
}
target.style.opacity = "0.5"
flag = true
setTimeout(() => {
flag = false
target.style.opacity = "1"
}, 1000)
})
}
b()
今が透明な状態かを示す flag
という変数がいる
次に使ってみたやつ
const sleep = ms => new Promise(res => setTimeout(() => res(), ms))
const a = async () => {
const target = document.getElementById('target1')
const click = event(target, 'click')
while(true) {
await click()
target.style.opacity = "0.5"
await sleep(1000)
target.style.opacity = "1"
}
}
a()
sleep
は n ms
待ってくれるasync関数
while(true) {}
で囲んでるのは何回も(無限に)やって欲しいから
見てわかるように状態がなくなった
感想
言うほど欲しくなかったかも
ゲームとか作るときには便利そう(?)
then
でイベントをつなげるとRxみたいな気持ちになってくる
// 3回クリックしたらなにかする
await click().then(click).then(click)
// なにか
動いてるもの
このスクラップは2020/12/23にクローズされました