JavaScript tek iş parçacıklıyken, düğümün tüm G / Ç ve yerel API'lere yapılan çağrıların ya eşzamansız (platforma özgü mekanizmaları kullanarak) ya da ayrı bir iş parçacığında çalıştığını unutmayın. (Bunların tümü libuv aracılığıyla gerçekleştirilir.)
Bu nedenle, bir sokette mevcut veri olduğunda veya yerel bir API işlevi geri geldiğinde, az önce meydana gelen belirli bir olayla ilgilenen JavaScript işlevini çağırmak için senkronize bir yola ihtiyacımız var.
Normal çok iş parçacıklı bir uygulamada karşılaştığınız aynı nedenlerle yerel olayın gerçekleştiği iş parçacığından JS işlevini çağırmak güvenli değildir - yarış koşulları, atomik olmayan bellek erişimi vb.
Yani yaptığımız şey, olayı iş parçacığı açısından güvenli bir şekilde kuyruğa yerleştirmek. Aşırı basitleştirilmiş psuedocode'da şöyle bir şey:
lock (queue) {
queue.push(event);
}
Ardından, ana JavaScript iş parçacığına geri dönün (ancak şeylerin C tarafında), şöyle bir şey yaparız:
while (true) {
lock (queue) {
var tickEvents = copy(queue);
queue.empty();
}
for (var i = 0; i < tickEvents.length; i++) {
InvokeJSFunction(tickEvents[i]);
}
}
while (true)
(Aslında düğümün kaynak kodunda mevcut olmadığı, bu sadece açıklayıcı olduğu) temsil ettiği olay döngü . İç kısım for
, kuyruktaki her olay için JS işlevini çağırır.
Bu bir işarettir: herhangi bir harici olay ile ilişkili sıfır veya daha fazla geri arama işlevinin eşzamanlı çağrılması. Kuyruk boşaltıldıktan ve son işlev geri döndüğünde, tik biter. Başa geri dönüyoruz (bir sonraki tik) ve JavaScript'imiz çalışırken diğer iş parçacıklarından kuyruğa eklenen olayları kontrol ediyoruz .
Sıraya ne ekleyebilir?
process.nextTick
setTimeout
/setInterval
- I / O (gelen malzeme
fs
, net
ve benzeri)
crypto
kripto akışları, pbkdf2 ve PRNG gibi işlemci yoğun işlevleri (aslında bunlar ...
- eşzamanlı C / C ++ kitaplık çağrılarının eşzamansız görünmesini sağlamak için libuv iş kuyruğunu kullanan herhangi bir yerel modül