

Call Stack гэдэг нь JavaScript яг одоо ямар function ажиллуулж байгааг хянадаг бүтэц юм.
Function дуудагдах үед stack-ийн дээр нэмэгдэнэ. Function ажиллаж дуусах үед stack-аас гарна.
Ажиллах дараалал:
first() stack-д орно
console.log("First") ажиллана
second() stack-д орно
console.log("Second") ажиллана
second() stack-аас гарна
first() stack-аас гарна
Үүнийг Last In, First Out зарчим гэж ойлгож болно.
Хамгийн сүүлд stack-д орсон function хамгийн түрүүнд гарна.JavaScript нэг л Call Stack-тай.
Тиймээс нэг function удаан ажиллавал дараагийн код ажиллаж чадахгүй.
Энэ хугацаанд:
button click боловсруулахгүй;
animation гацна;
scroll тасалдана;
timer ажиллахгүй;
UI хариу өгөхгүй.
Үүнийг blocking гэж нэрлэдэг.
Function өөрийгөө зогсолтгүй дуудвал Call Stack дүүрнэ.
Үр дүнд нь:
Maximum call stack size exceeded
гэсэн алдаа гарна.Учир нь function бүр stack-д нэмэгдэж байгаа ч аль нь ч дуусаж, stack-аас гарахгүй байна.
setTimeout JavaScript дотор хүлээдэггүйГаралт:
Start
End
TimeoutsetTimeout-ийн хугацааг JavaScript өөрөө тоолдоггүй.
Browser-ийн Web API эсвэл Node.js runtime timer-ийг хариуцна. Хугацаа дуусмагц callback нь queue-д орж, Call Stack сулрахыг хүлээнэ.
Event Loop бол Call Stack болон queue-үүдийг ажиглаж байдаг механизм.
Түүний үндсэн ажил:
Call Stack сул эсэхийг шалгана.
Хүлээгдэж буй callback байгаа эсэхийг шалгана.
Stack сул байвал дараагийн callback-ийг ажиллуулна.
Ерөнхий урсгал:
Event Loop өөрөө callback-ийг ажиллуулдаггүй.
Харин callback-ийг Call Stack руу оруулж ажиллуулах боломж олгодог.
setTimeout(..., 0) яагаад шууд ажилладаггүй вэ?Гаралт:
0 миллисекунд гэдэг нь:
“Яг одоо ажиллуул.”
гэсэн үг биш.
Харин:
“Timer дууссан гэж үзээд callback-ийг queue-д оруул. Call Stack сулрах үед ажиллуул.”
гэсэн утгатай.
Эхлээд synchronous код бүрэн дуусна.
Дараа нь Event Loop callback-ийг Call Stack руу оруулна.
Асинхрон callback-ууд бүгд нэг queue-д ордоггүй.
Үндсэн хоёр queue бий:
Энд ихэвчлэн:
Promise.then
Promise.catch
Promise.finally
queueMicrotask
await-ийн дараах үргэлжлэл
орно.
Энд ихэвчлэн:
setTimeout
setInterval
DOM event
message event
орно.
Microtask Queue нь Task Queue-ээс өндөр давуу эрхтэй.
Гаралт:
Дарааллыг задлавал:
A хэвлэгдэнэ.
Timeout callback Task Queue-д орохоор бүртгэгдэнэ.
Promise callback Microtask Queue-д орно.
D хэвлэгдэнэ.
Call Stack сулрана.
Event Loop эхлээд Microtask Queue-г ажиллуулна.
C хэвлэгдэнэ.
Дараа нь Task Queue рүү орно.
B хэвлэгдэнэ.
Ерөнхий дараалал:
Event Loop зөвхөн нэг microtask ажиллуулаад Task Queue рүү ордоггүй.
Microtask Queue хоосрох хүртэл бүх microtask-ийг ажиллуулна.
Гаралт:
Эхний Promise шинэ microtask үүсгэсэн ч Event Loop түүнийг мөн дуусгасны дараа timeout руу шилжинэ.
Хэт олон microtask дараалан үүсвэл Task Queue болон UI rendering хүртэл хойшилж болно.
async/await thread үүсгэдэггүйГаралт:
await хүрэх хүртэлх код synchronous ажиллана.
await дээр function-ийн үлдсэн хэсэг түр зогсоно.
гэсэн үргэлжлэл нь Promise шийдэгдсэний дараа Microtask Queue-д орно.
await бүх JavaScript-ийг зогсоодоггүй. Зөвхөн тухайн async function-ийн үргэлжлэлийг хүлээлгэдэг.
Техникийн хувьд Event Loop биш, Call Stack удаан хугацаанд завгүй байна.
Гаралт:
Timeout callback аль хэдийн бэлэн болсон байж болно.
Гэхдээ Call Stack завгүй байгаа учраас Event Loop түүнийг ажиллуулахаар оруулж чадахгүй.
Иймээс timer-ийн хугацаа нь callback яг тэр мөчид ажиллана гэсэн баталгаа биш.
гэдэг нь:
“Callback хамгийн багадаа нэг секундийн дараа ажиллах боломжтой болно.”
гэсэн утгатай.
Event Loop-ийн нэг эргэлтийг хялбаршуулбал:
Browser болон Node.js-ийн event loop implementation яг адил биш боловч үндсэн санаа нь ижил.
JavaScript өөрөө олон ажлыг нэгэн зэрэг Call Stack дээр ажиллуулдаггүй.
Харин runtime орчин дараах ажлуудыг хариуцна:
timer;
network request;
file operation;
user event;
native API.
Эдгээр ажил дуусмагц callback эсвэл Promise-ийн үргэлжлэл queue-д орно.
Event Loop Call Stack сулрахыг хүлээгээд тэдгээрийг дарааллаар ажиллуулна.
Үндсэн оролцогчид:
JavaScript бол үндсэндээ synchronous, single-threaded хэл.
Асинхрон мэт ажиллагааг дараах систем бий болгодог:
runtime APIs удаан ажлыг гүйцэтгэнэ;
queue-үүд callback-уудыг хүлээлгэнэ;
Event Loop тэдгээрийг зохицуулна;
Call Stack кодыг нэг нэгээр нь ажиллуулна.
Хамгийн чухал дараалал:
Тиймээс async/await болон Promise ашиглаж сурахаас гадна Call Stack хэзээ сулрах, callback аль queue-д орох, Event Loop ямар дарааллаар ажиллуулахыг ойлгох нь JavaScript-ийн асинхрон ажиллагааг жинхэнээсээ ойлгох үндэс юм.