Skip to content

Instantly share code, notes, and snippets.

@kamataryo
Last active August 25, 2018 06:21
Show Gist options
  • Save kamataryo/797630c0f47f7ce88cedd099d72a1ab8 to your computer and use it in GitHub Desktop.
Save kamataryo/797630c0f47f7ce88cedd099d72a1ab8 to your computer and use it in GitHub Desktop.
Add snippet
/**
* タイムアウト機能を埋め込むプロキシ
* targetが一定時間呼ばれなかったら固有の処理を実行する
* タイムアウトすると、呼ばれた回数のカウンタはリセットされる
* @param {function} target プロキシされる関数
* @param {{timeout: number, callback: function}} opts オプション
* @return {function} プロキシされた関数
*/
const timeoutProxy = (target, opts) => {
/**
* タイムアウトに関する情報を元の関数に埋め込む
* @type {symbol}
*/
const _timeoutTag = Symbol('timeout tag')
return new Proxy(target, {
/**
* apply handler
* @param {function} target ターゲット
* @param {any} thisArg コンテキスト
* @param {array} argumentList 引数
* @return {any} 元の関数の戻り値
*/
apply: (target, thisArg, argumentList) => {
const timeoutParams = target[_timeoutTag]
if (!timeoutParams) {
// 初めて関数が呼ばれた
const timerId = setTimeout(() => {
clearTimeout(timerId)
opts.callback(target[_timeoutTag].count, opts.timeout, target)
target[_timeoutTag] = void 0
}, opts.timeout)
target[_timeoutTag] = {
called: true,
count: 0,
timerId,
}
} else {
// 2回目以降に関数が呼ばれた
const { timerId } = target[_timeoutTag]
clearTimeout(timerId)
target[_timeoutTag].timerId = setTimeout(() => {
clearTimeout(timerId)
const { count } = target[_timeoutTag]
opts.callback(count, opts.timeout, target)
target[_timeoutTag] = void 0
}, opts.timeout)
}
target[_timeoutTag].count++
return target(argumentList)
},
})
}
// サンプルの関数
const sample = () => console.log('hello')
const opts = {
timeout: 1000,
callback: (count, timeout, target) =>
console.log(
`タイムアウト(${timeout}ミリ秒)するまでに ${count} 回 ${
target.name
} が呼ばれました`,
),
}
// プロキシを使って振る舞いを改ざんした新しい関数を作る
const timeoutFunc = timeoutProxy(sample, opts)
timeoutFunc()
timeoutFunc()
timeoutFunc()
timeoutFunc()
setTimeout(timeoutFunc, 500)
setTimeout(timeoutFunc, 3500)
// $ node ./timeout2.js
// hello
// hello
// hello
// hello
// hello
// タイムアウト(1000ミリ秒)するまでに 5 回 sample が呼ばれました
// hello
// タイムアウト(1000ミリ秒)するまでに 1 回 sample が呼ばれました
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment