1枚のDEEP DIVEサマリー(タイマー)
40441 ワード
タイマ
コールスケジューリング
関数を明示的に呼び出すと、関数はすぐに実行されます.function add(a, b) {
return a + b;
}
console.log(add(2, 5)) >>> 7;
関数を明示的に呼び出さず、所定の関数呼び出しが一定時間後に呼び出される場合は、タイマ関数が使用されます.これをコールスケジューリング(scheduling a call)と呼ぶ.
javascript
①タイマーを生成できるタイマー関数settimeout/setInterval
②タイマーのタイマー関数を削除できるclearTimeout/clearInterval
提供する
タイマ関数はECMAScript仕様で定義されたビルダーではありません.ブラウザ環境とノード.js環境では、タイマ関数をグローバルオブジェクトとして使用する方法が提供されています.すなわち、タイマ関数はホストオブジェクトである.
settimeout関数で生成されたタイマは1回のみ実行され、setInterval関数で生成されたタイマは繰り返し操作されます.
JavaScriptエンジンには実行コンテキストスタックが1つしかないため、2つ以上のタスクを同時に実行することはできません.つまり、JavaScriptエンジンは単一スレッドで動作します.したがって、タイマ関数は非同期処理で動作する.
タイマ関数
setTimeout / clearTimeout
const timeoutdId = setTimeout(func|code[, delay, param1, param2, ...]);
パラメータはfuncタイマが期限切れになった後、呼び出したコールバック関数のコールバック関数ではなく、コードを文字列として渡すことができることを示します.この場合、コード文字列はタイマが期限切れになった後に解釈および実行されます.遅延タイマの有効期限(ミリ秒単位)は、settimeout関数によって、遅延時間のみで動作するタイマを生成します.パラメータ伝達が省略されている場合は、デフォルト値0を指定します.param1, param2, ...呼び出しスケジューリングコールバック関数に渡す必要があるパラメータがある場合は、3番目の後続パラメータに渡すことができます.// 1초(1000ms) 후 타이머가 만료되면 콜백 함수가 호출된다.
setTimeout(() => console.log("Hi!"), 1000);
// 세 번째 인수로 문자열 'Lee' 전달
setTimeout((name) => console.log(`Hi! ${name}.`), 1000, "Lee");
// 두 번째 인수(delay)를 생략하면 기본값 0이 지정된다.
setTimeout(() => console.log("Hello!"));
settimeout関数は、生成されたタイマの一意の識別を識別できる一意の識別を返します.settimeout関数が返すタイマidは
①ブラウザ環境では数値です.
② Node.js環境でのオブジェクト
settimeout関数から返されるタイマidをcleartimeout関数のパラメータに渡すことで、タイマをキャンセルできます.const timerId = setTimeout(() => console.log("Hi!"), 1000);
console.log(timeId);
clearTimeout(timerId);
ブラウザで表示
setInterval/ clearInterval
setInterval関数は、2番目の引数が伝達される時間(ミリ秒、1/1000秒)で動作を繰り返すタイマを生成します.
setIntervalの最初のパラメータコールバック関数は、2番目のパラメータが伝達された時間内に呼び出しを繰り返すようにスケジューリングされる.const timeoutdId = setInterval(func|code[, delay, param1, param2, ...]);
setInterval関数は、生成されたタイマを識別できる一意のタイマidを返す.Node.js環境の場合、オブジェクトが返されます.let count = 1;
const timeoutId = setInterval(() => {
console.log(count); // 1 2 3 4 5
if (count++ === 5) clearInterval(timeoutId);
}, 1000);
console.log("timeoutId: ", timeoutId);
Node.js環境での表示
後退と制限
スクロール、resize、mousemoveなどのイベントが短時間間隔で連続して発生します.これらのイベントにバインドされたイベントハンドラが過度に呼び出され、パフォーマンスに問題が発生する可能性があります.ジッタおよび制限は、短時間間隔で連続的に発生するイベントをグループ化することによって、イベントハンドラの過度な呼び出しを防止するプログラミング技術である.<!DOCTYPE html>
<html>
<body>
<button>click me</button>
<pre>일반 클릭 이벤트 카운터 <span class="normal-msg">0</span></pre>
<pre>디바운스 클릭 이벤트 카운터 <span class="debounce-msg">0</span></pre>
<pre>스로틀 클릭 이벤트 카운터 <span class="throttle-msg">0</span></pre>
<script>
const $button = document.querySelector("button");
const $normalMsg = document.querySelector(".normal-msg");
const $debounceMsg = document.querySelector(".debounce-msg");
const $throttleMsg = document.querySelector(".throttle-msg");
const debounce = (callback, delay) => {
let timerId;
return (event) => {
if (timerId) clearTimeout(timerId);
timerId = setTimeout(callback, delay, event);
};
};
const throttle = (callback, delay) => {
let timerId;
return (event) => {
if (timerId) return;
timerId = setTimeout(
() => {
callback(event);
timerId = null;
},
delay,
event
);
};
};
$button.addEventListener("click", () => {
$normalMsg.textContent = +$normalMsg.textContent + 1;
});
$button.addEventListener(
"click",
debounce(() => {
$debounceMsg.textContent = +$debounceMsg.textContent + 1;
}, 500)
);
$button.addEventListener(
"click",
throttle(() => {
$throttleMsg.textContent = +$throttleMsg.textContent + 1;
}, 500)
);
</script>
</body>
</html>
返品
イベントが短時間間隔で連続して発生すると、disbounceはイベントハンドラを呼び出さず、一定時間後にイベントハンドラを1回だけ呼び出す.
すなわち、コールバックは、イベントハンドラが最後に1回だけ呼び出されるように、短時間間隔で発生したイベントをグループ化することができる.
コード時計のYouTube講座
function add(a, b) {
return a + b;
}
console.log(add(2, 5)) >>> 7;
const timeoutdId = setTimeout(func|code[, delay, param1, param2, ...]);
// 1초(1000ms) 후 타이머가 만료되면 콜백 함수가 호출된다.
setTimeout(() => console.log("Hi!"), 1000);
// 세 번째 인수로 문자열 'Lee' 전달
setTimeout((name) => console.log(`Hi! ${name}.`), 1000, "Lee");
// 두 번째 인수(delay)를 생략하면 기본값 0이 지정된다.
setTimeout(() => console.log("Hello!"));
const timerId = setTimeout(() => console.log("Hi!"), 1000);
console.log(timeId);
clearTimeout(timerId);
const timeoutdId = setInterval(func|code[, delay, param1, param2, ...]);
let count = 1;
const timeoutId = setInterval(() => {
console.log(count); // 1 2 3 4 5
if (count++ === 5) clearInterval(timeoutId);
}, 1000);
console.log("timeoutId: ", timeoutId);
<!DOCTYPE html>
<html>
<body>
<button>click me</button>
<pre>일반 클릭 이벤트 카운터 <span class="normal-msg">0</span></pre>
<pre>디바운스 클릭 이벤트 카운터 <span class="debounce-msg">0</span></pre>
<pre>스로틀 클릭 이벤트 카운터 <span class="throttle-msg">0</span></pre>
<script>
const $button = document.querySelector("button");
const $normalMsg = document.querySelector(".normal-msg");
const $debounceMsg = document.querySelector(".debounce-msg");
const $throttleMsg = document.querySelector(".throttle-msg");
const debounce = (callback, delay) => {
let timerId;
return (event) => {
if (timerId) clearTimeout(timerId);
timerId = setTimeout(callback, delay, event);
};
};
const throttle = (callback, delay) => {
let timerId;
return (event) => {
if (timerId) return;
timerId = setTimeout(
() => {
callback(event);
timerId = null;
},
delay,
event
);
};
};
$button.addEventListener("click", () => {
$normalMsg.textContent = +$normalMsg.textContent + 1;
});
$button.addEventListener(
"click",
debounce(() => {
$debounceMsg.textContent = +$debounceMsg.textContent + 1;
}, 500)
);
$button.addEventListener(
"click",
throttle(() => {
$throttleMsg.textContent = +$throttleMsg.textContent + 1;
}, 500)
);
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<body>
<input type="text" />
<div class="msg"></div>
<script>
const $input = document.querySelector("input");
const $msg = document.querySelector(".msg");
const debounce = (callback, delay) => {
let timerId;
// debounce 함수는 timerId를 기억하는 클로저를 반환한다.
return (event) => {
// delay가 경과하기 이전에 이벤트가 발생하면 이전 타이머를 취소하고
// 새로운 타이머를 재설정한다.
// 따라서 delay보다 짧은 간격으로 이벤트가 발생하면 callback은 호출되지 않는다.
if (timerId) clearTimeout(timerId);
timerId = setTimeout(callback, delay, event);
};
};
// debounce 함수가 반환하는 클로저가 이벤트 핸들러로 등록된다.
// 300ms보다 짧은 간격으로 input 이벤트가 발생하면 debounce 함수의 콜백 함수는
// 호출되지 않다가 300ms 동안 input 이벤트가 더 이상 발생하면 한 번만 호출된다.
$input.oninput = debounce((e) => {
$msg.textContent = e.target.value;
}, 300);
</script>
</body>
</html>
検索ウィンドウでクリックイベント(e.target.value)ごとにajaxリクエストを送信するよりも、デバッガによって最後のイベントにajaxリクエストを送信する方が、サーバ負荷を効果的に軽減できます.
スロットルバルブ
Throttleは、イベントが短時間間隔で連続的に発生しても、イベントハンドラが一定時間間隔で最大1回呼び出すことを可能にする.
短い間隔で連続的に発生するイベントのグループ化を制限し、イベントハンドラを一定時間呼び出すための呼び出しサイクルを作成します.
コード時計のYouTube講座
<!DOCTYPE html>
<html>
<head>
<style>
.container {
width: 300px;
height: 300px;
background-color: rebeccapurple;
overflow: scroll;
}
.content {
width: 300px;
height: 1000vh;
}
</style>
</head>
<body>
<div class="container">
<div class="content"></div>
</div>
<div>
일반 이벤트 핸들러가 scroll 이벤트를 처리한 횟수:
<span class="normal-count">0</span>
</div>
<div>
스로틀 이벤트 핸들러가 scroll 이벤트를 처리한 횟수:
<span class="throttle-count">0</span>
</div>
<script>
const $container = document.querySelector(".container");
const $normalCount = document.querySelector(".normal-count");
const $throttleCount = document.querySelector(".throttle-count");
const throttle = (callback, delay) => {
let timerId;
// throttle 함수는 timerId를 기억하는 클로저를 반환한다.
return (event) => {
// delay가 경과하기 이전에 이벤트가 발생하면 아무것도 하지 않다가
// delay가 경과했을 때 이벤트가 발생하면 새로운 타이머를 재설정한다.
// 따라서 delay 간격으로 callback이 호출된다.
if (timerId) return;
timerId = setTimeout(
() => {
callback(event);
timerId = null;
},
delay,
event
);
};
};
let normalCount = 0;
$container.addEventListener("scroll", () => {
$normalCount.textContent = ++normalCount;
});
let throttleCount = 0;
// throttle 함수가 반환하는 클로저가 이벤트 핸들러로 등록된다.
$container.addEventListener(
"scroll",
throttle(() => {
$throttleCount.textContent = ++throttleCount;
}, 1000)
);
</script>
</body>
</html>
Lodash
Lodash公式文書
例によってthrottやdebonseに関するコードを直接宣言して呼び出すが、lodashなどでより安全なコードを提供することができる.
リファレンス
コード時計のYouTube講座
このゲーム例は、YouTubeリンクを介して直接実施することができる.
Reference
この問題について(1枚のDEEP DIVEサマリー(タイマー)), 我々は、より多くの情報をここで見つけました https://velog.io/@junh0328/DEEP-DIVE-한-장-요약-타이머テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol