Как работи цикълът на събитията в JavaScript?

Макар че може да изисква задълбочено разбиране на езици като C ++ и C, за да напишете пълномащабен производствен код, JavaScript често може да бъде написан само с основно разбиране за това какво може да се направи с езика.


Концепции, като предаване на обратни обаждания към функции или писане на асинхронен код, често не са толкова трудни за изпълнение, което кара повечето разработчици на JavaScript да се грижат по-малко за това какво става под капака. Те просто не се интересуват от разбирането на сложностите, които са дълбоко абстрахирани от тях от езика.

Като разработчик на JavaScript става все по-важно да разберем какво наистина се случва под капака и как действително работят повечето от тези сложности, абстрахирани от нас. Помага ни да вземаме по-информирани решения, което от своя страна може да повиши драстично нашата работа.

Тази статия се фокусира върху една от много важните, но рядко разбираеми понятия или термини в JavaScript. Най- СЪБИТИЕ LOOP!. 

Писането на асинхронен код не може да бъде избегнато в JavaScript, но защо код, работещ асинхронно, наистина означава? т.е.. Примката на събитието

Преди да разберем как работи цикълът на събитията, първо трябва да разберем какво представлява самият JavaScript и как работи!

Какво е JavaScript?

Преди да продължим, бих искал да направим крачка назад към самите основи. Какво всъщност е JavaScript? Бихме могли да определим JavaScript като;

JavaScript е високо ниво, интерпретиран, еднопоточен, не блокиращ, асинхронен, паралелен език.

Чакай, какво е това? Буквално определение? ��

Нека го разградим!

Ключовите думи тук по отношение на тази статия са еднонишкови, не блокиращ, едновременно, и асинхронни.

Единична нишка

Нишката на изпълнение е най-малката последователност от програмирана инструкция, която може да се управлява независимо от планировчик. Езикът за програмиране е еднопоточен означава, че може да изпълнява само една задача или операция едновременно. Това означава, че би изпълнил цял процес от началото до края, без нишката да бъде прекъсната или спряна.

За разлика от многопоточните езици, при които множество процеси могат да се изпълняват едновременно в няколко нишки, без да се блокират взаимно.

Как JavaScript може да бъде с една нишка и без блокиране по същото време?

Но какво означава блокиране?

Неблокираща

Няма едно определение за блокиране; просто означава неща, които вървят бавно по нишката. Така че блокирането означава неща, които не са бавни по темата.

Но изчакайте, казах ли, че JavaScript работи на една нишка? И аз също казах, че не блокира, което означава, че задачата се изпълнява бързо в стека на повикванията? Но как??? Какво ще кажете, когато работим таймери? Loops?

Отпуснете се! Ще разберем малко ��.

едновременен

Паралелността означава, че кодът се изпълнява едновременно от повече от една нишка.

Добре, нещата стават наистина странен сега, как JavaScript може да бъде еднопоточен и едновременно да бъде съвместен? т.е., изпълнявайки кода си с повече от една нишка?

Asynchronous

Асинхронното програмиране означава, че кодът работи в цикъл на събитията. Когато има блокираща операция, събитието се стартира. Блокиращият код продължава да работи, без да блокира основната нишка за изпълнение. Когато блокиращият код приключи да се изпълнява, той е на опашката в резултат на блокиращите операции и ги връща обратно към стека.

Но JavaScript има една нишка? Какво тогава изпълнява този блокиращ код, докато оставя други кодове в нишката да се изпълняват?

Преди да продължим, нека да направим обобщение на горното.

  • JavaScript е с една нишка
  • JavaScript не блокира, т.е. бавните процеси не блокират неговото изпълнение
  • JavaScript е паралелен, т.е. изпълнява кода си в повече от една нишка едновременно
  • JavaScript е асинхронен, т.е. той работи блокиращ код някъде другаде.

Но горното не се събира точно как може еднопоточният език да не е блокиращ, едновременно и асинхронен?

Нека да отидем малко по-надълбоко, нека да се спуснем към двигателите за изпълнение на JavaScript, V8, може би има някои скрити нишки, за които не сме запознати.

V8 двигател

Двигателят V8 е високоефективен, с отворен код уебспръскващ механизъм за изпълнение за JavaScript, написан на C ++ от Google. Повечето браузъри работят с JavaScript, използвайки V8 двигателя и дори популярната среда за изпълнение на възел js също го използва.

На прост английски език V8 е C ++ програма, която получава JavaScript код, компилира и го изпълнява.

V8 прави две основни неща;

  • Разпределение на паметта на купчината
  • Контекст за изпълнение на стек за повикване

За съжаление подозрението ни беше грешно. V8 има само един стек за повиквания, помислете за стека на повикванията като нишка.

Една нишка === един стек за повикване === едно изпълнение в даден момент.

Изображение – хакерски обед

Тъй като V8 има само един стек за повиквания, как тогава JavaScript работи едновременно и асинхронно, без да блокира основната нишка за изпълнение?

Нека се опитаме да разберем, като напишем прост, но често срещан асинхронен код и заедно го анализираме.

