Я недавно закончил учебный курс по разработке программного обеспечения в школе Flatiron. На протяжении всей программы я погрузился в Ruby, Rails, Sinatra, JavaScript, React и Redux. Я узнал, что каждый язык/фреймворк имеет свои уникальные проблемы. «Стек вызовов» JavaScript был одной из самых сложных концепций для понимания, однако он является неотъемлемой частью оптимизированного взаимодействия с пользователем.
JavaScript является однопоточным, что означает, что в момент выполнения кода происходит только одно действие. Механизм JavaScript отслеживает, где он находится в коде, используя стек вызовов. Когда несколько синхронных функций вызываются одновременно, функции добавляются в стек в том порядке, в котором они были вызваны. Как только функция возвращается, она «выталкивается» из стека вызовов, и выполняется следующая функция.
На изображении ниже объявляются и вызываются три функции (A, B, C).
В приведенном выше примере демонстрируется синхронный блок кода, в котором каждый раздел кода выполняется по одному, в определенной последовательности. Каждая функция вызывается и добавляется в стек вызовов по порядку, и поскольку они являются синхронными запросами, данные записываются в консоль, как и ожидалось. Синхронные функции отлично подходят для простых задач, но могут быть проблематичными для функций, выполнение которых занимает много времени. Последнее, чего хочет пользователь, — это смотреть на пустой экран и думать, загрузится ли страница!
Итак, если JavaScript способен выполнять только одну команду за раз, как мы можем избежать зависания из-за медленного кода?
К счастью для нас, браузер может обрабатывать асинхронные запросы в фоновом режиме, не останавливая и не «блокируя» выполнение другого кода. Когда механизм JavaScript распознает асинхронный запрос, он передает его для выполнения браузером. Синхронный код является «блокирующим», в то время как асинхронный код является «неблокирующим», что означает, что другой код может выполняться до того, как функция будет возвращена. Асинхронные запросы не добавляются в стек вызовов до тех пор, пока они не будут возвращены, и стек вызовов не станет пустым.
Примером асинхронного запроса является выборка. В приведенном ниже примере функция handleSubmit вызывается при отправке формы для создания нового события. Я включил журналы консоли, чтобы продемонстрировать порядок выполнения кода. Основываясь на том, что вы знаете о синхронных и асинхронных запросах, как вы думаете, что мы увидим в консоли?
handleSubmit = event => { event.preventDefault(); console.log('Before create event') this.createEvent(); console.log('After createEvent') } createEvent = () => { console.log('Making fetch request') return fetch('http://localhost:3001/events', { method: 'POST', headers: { "Accept": "application/json", "Content-Type": "application/json", }, body: JSON.stringify({event: { name: this.state.name, start_time: this.state.start_time, end_time: this.state.end_time, location: this.state.location, address: this.state.address, notes: this.state.notes, invited_user_ids: this.state.invited_user_ids, } }) }) .then(res => { if(res.ok) { console.log('successful response') return res.json() } else { return res.json().then(errors => Promise.reject(errors)) } }) }
Вы были правы? Как видите, асинхронный запрос на выборку регистрируется в консоли последним.
День за днем я восхищаюсь сложностью и возможностями Интернета. Во время учебы в школе Flatiron я узнал, что важно понимать стек вызовов JavaScript и использовать как синхронный, так и асинхронный код для создания наилучшего взаимодействия с пользователем.