ÐоÑок вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð² бÑаÑзеÑе, Ñавно как и в Node.js, оÑнован на ÑобÑÑийном Ñикле.
Ðонимание ÑабоÑÑ ÑобÑÑийного Ñикла важно Ð´Ð»Ñ Ð¾Ð¿ÑимизаÑий, иногда Ð´Ð»Ñ Ð¿ÑавилÑной аÑÑ Ð¸ÑекÑÑÑÑ.
Ð ÑÑой главе Ð¼Ñ ÑнаÑала ÑазбеÑÑм ÑеоÑиÑ, а заÑем ÑаÑÑмоÑÑим ÐµÑ Ð¿ÑакÑиÑеÑкое пÑименение.
СобÑÑийнÑй Ñикл
ÐÐ´ÐµÑ ÑобÑÑийного Ñикла оÑÐµÐ½Ñ Ð¿ÑоÑÑа. ÐÑÑÑ Ð±ÐµÑконеÑнÑй Ñикл, в коÑоÑом движок JavaScript Ð¾Ð¶Ð¸Ð´Ð°ÐµÑ Ð·Ð°Ð´Ð°Ñи, иÑполнÑÐµÑ Ð¸Ñ Ð¸ Ñнова Ð¾Ð¶Ð¸Ð´Ð°ÐµÑ Ð¿Ð¾ÑÐ²Ð»ÐµÐ½Ð¸Ñ Ð½Ð¾Ð²ÑÑ .
ÐбÑий алгоÑиÑм движка:
- Ðока еÑÑÑ Ð·Ð°Ð´Ð°Ñи:
- вÑполниÑÑ Ð¸Ñ , наÑÐ¸Ð½Ð°Ñ Ñ Ñамой ÑÑаÑой
- ÐездейÑÑвоваÑÑ Ð´Ð¾ поÑÐ²Ð»ÐµÐ½Ð¸Ñ Ð½Ð¾Ð²Ð¾Ð¹ задаÑи, а заÑем пеÑейÑи к пÑнкÑÑ 1
ÐÑо ÑоÑмализаÑÐ¸Ñ Ñого, ÑÑо Ð¼Ñ Ð½Ð°Ð±Ð»Ñдаем, пÑоÑмаÑÑÐ¸Ð²Ð°Ñ Ð²ÐµÐ±-ÑÑÑаниÑÑ. Ðвижок JavaScript болÑÑÑÑ ÑаÑÑÑ Ð²Ñемени ниÑего не Ð´ÐµÐ»Ð°ÐµÑ Ð¸ ÑабоÑаеÑ, ÑолÑко еÑли ÑÑебÑеÑÑÑ Ð¸ÑполниÑÑ ÑкÑипÑ/обÑабоÑÑик или обÑабоÑаÑÑ ÑобÑÑие.
ÐÑимеÑÑ Ð·Ð°Ð´Ð°Ñ:
- Ðогда загÑÑжаеÑÑÑ Ð²Ð½ÐµÑний ÑкÑипÑ
<script src="...">, Ñо задаÑа â ÑÑо вÑполнение ÑÑого ÑкÑипÑа. - Ðогда полÑзоваÑÐµÐ»Ñ Ð´Ð²Ð¸Ð³Ð°ÐµÑ Ð¼ÑÑÑ, задаÑа â ÑгенеÑиÑоваÑÑ ÑобÑÑие
mousemoveи вÑполниÑÑ ÐµÐ³Ð¾ обÑабоÑÑики. - Ðогда иÑÑеÑÑÑ ÑаймеÑ, ÑÑÑановленнÑй Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ
setTimeout(func, ...), задаÑа â ÑÑо вÑполнение ÑÑнкÑииfunc - Ð Ñак далее.
ÐадаÑи поÑÑÑпаÑÑ Ð½Ð° вÑполнение â движок вÑполнÑÐµÑ Ð¸Ñ â заÑем Ð¾Ð¶Ð¸Ð´Ð°ÐµÑ Ð½Ð¾Ð²Ñе задаÑи (во вÑÐµÐ¼Ñ Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸Ñ Ð¿ÑакÑиÑеÑки не нагÑÑÐ¶Ð°Ñ Ð¿ÑоÑеÑÑÐ¾Ñ ÐºÐ¾Ð¼Ð¿ÑÑÑеÑа)
ÐÐ¾Ð¶ÐµÑ Ñак ÑлÑÑиÑÑÑÑ, ÑÑо задаÑа поÑÑÑпаеÑ, когда движок занÑÑ Ñем-Ñо дÑÑгим, Ñогда она ÑÑавиÑÑÑ Ð² оÑеÑедÑ.
ÐÑеÑедÑ, коÑоÑÑÑ ÑоÑмиÑÑÑÑ Ñакие задаÑи, назÑваÑÑ Â«Ð¾ÑеÑедÑÑ Ð¼Ð°ÐºÑозадаÑ» (macrotask queue, ÑеÑмин V8).
ÐапÑимеÑ, когда движок занÑÑ Ð²Ñполнением ÑкÑипÑа, полÑзоваÑÐµÐ»Ñ Ð¼Ð¾Ð¶ÐµÑ Ð¿ÐµÑедвинÑÑÑ Ð¼ÑÑÑ, Ñем ÑамÑм вÑзвав поÑвление ÑобÑÑÐ¸Ñ mousemove, или Ð¼Ð¾Ð¶ÐµÑ Ð¸ÑÑеÑÑ ÑаймеÑ, ÑÑÑановленнÑй setTimeout, и Ñ.п. ÐÑи задаÑи ÑоÑмиÑÑÑÑ Ð¾ÑеÑедÑ, как показано на иллÑÑÑÑаÑии вÑÑе.
ÐадаÑи из оÑеÑеди иÑполнÑÑÑÑÑ Ð¿Ð¾ пÑÐ°Ð²Ð¸Ð»Ñ Â«Ð¿ÐµÑвÑм пÑиÑÑл â пеÑвÑм ÑÑÑл». Ðогда бÑаÑÐ·ÐµÑ Ð·Ð°ÐºÐ°Ð½ÑÐ¸Ð²Ð°ÐµÑ Ð²Ñполнение ÑкÑипÑа, он обÑабаÑÑÐ²Ð°ÐµÑ ÑобÑÑие 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("Done in " + (Date.now() - start) + 'ms');
}
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("Done in " + (Date.now() - start) + 'ms');
}
}
count();
ТепеÑÑ, когда Ð¼Ñ Ð½Ð°Ñинаем вÑполнÑÑÑ count() и видим, ÑÑо поÑÑебÑеÑÑÑ Ð²ÑполниÑÑ count() еÑÑ Ñаз, Ð¼Ñ Ð¿Ð»Ð°Ð½Ð¸ÑÑем ÑÑÐ¾Ñ Ð²Ñзов немедленно, пеÑед вÑполнением ÑабоÑÑ.
ÐÑли Ð²Ñ Ð·Ð°Ð¿ÑÑÑиÑе ÑÑÐ¾Ñ ÐºÐ¾Ð´, Ñо легко замеÑиÑе, ÑÑо он ÑÑебÑÐµÑ Ð·Ð½Ð°ÑиÑелÑно менÑÑе вÑемени.
ÐоÑемÑ?
ÐÑÑ Ð¿ÑоÑÑо: как Ð²Ñ Ð¿Ð¾Ð¼Ð½Ð¸Ñе, в бÑаÑзеÑе еÑÑÑ Ð¼Ð¸Ð½Ð¸Ð¼Ð°Ð»ÑÐ½Ð°Ñ Ð·Ð°Ð´ÐµÑжка в 4 миллиÑекÑÐ½Ð´Ñ Ð¿Ñи множеÑÑве вложеннÑÑ
вÑзовов setTimeout. Ðаже еÑли Ð¼Ñ ÑказÑваем задеÑÐ¶ÐºÑ 0, на Ñамом деле она бÑÐ´ÐµÑ Ñавна 4 Ð¼Ñ (или ÑÑÑÑ Ð±Ð¾Ð»ÑÑе). ÐоÑÑÐ¾Ð¼Ñ Ñем ÑанÑÑе Ð¼Ñ Ð·Ð°Ð¿Ð»Ð°Ð½Ð¸ÑÑем вÑполнение â Ñем бÑÑÑÑее вÑполниÑÑÑ ÐºÐ¾Ð´.
ÐÑак, Ð¼Ñ Ñазбили ÑеÑÑÑÑоÑмкÑÑ Ð·Ð°Ð´Ð°ÑÑ Ð½Ð° ÑаÑÑи â ÑепеÑÑ Ð¾Ð½Ð° не блокиÑÑÐµÑ Ð¿Ð¾Ð»ÑзоваÑелÑÑкий инÑеÑÑейÑ, пÑиÑÑм поÑÑи без поÑеÑÑ Ð² обÑем вÑемени вÑполнениÑ.
ÐÑÐ¸Ð¼ÐµÑ 2: индикаÑÐ¸Ñ Ð¿ÑогÑеÑÑа
ÐÑÑ Ð¾Ð´Ð½Ð¾ пÑеимÑÑеÑÑво ÑÐ°Ð·Ð´ÐµÐ»ÐµÐ½Ð¸Ñ Ð½Ð° ÑаÑÑи кÑÑпной задаÑи в бÑаÑзеÑнÑÑ ÑкÑипÑÐ°Ñ â ÑÑо возможноÑÑÑ Ð¿Ð¾ÐºÐ°Ð·ÑваÑÑ Ð¸Ð½Ð´Ð¸ÐºÐ°ÑÐ¾Ñ Ð²ÑполнениÑ.
ÐбÑÑно бÑаÑÐ·ÐµÑ Ð¾ÑÑиÑовÑÐ²Ð°ÐµÑ ÑодеÑжимое ÑÑÑаниÑÑ Ð¿Ð¾Ñле Ñого, как заканÑиваеÑÑÑ Ð²Ñполнение ÑекÑÑего кода. Ðе Ð¸Ð¼ÐµÐµÑ Ð·Ð½Ð°ÑениÑ, наÑколÑко долго вÑполнÑеÑÑÑ Ð·Ð°Ð´Ð°Ñа. ÐÐ·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² DOM оÑобÑажаÑÑÑÑ ÑолÑко поÑле ÐµÑ Ð·Ð°Ð²ÐµÑÑениÑ.
С одной ÑÑоÑонÑ, ÑÑо Ñ Ð¾ÑоÑо, поÑÐ¾Ð¼Ñ ÑÑо наÑа ÑÑнкÑÐ¸Ñ Ð¼Ð¾Ð¶ÐµÑ ÑоздаваÑÑ Ð¼Ð½Ð¾Ð³Ð¾ ÑлеменÑов, добавлÑÑÑ Ð¸Ñ Ð¿Ð¾ Ð¾Ð´Ð½Ð¾Ð¼Ñ Ð² докÑÐ¼ÐµÐ½Ñ Ð¸ изменÑÑÑ Ð¸Ñ ÑÑили â полÑзоваÑÐµÐ»Ñ Ð½Ðµ ÑÐ²Ð¸Ð´Ð¸Ñ Â«Ð¿ÑомежÑÑоÑного», незаконÑенного ÑоÑÑоÑниÑ. ÐÑо важно, веÑно?
РпÑимеÑе ниже Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ i не бÑдÑÑ Ð·Ð°Ð¼ÐµÑнÑ, пока ÑÑнкÑÐ¸Ñ Ð½Ðµ завеÑÑиÑÑÑ, поÑÑÐ¾Ð¼Ñ Ð¼Ñ Ñвидим ÑолÑко поÑледнее знаÑение 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));
};
ÐакÑозадаÑи и ÐикÑозадаÑи
Ðомимо макÑозадаÑ, опиÑаннÑÑ Ð² ÑÑой ÑаÑÑи, ÑÑÑеÑÑвÑÑÑ Ð¼Ð¸ÐºÑозадаÑи, ÑпомÑнÑÑÑе в главе ÐикÑозадаÑи.
ÐикÑозадаÑи пÑиÑ
одÑÑ ÑолÑко из кода. ÐбÑÑно они ÑоздаÑÑÑÑ Ð¿ÑомиÑами: вÑполнение обÑабоÑÑика .then/catch/finally ÑÑановиÑÑÑ Ð¼Ð¸ÐºÑозадаÑей. ÐикÑозадаÑи Ñакже иÑполÑзÑÑÑÑÑ Â«Ð¿Ð¾Ð´ капоÑом» await, Ñ.к. ÑÑо ÑоÑма обÑабоÑки пÑомиÑа.
Также еÑÑÑ ÑпеÑиалÑÐ½Ð°Ñ ÑÑнкÑÐ¸Ñ queueMicrotask(func), коÑоÑÐ°Ñ Ð¿Ð¾Ð¼ÐµÑÐ°ÐµÑ func в оÑеÑÐµÐ´Ñ Ð¼Ð¸ÐºÑозадаÑ.
СÑÐ°Ð·Ñ Ð¿Ð¾Ñле каждой макÑозадаÑи движок иÑполнÑÐµÑ Ð²Ñе задаÑи из оÑеÑеди микÑÐ¾Ð·Ð°Ð´Ð°Ñ Ð¿ÐµÑед Ñем, как вÑполниÑÑ ÑледÑÑÑÑÑ Ð¼Ð°ÐºÑозадаÑÑ Ð¸Ð»Ð¸ оÑобÑазиÑÑ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð½Ð° ÑÑÑаниÑе, или ÑделаÑÑ ÑÑо-Ñо еÑÑ.
ÐапÑимеÑ:
setTimeout(() => alert("timeout"));
Promise.resolve()
.then(() => alert("promise"));
alert("code");
Ðакой здеÑÑ Ð±ÑÐ´ÐµÑ Ð¿Ð¾ÑÑдок?
codeпоÑвлÑеÑÑÑ Ð¿ÐµÑвÑм, Ñ.к. ÑÑо обÑÑнÑй ÑÐ¸Ð½Ñ ÑоннÑй вÑзов.promiseпоÑвлÑеÑÑÑ Ð²ÑоÑÑм, поÑÐ¾Ð¼Ñ ÑÑо.thenпÑÐ¾Ñ Ð¾Ð´Ð¸Ñ ÑеÑез оÑеÑÐµÐ´Ñ Ð¼Ð¸ÐºÑÐ¾Ð·Ð°Ð´Ð°Ñ Ð¸ вÑполнÑеÑÑÑ Ð¿Ð¾Ñле ÑекÑÑего ÑÐ¸Ð½Ñ Ñонного кода.timeoutпоÑвлÑеÑÑÑ Ð¿Ð¾Ñледним, поÑÐ¾Ð¼Ñ ÑÑо ÑÑо макÑозадаÑа.
Ðолее подÑобное изобÑажение ÑобÑÑийного Ñикла вÑглÑÐ´Ð¸Ñ Ñак:
ÐÑе микÑозадаÑи завеÑÑаÑÑÑÑ Ð´Ð¾ обÑабоÑки ÐºÐ°ÐºÐ¸Ñ -либо ÑобÑÑий или ÑендеÑинга, или пеÑÐµÑ Ð¾Ð´Ð° к дÑÑгой макÑозадаÑе.
ÐÑо важно, Ñак как гаÑанÑиÑÑеÑ, ÑÑо обÑее окÑÑжение оÑÑаÑÑÑÑ Ð¾Ð´Ð½Ð¸Ð¼ и Ñем же Ð¼ÐµÐ¶Ð´Ñ Ð¼Ð¸ÐºÑозадаÑами â не Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ñ ÐºÐ¾Ð¾ÑдинаÑÑ Ð¼ÑÑи, не полÑÑÐµÐ½Ñ Ð½Ð¾Ð²Ñе даннÑе по ÑеÑи и Ñ.п.
ÐÑли Ð¼Ñ Ñ
оÑим запÑÑÑиÑÑ ÑÑнкÑÐ¸Ñ Ð°ÑинÑ
Ñонно (поÑле ÑекÑÑего кода), но до оÑобÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹ и до новÑÑ
ÑобÑÑий, Ñо можем запланиÑоваÑÑ ÑÑо ÑеÑез 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). - Также обÑабоÑÑики пÑомиÑов вÑполнÑÑÑÑÑ Ð² ÑÐ°Ð¼ÐºÐ°Ñ Ð¾ÑеÑеди микÑозадаÑ.
СобÑÑÐ¸Ñ Ð¿Ð¾Ð»ÑзоваÑелÑÑкого инÑеÑÑейÑа и ÑеÑевÑе ÑобÑÑÐ¸Ñ Ð² пÑомежÑÑÐºÐ°Ñ Ð¼ÐµÐ¶Ð´Ñ Ð¼Ð¸ÐºÑозадаÑами не обÑабаÑÑваÑÑÑÑ: микÑозадаÑи иÑполнÑÑÑÑÑ Ð½ÐµÐ¿ÑеÑÑвно одна за дÑÑгой.
ÐоÑÑÐ¾Ð¼Ñ queueMicrotask можно иÑполÑзоваÑÑ Ð´Ð»Ñ Ð°ÑинÑ
Ñонного вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÑÑнкÑии в Ñом же ÑоÑÑоÑнии окÑÑжениÑ.
ÐÐ»Ñ Ð´Ð»Ð¸ÑелÑнÑÑ ÑÑжÑлÑÑ Ð²ÑÑиÑлений, коÑоÑÑе не Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±Ð»Ð¾ÐºÐ¸ÑоваÑÑ ÑобÑÑийнÑй Ñикл, Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ иÑполÑзоваÑÑ Web Workers.
ÐÑо ÑпоÑоб иÑполниÑÑ ÐºÐ¾Ð´ в дÑÑгом, паÑаллелÑном поÑоке.
Web Workers могÑÑ Ð¾Ð±Ð¼ÐµÐ½Ð¸Ð²Ð°ÑÑÑÑ ÑообÑениÑми Ñ Ð¾ÑновнÑм пÑоÑеÑÑом, но они имеÑÑ Ñвои пеÑеменнÑе и Ñвой ÑобÑÑийнÑй Ñикл.
Web Workers не имеÑÑ Ð´Ð¾ÑÑÑпа к DOM, поÑÑÐ¾Ð¼Ñ Ð¾Ñновное Ð¸Ñ Ð¿Ñименение â вÑÑиÑлениÑ. Ðни позволÑÑÑ Ð·Ð°Ð´ÐµÐ¹ÑÑвоваÑÑ Ð½ÐµÑколÑко ÑÐ´ÐµÑ Ð¿ÑоÑеÑÑоÑа одновÑеменно.
ÐомменÑаÑии
<code>, Ð´Ð»Ñ Ð½ÐµÑколÑÐºÐ¸Ñ ÑÑÑок кода — Ñег<pre>, еÑли болÑÑе 10 ÑÑÑок — ÑÑÑÐ»ÐºÑ Ð½Ð° пеÑоÑниÑÑ (plnkr, JSBin, codepenâ¦)