JavaScript изпълнява всеки ред по ред, един след друг (едноредов). Както се очаква, първият ред се отпечатва в конзолата тук, но защо последният ред се отпечатва преди кода на изчакване? Защо процесът на изпълнение не изчаква кода за изчакване (блокиране), преди да продължи напред, за да стартира последния ред?

Изглежда, че някаква друга нишка ни е помогнала да изпълним този период от време, тъй като сме почти сигурни, че нишката може да изпълни само една задача във всеки момент.

Нека погледнем подъл V8 Изходен код за малко.

Чакаме какво??!!! В V8 няма таймерни функции, няма DOM? Няма събития? Няма AJAX?…. Yeeeeessss!!!

Събития, DOM, таймери и т.н. не са част от основната имплементация на JavaScript, JavaScript стриктно съответства на спецификациите на Ecma Scripts и различните версии на него често се посочват в съответствие със спецификациите на Ecma Scripts (ES X).

Изпълнение Работен процес

Събития, таймери, заявки на Ajax се предоставят от страна на клиента от браузърите и често се наричат ​​Web API. Те са тези, които позволяват на еднопоточния JavaScript да бъде блокиращ, едновременен и асинхронен! Но как?

Има три основни секции към работния процес на изпълнение на всяка програма на JavaScript, стека на обажданията, уеб API и опашката на задачите.

Стека на обажданията

Стекът е структура от данни, в която последният добавен елемент винаги е първият, който се премахва от стека, можете да мислите за него като стек от плоча, в който първо може да бъде премахната само първата плоча, която е била последната добавена. Стекът на обаждания е просто нищо, освен структура на стек данни, където задачите или кодът се изпълняват съответно.

Нека разгледаме следния пример;

Източник – https://youtu.be/8aGhZQkoFbQ

Когато извикате функцията printSquare (), тя се натиска върху стека на повикванията, функцията printSquare () извиква функцията square (). Функцията square () се натиска върху стека и също извиква функцията multiply (). Функцията за умножение се натиска върху стека. Тъй като функцията за умножение се връща и е последното нещо, което беше избутано към стека, първо се разрешава и се отстранява от стека, последвано от функцията square () и след това функцията printSquare ().

Web API

Тук се изпълнява код, който не се обработва от V8 двигателя, за да не “блокира” основната нишка за изпълнение. Когато стекът за повикване се сблъска с функция на уеб API, процесът се предава незабавно на уеб API, където се изпълнява и освобождава стека за повикване за извършване на други операции по време на неговото изпълнение.

Да се ​​върнем към нашия пример setTimeout по-горе;

Когато стартираме кода, първият ред console.log се изтласква към стека и получаваме изхода си почти веднага, след като стигнем до тайм-аута, таймерите се обработват от браузър и не са част от основната имплементация на V8, той се натиска вместо това да освобождава стека, за да може да извършва други операции.

Докато тайм-аутът продължава да работи, стекът преминава към следващия ред на действие и изпълнява последния console.log, което обяснява защо получаваме това, изведено преди изхода на таймера. След като таймерът е завършен, нещо се случва. Конзолата.log в тогава таймер магически се появява отново в стека на повикванията!

как?

Примката на събитието

Преди да обсъдим цикъла на събитието, нека първо преминем през функцията на опашката за задачи.

Назад към нашия пример за изчакване, след като Web API завърши изпълнението на задачата, той не го връща автоматично към стека на обажданията автоматично. Отива се към Опашка за задачи. 

Опашката е структура от данни, която работи на принципа First in First out, така че когато задачите бъдат изтласкани в опашката, те излизат в същия ред. Задачи, изпълнени от API на Web API, които се избутват към опашката на задачите, след което се върнете към стека на обажданията, за да изпечатате резултата си.

Но почакай. КАКЪВ ХЕКЪТ Е СЪБИТИЯТ ЛОП???

Източник – https://youtu.be/8aGhZQkoFbQ

Цикълът на събитията е процес, който изчаква стека на повикването да се изчисти, преди да натисне обратните повиквания от опашката за задачи към стека на повикванията. След като стекът е изчистен, цикълът на събитието се задейства и проверява опашката за задачи за налични обратни повиквания. Ако има такива, той го избутва към стека за повикване, изчаква отново стека за повикване и се повтаря същия процес.

Източник – https://www.quora.com/How-does-an-event-loop-work/answer/Timothy-Maxwell

Горната диаграма демонстрира основния работен процес между цикъла на събитията и опашката на задачите.

заключение

Въпреки че това е много основно въведение, концепцията за асинхронно програмиране в JavaScript дава достатъчно разбиране, за да се разбере ясно какво става под капака и как JavaScript може да работи едновременно и асинхронно само с една нишка.

JavaScript винаги е по заявка и ако ви е любопитно да научите, бих ви посъветвал да проверите това Удеми курс.

Jeffrey Wilson Administrator
Sorry! The Author has not filled his profile.
follow me
    Like this post? Please share to your friends:
    Adblock
    detector
    map