ÐоÑÑк Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ JavaScript в бÑаÑзеÑÑ, Ñак Ñамо Ñк Ñ Ð² Node.js, базÑÑÑÑÑÑ Ð½Ð° ÑÐ¸ÐºÐ»Ñ Ð¿Ð¾Ð´Ñй (event loop).
РозÑмÑÐ½Ð½Ñ Ð¿ÑинÑÐ¸Ð¿Ñ ÑобоÑи ÑÐ¸ÐºÐ»Ñ Ð¿Ð¾Ð´Ñй важливе Ð´Ð»Ñ Ð¾Ð¿ÑимÑзаÑÑÑ, Ñа ÑÐ½Ð¾Ð´Ñ Ð´Ð»Ñ Ð¿ÑавилÑÐ½Ð¾Ñ Ð°ÑÑ ÑÑекÑÑÑи.
Ð ÑÑÐ¾Ð¼Ñ ÑоздÑÐ»Ñ Ð¼Ð¸ ÑпоÑаÑÐºÑ ÑозглÑнемо ÑеоÑеÑиÑÐ½Ñ Ð±Ð°Ð·Ñ, а поÑÑм пÑакÑиÑне заÑÑоÑÑÐ²Ð°Ð½Ð½Ñ ÑÐ¸Ñ Ð·Ð½Ð°Ð½Ñ.
Цикл подÑй (event loop)
ÐонÑепÑÑÑ ÑÐ¸ÐºÐ»Ñ Ð¿Ð¾Ð´Ñй дÑже пÑоÑÑа. ÐÑнÑÑ Ð½ÐµÑкÑнÑенний Ñикл, в ÑÐºÐ¾Ð¼Ñ ÑÑÑÑй JavaScript оÑÑкÑÑ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ, виконÑÑ ÑÑ , а поÑÑм пеÑÐµÑ Ð¾Ð´Ð¸ÑÑ Ð² Ñежим оÑÑкÑÐ²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¸Ñ Ð·Ð°Ð²Ð´Ð°Ð½Ñ.
ÐагалÑний алгоÑиÑм ÑÑÑÑÑ:
- Ðоки Ñ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ:
- виконаÑи ÑÑ , поÑинаÑÑи з найÑÑаÑÑÑого.
- ÐÑÑкÑваÑи поки Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð½Ðµ зâÑвиÑÑÑÑ, поÑÑм пеÑейÑи до пÑнкÑÑ 1.
Це ÑоÑмалÑзаÑÑÑ Ñого, Ñо ми баÑимо, гоÑÑаÑÑи вебÑÑоÑÑнкÑ. Ð ÑÑÑй JavaScript бÑлÑÑÑÑÑÑ ÑаÑÑ Ð½Ðµ ÑобиÑÑ Ð½ÑÑого, вÑн пÑаÑÑÑ Ð»Ð¸Ñе коли ÑпÑаÑÑовÑÑ ÑкÑипÑ, обÑобник подÑй Ñи подÑÑ.
ÐÑиклади завданÑ:
- Ðоли заванÑажÑÑÑÑÑÑ Ð·Ð¾Ð²Ð½ÑÑнÑй ÑкÑипÑ
<script src="...">, ÑÐ¾Ð´Ñ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð¿Ð¾Ð»ÑÐ³Ð°Ñ Ð² Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ ÑÑого ÑкÑипÑа. - Ðоли коÑиÑÑÑÐ²Ð°Ñ ÑÑÑ
Ð°Ñ Ð¼Ð¸ÑкоÑ, ÑÐ¾Ð´Ñ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð·Ð³ÐµÐ½ÐµÑÑваÑи подÑÑ
mousemoveÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñи ÑÑ Ð¾Ð±Ñобники. - Ðоли пÑойде ÑаÑ, запÑогÑамований в
setTimeout, ÑÐ¾Ð´Ñ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð·Ð°Ð¿ÑÑÑиÑи його колбек. - â¦Ñ Ñак далÑ.
ÐâÑвлÑÑÑÑÑÑ Ð·Ð°Ð´Ð°ÑÑ Ð´Ð»Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ â ÑÑÑÑй виконÑÑ ÑÑ â поÑÑм оÑÑкÑÑ Ð½Ð¾Ð²Ð¸Ñ Ð·Ð°Ð²Ð´Ð°Ð½Ñ (майже не наванÑажÑÑÑи пÑоÑеÑÐ¾Ñ Ð² ÑÐµÐ¶Ð¸Ð¼Ñ Ð¾ÑÑкÑваннÑ).
Ðоже ÑÑапиÑиÑÑ Ñак, Ñо Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð¿ÑÐ¸Ñ Ð¾Ð´Ð¸ÑÑ ÑодÑ, коли ÑÑÑÑй вже зайнÑÑий, ÑÐ¾Ð´Ñ Ñе Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ ÑÑÐ°Ñ Ð² ÑеÑгÑ.
ЧеÑÐ³Ñ Ð· ÑÐ°ÐºÐ¸Ñ Ð·Ð°Ð²Ð´Ð°Ð½Ñ Ð½Ð°Ð·Ð¸Ð²Ð°ÑÑÑ âÑеÑÐ³Ð¾Ñ Ð¼Ð°ÐºÑозавданÑâ (âmacrotask queueâ, ÑеÑмÑн v8):
ÐапÑиклад, поки ÑÑÑÑй виконÑÑ script, коÑиÑÑÑÐ²Ð°Ñ Ð¼Ð¾Ð¶Ðµ поÑÑÑ
аÑи миÑкоÑ, Ñо ÑпÑиÑиниÑÑ Ð¿Ð¾ÑÐ²Ñ Ð¿Ð¾Ð´ÑÑ mousemove, Ñа може вийÑи ÑаÑ, запÑогÑамований в setTimeout Ñ Ñак далÑ. Ð¦Ñ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ ÑÑоÑмÑÑÑÑ ÑеÑгÑ, Ñк показано на ÑÑ
ÐµÐ¼Ñ Ð²Ð¸Ñе.
ÐадаÑÑ Ð· ÑеÑги виконÑÑÑÑÑÑ Ð·Ð° пÑавилом âпеÑÑий пÑийÑов â пеÑÑий пÑÑовâ. Ðоли ÑÑÑÑй бÑаÑзеÑа закÑнÑиÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ script, вÑн обÑобиÑÑ Ð¿Ð¾Ð´ÑÑ mousemove, поÑÑм Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ Ð¾Ð±Ñобник setTimeout ÑоÑо.
ÐÐ¾Ð²Ð¾Ð»Ñ Ð¿ÑоÑÑо наÑазÑ, Ñи не Ñак?
Ще декÑлÑка деÑалей:
- РендеÑинг нÑколи не вÑдбÑваÑÑÑÑÑ Ð¿Ð¾ÐºÐ¸ ÑÑÑÑй виконÑÑ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ. Ðе Ð¼Ð°Ñ Ð·Ð½Ð°ÑÐµÐ½Ð½Ñ Ð½Ð°ÑкÑлÑки довго виконÑÑÑÑÑÑ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ. ÐмÑни в DOM бÑдÑÑÑ Ð²ÑдмалÑÐ¾Ð²Ð°Ð½Ñ Ð»Ð¸Ñе пÑÑÐ»Ñ Ð·Ð°Ð²ÐµÑÑÐµÐ½Ð½Ñ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ.
- ЯкÑо Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð·Ð°Ð¹Ð¼Ð°Ñ Ð½Ð°Ð´Ñо багаÑо ÑаÑÑ, бÑаÑÐ·ÐµÑ Ð½Ðµ зможе виконÑваÑи ÑнÑÑ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ, напÑиклад, обÑоблÑÑи коÑиÑÑÑваÑÑÐºÑ Ð¿Ð¾Ð´ÑÑ. Тож пÑÑÐ»Ñ Ð½ÐµÐ´Ð¾Ð²Ð³Ð¾Ð³Ð¾ ÑаÑÑ âзавиÑаннÑâ зâÑвиÑÑÑÑ Ð¾Ð¿Ð¾Ð²ÑÑÐµÐ½Ð½Ñ âСÑоÑÑнка не вÑдповÑдаÑâ Ñ Ð¿ÑопозиÑÑÑ Ð²Ð±Ð¸Ñи пÑоÑÐµÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ñазом з ÑÑÐ»Ð¾Ñ ÑÑоÑÑнкоÑ. Таке ÑÑаплÑÑÑÑÑÑ ÐºÐ¾Ð»Ð¸ код мÑÑÑиÑÑ Ð±Ð°Ð³Ð°Ñо ÑÐºÐ»Ð°Ð´Ð½Ð¸Ñ Ð¾Ð±ÑÐ°Ñ ÑнкÑв або Ð²Ð¸Ð½Ð¸ÐºÐ°Ñ Ð¿ÑогÑамна помилка, Ñо ÑÑвоÑÑÑ Ð½ÐµÑкÑнÑенний Ñикл.
Що ж, Ñе бÑла ÑеоÑÑÑ. Ð¢ÐµÐ¿ÐµÑ Ð¿Ð¾Ð±Ð°Ñимо Ñк можна викоÑиÑÑаÑи ÑÑ Ð·Ð½Ð°Ð½Ð½Ñ Ð½Ð° пÑакÑиÑÑ.
ÐÑиклад 1: ÑозбиÑÑÑ ÑеÑÑÑÑозаÑÑаÑÐ½Ð¸Ñ Ð·Ð°Ð²Ð´Ð°Ð½Ñ
ÐÑипÑÑÑимо Ñ Ð½Ð°Ñ Ñ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ, Ñо поÑÑебÑÑ Ð·Ð½Ð°ÑÐ½Ð¸Ñ ÑеÑÑÑÑÑв пÑоÑеÑоÑа.
ÐапÑиклад, пÑдÑвÑÑÑÐ²Ð°Ð½Ð½Ñ ÑинÑакÑиÑÑ (викоÑиÑÑовÑÑÑÑÑÑ Ð´Ð»Ñ Ð²Ð¸Ð´ÑÐ»ÐµÐ½Ð½Ñ ÐºÐ¾Ð»ÑоÑом ÐºÐ¾Ð´Ñ Ð½Ð° ÑÑй ÑÑоÑÑнÑÑ) Ð´Ð¾Ð²Ð¾Ð»Ñ Ð²Ð°Ð¶ÐºÐµ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð¿ÑоÑеÑоÑа. Щоб ÑозмалÑваÑи код, пÑоÑеÑÐ¾Ñ Ð¹Ð¾Ð³Ð¾ аналÑзÑÑ, ÑÑвоÑÑÑ Ð±Ð°Ð³Ð°Ñо колÑоÑÐ¾Ð²Ð¸Ñ ÐµÐ»ÐµÐ¼ÐµÐ½ÑÑв, Ð´Ð¾Ð´Ð°Ñ ÑÑ Ð² докÑÐ¼ÐµÐ½Ñ â Ð´Ð»Ñ Ð²ÐµÐ»Ð¸ÐºÐ¸Ñ Ð¾Ð±âÑмÑв ÑекÑÑÑ Ñе Ð·Ð°Ð¹Ð¼Ð°Ñ Ð±Ð°Ð³Ð°Ñо ÑаÑÑ.
Ðоки ÑÑÑÑй зайнÑÑий пÑдÑвÑÑÑваннÑм ÑинÑакÑиÑÑ Ð²Ñн не може виконÑваÑи ÑнÑÑ ÑеÑÑ, повâÑÐ·Ð°Ð½Ñ Ð· DOM, обÑоблÑÑи коÑиÑÑÑваÑÑÐºÑ Ð¿Ð¾Ð´ÑÑ ÑоÑо. Це може ÑпÑиÑиниÑи âзавиÑаннÑâ бÑаÑзеÑа, Ñо Ñ Ð½ÐµÐ¿ÑийнÑÑним.
Ðи можемо ÑникнÑÑи пÑоблем ÑлÑÑ
ом ÑÐ¾Ð·Ð±Ð¸Ð²Ð°Ð½Ð½Ñ Ð²ÐµÐ»Ð¸ÐºÐ¾Ð³Ð¾ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð½Ð° ÑмаÑоÑки. ÐÑдÑвÑÑиÑи пеÑÑÑ 100 ÑÑдкÑв, поÑÑм поÑÑавиÑи setTimeout (з нÑлÑÐ¾Ð²Ð¾Ñ Ð·Ð°ÑÑимкоÑ) Ð´Ð»Ñ Ð½Ð°ÑÑÑпниÑ
100 ÑÑдкÑв Ñ Ñак далÑ.
Щоб пÑодемонÑÑÑÑваÑи Ñакий пÑдÑ
Ñд, замÑÑÑÑ Ð¿ÑдÑвÑÑÑÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ ÑпÑоÑÐµÐ½Ð½Ñ Ð²ÑзÑмемо ÑÑнкÑÑÑ, Ñка ÑаÑ
ÑÑ Ð²Ñд 1 до 1000000000.
ЯкÑо ви запÑÑÑиÑе код нижÑе, ÑÑÑÑй âзавиÑнеâ на деÑкий ÑаÑ. ÐÐ»Ñ ÑеÑвеÑного JS Ñе бÑде Ñвно видно, а ÑкÑо ви запÑÑкаÑÑе Ñе в бÑаÑзеÑÑ, Ñо ÑпÑобÑйÑе понаÑиÑкаÑи ÑнÑÑ ÐºÐ½Ð¾Ð¿ÐºÐ¸ на ÑÑоÑÑнÑÑ â ви побаÑиÑе, Ñо жодна з подÑй не ÑпÑаÑÑÑ Ð¿Ð¾ÐºÐ¸ Ñей код не завеÑÑиÑÑÑÑ.
let i = 0;
let start = Date.now();
function count() {
// Ñобимо Ð²Ð°Ð¶ÐºÑ ÑобоÑÑ
for (let j = 0; j < 1e9; j++) {
i++;
}
alert("Ðиконано за " + (Date.now() - start) + 'мÑ');
}
count();
ÐÑаÑÐ·ÐµÑ Ð½Ð°Ð²ÑÑÑ Ð¼Ð¾Ð¶Ðµ показаÑи повÑÐ´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ âÑкÑÐ¸Ð¿Ñ Ð²Ð¸ÐºÐ¾Ð½ÑÑÑÑÑÑ Ð½Ð°Ð´Ñо довгоâ.
ÐавайÑе ÑозÑбâÑмо ÑобоÑÑ Ð½Ð° ÑаÑÑини, викоÑиÑÑавÑи Ð²ÐºÐ»Ð°Ð´ÐµÐ½Ñ Ð²Ð¸ÐºÐ»Ð¸ÐºÐ¸ setTimeout:
let i = 0;
let start = Date.now();
function count() {
// Ñобимо ÑаÑÑÐ¸Ð½Ñ Ð²Ð°Ð¶ÐºÐ¾Ñ ÑобоÑи (*)
do {
i++;
} while (i % 1e6 != 0);
if (i == 1e9) {
alert("Done in " + (Date.now() - start) + 'ms');
} else {
setTimeout(count); // планÑÑмо новий виклик (**)
}
}
count();
Ð¢ÐµÐ¿ÐµÑ ÑнÑеÑÑÐµÐ¹Ñ Ð±ÑаÑзеÑа повнÑÑÑÑ ÑобоÑий пÑд ÑÐ°Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð¿ÑоÑеÑÑ âобÑиÑленнÑâ.
ÐÑоÑÑий виклик count ÑобиÑÑ ÑаÑÑÐ¸Ð½Ñ ÑобоÑи (*), Ñ Ð¿Ð¾ÑÑм планÑÑ ÑвÑй же виклик (**), ÑкÑо Ñе необÑ
Ñдно:
- ÐеÑÑе Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð¾Ð±ÑиÑлÑÑ:
i=1...1000000. - ÐÑÑге Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð¾Ð±ÑиÑлÑÑ:
i=1000001..2000000. - â¦Ñ Ñак далÑ.
ТепеÑ, ÑкÑо зâÑвлÑÑÑÑÑÑ Ð½Ð¾Ð²Ðµ ÑÑоÑÐ¾Ð½Ð½Ñ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ (Ñаке Ñк подÑÑ onclick) поки ÑÑÑÑй виконÑÑ ÑаÑÑÐ¸Ð½Ñ 1, воно ÑÑÐ°Ñ Ð² ÑеÑÐ³Ñ Ñ Ð²Ð¸ÐºÐ¾Ð½ÑÑÑÑÑÑ Ð¿ÑÑÐ»Ñ Ð·Ð°ÐºÑнÑÐµÐ½Ð½Ñ ÑаÑÑини 1, пеÑед наÑÑÑÐ¿Ð½Ð¾Ñ ÑаÑÑиноÑ. ÐеÑÑодиÑÐ½Ñ Ð¿Ð¾Ð²ÐµÑÐ½ÐµÐ½Ð½Ñ Ð² Ñикл подÑй мÑж виконаннÑм count даÑÑÑ ÑÑÑÑÑ Ð´Ð¾ÑÑаÑнÑо âпÑоÑÑоÑÑâ, Ñоб зÑобиÑи ÑоÑÑ ÑÑе, вÑдÑеагÑваÑи на дÑÑ ÐºÐ¾ÑиÑÑÑваÑа.
ÐÑимÑÑна ÑÑÑ, Ñо обидва ваÑÑанÑи â з ÑозбиÑÑÑм Ñ Ð±ÐµÐ· ÑозбиÑÑÑ ÑобоÑи з setTimeout â майже не вÑдÑÑзнÑÑÑÑÑÑ Ð·Ð° ÑвидкÑÑÑÑ. ÐÐµÐ¼Ð°Ñ Ð²ÐµÐ»Ð¸ÐºÐ¾Ñ ÑÑзниÑÑ Ð² загалÑÐ½Ð¾Ð¼Ñ ÑаÑÑ Ð¿ÑдÑаÑ
ÑнкÑ.
Щоб зменÑиÑи ÑÑ ÑÑзниÑÑ Ñе ÑилÑнÑÑе, давайÑе внеÑемо покÑаÑеннÑ.
Ðи пеÑенеÑемо планÑÐ²Ð°Ð½Ð½Ñ Ð²Ð¸ÐºÐ»Ð¸ÐºÑ Ð² поÑаÑок count():
let i = 0;
let start = Date.now();
function count() {
// пеÑеноÑимо планÑÐ²Ð°Ð½Ð½Ñ Ð²Ð¸ÐºÐ»Ð¸ÐºÑ Ð² поÑаÑок
if (i < 1e9 - 1e6) {
setTimeout(count); // планÑÑмо новий виклик
}
do {
i++;
} while (i % 1e6 != 0);
if (i == 1e9) {
alert("Ðиконано за " + (Date.now() - start) + 'мÑ');
}
}
count();
Ð¢ÐµÐ¿ÐµÑ ÐºÐ¾Ð»Ð¸ ми викликаÑмо count() Ñ Ð±Ð°Ñимо, Ñо нам поÑÑÑбно викликаÑи count() Ñе, ми планÑÑмо Ñе негайно, Ñе пеÑед Ñим Ñк виконÑваÑи ÑобоÑÑ.
ЯкÑо ви запÑÑÑиÑе Ñе, Ñо легко заÑважиÑе, Ñо Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð·Ð°Ð¹Ð¼Ð°Ñ Ð·Ð½Ð°Ñно менÑе ÑаÑÑ.
ЧомÑ?
ÐÑе пÑоÑÑо: Ñк ви знаÑÑе, в бÑаÑзеÑа Ñ Ð¼ÑнÑмалÑна заÑÑимка в 4Ð¼Ñ Ð¿Ñи багаÑÑоÑ
вкладениÑ
викликаÑ
setTimeout. ÐавÑÑÑ ÑкÑо ми вÑÑановимо 0, наÑпÑÐ°Ð²Ð´Ñ Ñе бÑде 4ms (або ÑÑоÑ
и бÑлÑÑе). Тож Ñим ÑанÑÑе ми запланÑÑмо виклик â Ñим ÑвидÑе виконаÑÑÑÑÑ ÐºÐ¾Ð´.
ÐÑож, ми Ñозбили ÑеÑÑÑÑозаÑÑаÑне Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð½Ð° ÑаÑÑини â ÑÐµÐ¿ÐµÑ Ð²Ð¾Ð½Ð¾ не бÑде блокÑваÑи коÑиÑÑÑваÑÑкий ÑнÑеÑÑейÑ. РзагалÑний ÑÐ°Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð¿ÑакÑиÑно не збÑлÑÑиÑÑÑÑ.
ÐÑиклад 2: ÑндикаÑÑÑ Ð¿ÑогÑеÑÑ
ÐнÑÐ¾Ñ Ð¿ÐµÑÐµÐ²Ð°Ð³Ð¾Ñ ÑозбиÑÑÑ Ð²ÐµÐ»Ð¸ÐºÐ¸Ñ Ð·Ð°Ð²Ð´Ð°Ð½Ñ Ð½Ð° ÑаÑÑини Ñ Ð¼Ð¾Ð¶Ð»Ð¸Ð²ÑÑÑÑ Ð¿Ð¾ÐºÐ°Ð·ÑваÑи ÑндикаÑÐ¾Ñ Ð¿ÑогÑеÑÑ.
Як зазнаÑено ÑанÑÑе, змÑни в DOM вÑдмалÑовÑÑÑÑÑÑ Ð»Ð¸Ñе пÑÑÐ»Ñ Ð·Ð°Ð²ÐµÑÑÐµÐ½Ð½Ñ Ð¿Ð¾ÑоÑного завданнÑ, не важливо Ñк довго воно виконÑÑÑÑÑÑ.
Родного бокÑ, Ñе ÑÑдово, ÑÐ¾Ð¼Ñ Ñо наÑа ÑÑнкÑÑÑ Ð¼Ð¾Ð¶Ðµ ÑÑвоÑиÑи багаÑо елеменÑÑв, додаÑи ÑÑ Ð¾Ð´Ð¸Ð½ за одним в докÑÐ¼ÐµÐ½Ñ Ñ Ð·Ð¼ÑниÑи ÑÑ ÑÑÐ¸Ð»Ñ â коÑиÑÑÑÐ²Ð°Ñ Ð½Ðµ побаÑиÑÑ Ð¶Ð¾Ð´Ð½Ð¾Ð³Ð¾ âнедоÑобленогоâ, незакÑнÑеного ÑÑанÑ. Це важливо, Ñи не Ñак?
РозглÑнемо пÑиклад, в ÑÐºÐ¾Ð¼Ñ Ð·Ð¼Ñни i не бÑде видно поки ÑÑнкÑÑÑ Ð½Ðµ завеÑÑиÑÑÑÑ, Ñож ми побаÑимо лиÑе оÑÑÐ°Ð½Ð½Ñ Ð·Ð½Ð°ÑеннÑ:
<div id="progress"></div>
<script>
function count() {
for (let i = 0; i < 1e6; i++) {
i++;
progress.innerHTML = i;
}
}
count();
</script>
â¦Ðле можливо ми Ñ Ð¾Ñемо показаÑи ÑоÑÑ Ð¿Ñд ÑÐ°Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ, напÑиклад ÑндикаÑÐ¾Ñ Ð¿ÑогÑеÑÑ.
ЯкÑо ми ÑоздÑлимо велике Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð½Ð° ÑаÑÑини викоÑиÑÑовÑÑÑи setTimeout, ÑÐ¾Ð´Ñ Ð·Ð¼Ñни бÑдÑÑÑ Ð²ÑдмалÑÐ¾Ð²Ð°Ð½Ñ Ð² пÑомÑжкаÑ
мÑж ÑаÑÑинами.
Це вже виглÑÐ´Ð°Ñ ÐºÑаÑе:
<div id="progress"></div>
<script>
let i = 0;
function count() {
// зÑобиÑи ÑмаÑоÑок Ð²Ð°Ð¶ÐºÐ¾Ñ ÑобоÑи (*)
do {
i++;
progress.innerHTML = i;
} while (i % 1e3 != 0);
if (i < 1e7) {
setTimeout(count);
}
}
count();
</script>
Ð¢ÐµÐ¿ÐµÑ <div> показÑÑ i, Ñке поÑÑÑпово збÑлÑÑÑÑÑÑÑÑ, ÑоÑÑ ÑÑ
оже на ÑндикаÑÐ¾Ñ Ð¿ÑогÑеÑÑ.
ÐÑиклад 3: Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ ÑогоÑÑ Ð¿ÑÑÐ»Ñ Ð¿Ð¾Ð´ÑÑ
РобÑÐ¾Ð±Ð½Ð¸ÐºÑ Ð¿Ð¾Ð´Ñй ми можемо виÑÑÑиÑи вÑдклаÑÑи Ð¿ÐµÐ²Ð½Ñ Ð´ÑÑ Ð¿Ð¾ÐºÐ¸ подÑÑ Ð½Ðµ вÑпливе Ñ Ð½Ðµ бÑде обÑоблена на вÑÑÑ
ÑÑвнÑÑ
. Ðи можемо зÑобиÑи Ñе огоÑнÑвÑи код в setTimeout з нÑлÑÐ¾Ð²Ð¾Ñ Ð·Ð°ÑÑимкоÑ.
Ð ÑоздÑÐ»Ñ ÐапÑÑк коÑиÑÑÑваÑÑкиÑ
подÑй ми баÑили пÑиклад: каÑÑомна подÑÑ menu-open генеÑÑÑÑÑÑÑ ÑеÑез setTimeout Ð´Ð»Ñ Ñого, Ñоб виконаÑиÑÑ Ð¿ÑÑÐ»Ñ Ñого Ñк подÑÑ âclickâ бÑде повнÑÑÑÑ Ð¾Ð±Ñоблена.
menu.onclick = function() {
// ...
// ÑÑвоÑÑÑмо каÑÑÐ¾Ð¼Ð½Ñ Ð¿Ð¾Ð´ÑÑ Ð· даними клÑкнÑÑого пÑнкÑÑ Ð¼ÐµÐ½Ñ
let customEvent = new CustomEvent("menu-open", {
bubbles: true
});
// аÑинÑ
Ñонно згенеÑÑваÑи каÑÑÐ¾Ð¼Ð½Ñ Ð¿Ð¾Ð´ÑÑ
setTimeout(() => menu.dispatchEvent(customEvent));
};
ÐакÑÐ¾Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ (Macrotasks) Ñа ÐÑкÑÐ¾Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ (Microtasks)
Разом з макÑозавданнÑми (macrotasks), опиÑаними в ÑÑÐ¾Ð¼Ñ ÑоздÑлÑ, ÑÑнÑÑÑÑ Ð¼ÑкÑÐ¾Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ (microtasks), опиÑÐ°Ð½Ñ Ð² ÑоздÑÐ»Ñ ÐÑкÑозадаÑÑ.
ÐÑкÑÐ¾Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð¿ÑиÑ
одÑÑÑ Ð»Ð¸Ñе з наÑого кодÑ. ÐÑ
зазвиÑай ÑÑвоÑÑÑÑÑ Ð¿ÑомÑÑи: Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð¾Ð±Ñобника .then/catch/finally ÑÑÐ°Ñ Ð¼ÑкÑозавданнÑм. ÐÑкÑÐ¾Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ñакож викоÑиÑÑовÑÑÑÑÑÑ âпÑд капоÑомâ await, Ñак Ñк Ñе ÑоÑма обÑобки пÑомÑÑа.
Також ÑÑнÑÑ ÑпеÑÑалÑна ÑÑнкÑÑÑ queueMicrotask(func), Ñка ÑÑавиÑÑ func в ÑеÑÐ³Ñ Ð¼ÑкÑозавданÑ.
ÐдÑÐ°Ð·Ñ Ð¿ÑÑÐ»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ макÑозавданнÑ, ÑÑÑÑй виконÑÑ Ð²ÑÑ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð· ÑеÑги мÑкÑÐ¾Ð·Ð°Ð²Ð´Ð°Ð½Ñ Ð¿ÐµÑед Ñим Ñк виконаÑи ÑкеÑÑ Ð¼Ð°ÐºÑÐ¾Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ñи ÑендеÑинг Ñи виконаÑи ÑоÑÑ ÑÑе.
ÐапÑиклад, подивÑÑÑÑÑ:
setTimeout(() => alert("timeout"));
Promise.resolve()
.then(() => alert("promise"));
alert("code");
Який ÑÑÑ Ð±Ñде поÑÑдок виконаннÑ?
codeбÑде показано пеÑÑим, ÑÐ¾Ð¼Ñ Ñо Ñе звиÑайний ÑÐ¸Ð½Ñ Ñонний виклик.promiseбÑде показано дÑÑгим, ÑÐ¾Ð¼Ñ Ñо.thenпÑÐ¾Ñ Ð¾Ð´Ð¸ÑÑ ÑеÑез ÑеÑÐ³Ñ Ð¼ÑкÑозадаÑ, Ñ Ð²Ð¸ÐºÐ¾Ð½ÑÑÑÑÑÑ Ð¿ÑÑÐ»Ñ Ð¿Ð¾ÑоÑного ÑÐ¸Ð½Ñ Ñонного кодÑ.timeoutбÑде показано оÑÑаннÑм, ÑÐ¾Ð¼Ñ Ñо Ñе макÑозавданнÑ.
ÐÑлÑÑ Ð´ÐµÑалÑна ÑлÑÑÑÑаÑÑÑ ÑÐ¸ÐºÐ»Ñ Ð¿Ð¾Ð´Ñй виглÑÐ´Ð°Ñ Ñак (поÑÑдок з веÑÑ Ñ Ð´Ð¾ низÑ: ÑпоÑаÑÐºÑ script, поÑÑм мÑкÑозавданнÑ, ÑендеÑинг Ñ Ñак далÑ):
ÐÑÑ Ð¼ÑкÑÐ¾Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð·Ð°Ð²ÐµÑÑÑÑÑÑÑÑ Ð´Ð¾ обÑобки бÑдÑ-ÑÐºÐ¸Ñ Ð¿Ð¾Ð´Ñй Ñи ÑендеÑÐ¸Ð½Ð³Ñ Ñи Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ ÑнÑÐ¸Ñ Ð¼Ð°ÐºÑозавданÑ.
Це важливо, ÑÐ¾Ð¼Ñ Ñо Ñе гаÑанÑÑÑ, Ñо ÑеÑедовиÑе заÑÑоÑÑÐ½ÐºÑ Ð·Ð°Ð»Ð¸ÑаÑÑÑÑÑ Ð½ÐµÐ·Ð¼Ñнним мÑж мÑкÑозадаÑами (не змÑнилиÑÑ ÐºÐ¾Ð¾ÑдинаÑи миÑки, не зâÑвилиÑÑ Ð½Ð¾Ð²Ñ Ð´Ð°Ð½Ñ ÑеÑез меÑÐµÐ¶Ñ ÑоÑо).
ЯкÑо ми Ñ
оÑемо виконаÑи ÑÑнкÑÑÑ Ð°ÑинÑ
Ñонно (пÑÑÐ»Ñ Ð¿Ð¾ÑоÑного кодÑ), але до вÑдобÑÐ°Ð¶ÐµÐ½Ð½Ñ Ð·Ð¼Ñн Ñи обÑобки новиÑ
подÑй, ми можемо запланÑваÑи ÑÑ Ð·Ð° Ð´Ð¾Ð¿Ð¾Ð¼Ð¾Ð³Ð¾Ñ queueMicrotask.
ÐаÑÑÑпний пÑиклад показÑÑ ÑндикаÑÐ¾Ñ Ð¿ÑогÑеÑÑ, ÑÑ
ожий на попеÑеднÑй, але queueMicrotask викоÑиÑÑовÑÑÑÑÑÑ Ð·Ð°Ð¼ÑÑÑÑ setTimeout. ÐаÑважÑе, Ñо вÑдмалÑÐ²Ð°Ð½Ð½Ñ Ð²ÑдбÑваÑÑÑÑÑ Ð»Ð¸Ñе в ÑÐ°Ð¼Ð¾Ð¼Ñ ÐºÑнÑÑ. Так Ñк Ñ Ð· ÑинÑ
Ñонним кодом:
<div id="progress"></div>
<script>
let i = 0;
function count() {
// зÑобиÑи ÑаÑÑÐ¸Ð½Ñ Ð²ÐµÐ»Ð¸ÐºÐ¾Ð³Ð¾ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ (*)
do {
i++;
progress.innerHTML = i;
} while (i % 1e3 != 0);
if (i < 1e6) {
queueMicrotask(count);
}
}
count();
</script>
ÐÑдÑÑмки
ÐÑлÑÑ Ð´ÐµÑалÑний алгоÑиÑм ÑÐ¸ÐºÐ»Ñ Ð¿Ð¾Ð´Ñй (Ñ Ð¾Ñ Ñ ÑпÑоÑений поÑÑвнÑно Ð·Ñ ÑпеÑиÑÑкаÑÑÑÑ):
- ÐбÑаÑи Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñи найÑÑаÑÑÑе Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð· ÑеÑги макÑÐ¾Ð·Ð°Ð²Ð´Ð°Ð½Ñ (напÑиклад, âscriptâ).
- ÐиконаÑи вÑÑ Ð¼ÑкÑозавданнÑ:
- Ðоки ÑеÑга мÑкÑÐ¾Ð·Ð°Ð²Ð´Ð°Ð½Ñ Ð½Ðµ пÑÑÑа:
- ÐбÑаÑи з ÑеÑги Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñи найÑÑаÑÑÑе мÑкÑозавданнÑ.
- Ðоки ÑеÑга мÑкÑÐ¾Ð·Ð°Ð²Ð´Ð°Ð½Ñ Ð½Ðµ пÑÑÑа:
- ÐÑдмалÑваÑи змÑни, ÑкÑо вони Ñ.
- ЯкÑо ÑеÑга макÑÐ¾Ð·Ð°Ð²Ð´Ð°Ð½Ñ Ð¿ÑÑÑа, заÑекаÑи поки макÑÐ¾Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð·âÑвиÑÑÑÑ.
- ÐеÑейÑи до кÑÐ¾ÐºÑ 1.
Щоб додаÑи в ÑеÑÐ³Ñ Ð½Ð¾Ð²Ðµ макÑозавданнÑ:
- ÐикоÑиÑÑайÑе
setTimeout(f)з нÑлÑÐ¾Ð²Ð¾Ñ Ð·Ð°ÑÑимкоÑ.
Цей ÑпоÑÑб можна викоÑиÑÑаÑи Ð´Ð»Ñ ÑозбиÑÑÑ Ð²ÐµÐ»Ð¸ÐºÐ¾Ð³Ð¾ ÑеÑÑÑÑозаÑÑаÑного Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð½Ð° ÑаÑÑини, Ñоб бÑаÑÐ·ÐµÑ Ð¼Ð°Ð² Ð·Ð¼Ð¾Ð³Ñ ÑеагÑваÑи на коÑиÑÑÑваÑÑÐºÑ Ð¿Ð¾Ð´ÑÑ Ñ Ð¿Ð¾ÐºÐ°Ð·ÑваÑи ÑндикаÑÐ¾Ñ Ð¿ÑогÑеÑÑ Ð¼Ñж ними.
Також Ñе викоÑиÑÑовÑÑÑÑÑÑ Ð² обÑÐ¾Ð±Ð½Ð¸ÐºÐ°Ñ Ð¿Ð¾Ð´Ñй, Ñоб вÑдклаÑÑи дÑÑ Ð´Ð¾ моменÑÑ Ð¿Ð¾Ð²Ð½Ð¾Ñ Ð¾Ð±Ñобки подÑÑ (вÑÐ¿Ð»Ð¸Ð²Ð°Ð½Ð½Ñ Ð·Ð°Ð²ÐµÑÑене).
Щоб запланÑваÑи нове мÑкÑозавданнÑ
- ÐикоÑиÑÑайÑе
queueMicrotask(f). - Також обÑобники пÑомÑÑÑв виконÑÑÑÑÑÑ Ð² ÑеÑÐ·Ñ Ð¼ÑкÑозавданÑ.
ÐÐ¾Ð´Ð½Ñ UI або меÑÐµÐ¶ÐµÐ²Ñ Ð¿Ð¾Ð´ÑÑ Ð½Ðµ обÑоблÑÑÑÑÑÑ Ð¼Ñж мÑкÑозавданнÑми: мÑкÑÐ¾Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð²Ð¸ÐºÐ¾Ð½ÑÑÑÑÑÑ Ð½ÐµÐ³Ð°Ð¹Ð½Ð¾ одне за одним.
Ð¢Ð¾Ð¼Ñ queueMicrotask можна викоÑиÑÑаÑи Ð´Ð»Ñ Ð°ÑинÑ
Ñонного Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ ÑÑнÑÑÑ, але в Ð¾Ð´Ð½Ð¾Ð¼Ñ Ð¹ ÑÐ¾Ð¼Ñ Ð¶ ÑÑÐ°Ð½Ñ ÑеÑедовиÑа.
ÐÐ»Ñ Ð´Ð¾Ð²Ð³Ð¸Ñ Ð²Ð°Ð¶ÐºÐ¸Ñ Ð¾Ð±ÑиÑленÑ, ÑÐºÑ Ð½Ðµ Ð¿Ð¾Ð²Ð¸Ð½Ð½Ñ Ð±Ð»Ð¾ÐºÑваÑи Ñикл подÑй, ми можемо викоÑиÑÑаÑи Web Workers.
Це ÑпоÑÑб запÑÑÑиÑи код в ÑнÑомÑ, паÑалелÑÐ½Ð¾Ð¼Ñ Ð¿Ð¾ÑоÑÑ.
Web Workers можÑÑÑ Ð¾Ð±Ð¼ÑнÑваÑиÑÑ Ð¿Ð¾Ð²ÑдомленнÑми з оÑновним пÑоÑеÑом, але вони маÑÑÑ Ð²Ð»Ð°ÑÐ½Ñ Ð·Ð¼ÑÐ½Ð½Ñ Ñ Ð²Ð»Ð°Ñний Ñикл подÑй.
Web Workers не маÑÑÑ Ð´Ð¾ÑÑÑÐ¿Ñ Ð´Ð¾ DOM, Ñож вони коÑиÑÐ½Ñ Ð¿ÐµÑеважно Ð´Ð»Ñ Ð¾Ð±ÑиÑленÑ. Ðони можÑÑÑ Ð²Ð¸ÐºÐ¾ÑиÑÑовÑваÑи декÑлÑка ÑÐ´ÐµÑ Ð¿ÑоÑеÑоÑа одноÑаÑно.
ÐоменÑаÑÑ
<code>, Ð´Ð»Ñ ÐºÑлÑÐºÐ¾Ñ ÑÑдкÑв â обгоÑнÑÑÑ ÑÑ Ñегом<pre>, Ð´Ð»Ñ Ð¿Ð¾Ð½Ð°Ð´ 10 ÑÑдкÑв â викоÑиÑÑовÑйÑе пÑÑоÑниÑÑ (plnkr, jsbin, codepenâ¦)