摘要:調(diào)用棧是一種棧結(jié)構(gòu)它用來存儲計(jì)算機(jī)程序執(zhí)行時(shí)候其活躍子程序的信息。調(diào)用棧是解析器的一種機(jī)制。并形成一個棧幀任何被這個函數(shù)調(diào)用的函數(shù)會進(jìn)一步添加到調(diào)用棧中,形成另一個棧幀并且運(yùn)行到它們被上個程序調(diào)用的位置。然后調(diào)用棧繼續(xù)運(yùn)行其他部門。
大家在進(jìn)行javascript開發(fā)的時(shí)候,有沒有想過,我們寫的代碼是怎么樣運(yùn)行的呢?下面我們就來剖析一下代碼的執(zhí)行過程。
一 什么是調(diào)用棧代碼在運(yùn)行過程中,會有一個叫做調(diào)用棧(call stack)的概念。調(diào)用棧是一種棧結(jié)構(gòu),它用來存儲計(jì)算機(jī)程序執(zhí)行時(shí)候其活躍子程序的信息。(比如什么函數(shù)正在執(zhí)行,什么函數(shù)正在被這個函數(shù)調(diào)用等等信息)。調(diào)用棧是解析器的一種機(jī)制。call stack
我們以一段簡單代碼為示例,來看一看到底什么是調(diào)用棧,它是一個怎么樣的運(yùn)行機(jī)制
function boo (a) { return a * 3 } function foo (b) { return boo(4) * 2 } console.log(foo(3))二 詳解代碼執(zhí)行
下面我們來分析一下上述代碼的執(zhí)行過程
(1)console.log(foo(3)) 執(zhí)行,形成一個棧幀,調(diào)用foo函數(shù),再形成另一個棧幀。
(2)新的棧幀壓在上一個棧幀之上,繼續(xù)執(zhí)行代碼,foo函數(shù)中又調(diào)用了boo函數(shù),形成了另一個棧幀壓在舊棧幀之上。然后執(zhí)行boo。
(3)當(dāng)執(zhí)行完boo時(shí)候,返回值給foo函數(shù)之后,boo被推出調(diào)用棧,foo函數(shù)繼續(xù)執(zhí)行,然后foo函數(shù)執(zhí)行完,返回值給console.log,foo函數(shù)被推出調(diào)用棧,console.log得到foo函數(shù)的返回值,運(yùn)行,輸出結(jié)果,最后console.log也被推出調(diào)用棧,該段程序執(zhí)行完成。
圖解代碼運(yùn)行過程:
// 省略一部分html $.on("button", "click", function onClick() { setTimeout(function timer() { console.log("You clicked the button!"); }, 0); }); console.log("Hi!"); setTimeout(function timeout() { console.log("Click the button!"); }, 5000); console.log("My Name Is Chirs.")
大家看看上敘的代碼,結(jié)合一下前面的的分析,思考一下調(diào)用棧是怎么工作的?
(1)先運(yùn)行綁定事件函數(shù),把onClick事件綁定在button標(biāo)簽上。該函數(shù)沒有沒有調(diào)用其他函數(shù)。
(2)接下來運(yùn)行console.log("hi"),該函數(shù)沒有調(diào)用任何其他函數(shù)。
(3)然后繼續(xù)執(zhí)行下面的setTimeout,setTimeout是一個異步函數(shù),經(jīng)過5秒之后,在運(yùn)行隊(duì)列里面插入這個回調(diào)函數(shù),然后如果該隊(duì)列之前沒有其他函數(shù),就執(zhí)行該隊(duì)列,有則等待前面的函數(shù)執(zhí)行完成,再執(zhí)行。
(4)console.log("My Name Is Chirs")不會等待5s之后,再執(zhí)行,因?yàn)閟ettimeout并不會在調(diào)用棧中執(zhí)行5秒,實(shí)際上它在調(diào)用棧中是立即執(zhí)行完的。
(5)假設(shè)在這個時(shí)候,我們點(diǎn)擊了按鈕,按鈕綁定的回調(diào)事件被添加到運(yùn)行隊(duì)列中。(運(yùn)行隊(duì)列中的代碼要等調(diào)用棧被清空之后才會執(zhí)行)由于調(diào)用棧中還有代碼需要執(zhí)行,所以會繼續(xù)執(zhí)行下面的console.log()
(6)然后執(zhí)行完console.log之后,由于時(shí)間還沒有經(jīng)過5s,所以點(diǎn)擊的回調(diào)事件會被先壓入棧中去執(zhí)行,由于該回調(diào)事件里面又是一個settimeout事件,由于它的事件間隔只有0s,所以這個settimeout的回調(diào)會先被壓入運(yùn)行隊(duì)列。先輸出You clicked the button! 再過幾秒之后,間隔為5s的settimeout把回調(diào)函數(shù)壓入隊(duì)列,這時(shí)候調(diào)用棧中沒有代碼在執(zhí)行,所以會執(zhí)行這個代碼,輸出"Click the button“。結(jié)束代碼運(yùn)行。
同樣來看一個運(yùn)行示意圖:
調(diào)用棧其實(shí)就是一種解析器去處理程序的機(jī)制,它是棧數(shù)據(jù)結(jié)構(gòu)。它能追蹤子程序的運(yùn)行狀態(tài)。
(1)當(dāng)腳本要調(diào)用一個函數(shù)時(shí),解析器把該函數(shù)添加到棧中并且執(zhí)行這個函數(shù)。并形成一個棧幀
(2)任何被這個函數(shù)調(diào)用的函數(shù)會進(jìn)一步添加到調(diào)用棧中,形成另一個棧幀,并且運(yùn)行到它們被上個程序調(diào)用的位置。
(3)當(dāng)執(zhí)行完這個函數(shù)后,如果它沒有調(diào)用其他函數(shù),則它會從調(diào)用棧中推出。然后調(diào)用棧繼續(xù)運(yùn)行其他部門。
(4) 異步函數(shù)的回調(diào)函數(shù)一般都會被添加到運(yùn)行隊(duì)列里面,如settimeout會在響應(yīng)的時(shí)間后把回調(diào)函數(shù)放入隊(duì)列中,隊(duì)列里的函數(shù)需要等棧為空時(shí)才會被推入棧中執(zhí)行。如果隊(duì)列中有其他函數(shù),需要等隊(duì)列前面的函數(shù)被堆入調(diào)用棧中之后才會運(yùn)行。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/84337.html
摘要:同時(shí),如果執(zhí)行的過程中發(fā)現(xiàn)其他函數(shù),繼續(xù)入棧然后執(zhí)行。上面我們討論的其實(shí)都是同步代碼,代碼在運(yùn)行的時(shí)候只用調(diào)用棧解釋就可以了。 序 Event Loop 這個概念相信大家或多或少都了解過,但是有一次被一個小伙伴問到它具體的原理的時(shí)候,感覺自己只知道個大概印象,于是計(jì)劃著寫一篇文章,用輸出倒逼輸入,讓自己重新學(xué)習(xí)這個概念,同時(shí)也能幫助更多的人理解它~ 概念 JavaScript 是一門 ...
摘要:如果執(zhí)行的準(zhǔn)備時(shí)間大于了,因?yàn)閳?zhí)行同步代碼后,定時(shí)器的回調(diào)已經(jīng)被放入隊(duì)列,所以會先執(zhí)行隊(duì)列。 showImg(https://segmentfault.com/img/remote/1460000018998584); 閱讀原文 瀏覽器中的事件輪詢 JavaScript 是一門單線程語言,之所以說是單線程,是因?yàn)樵跒g覽器中,如果是多線程,并且兩個線程同時(shí)操作了同一個 Dom 元素,...
摘要:回調(diào)函數(shù),一般在同步情境下是最后執(zhí)行的,而在異步情境下有可能不執(zhí)行,因?yàn)槭录]有被觸發(fā)或者條件不滿足。同步方式請求異步同步請求當(dāng)請求開始發(fā)送時(shí),瀏覽器事件線程通知主線程,讓線程發(fā)送數(shù)據(jù)請求,主線程收到 一直以來都知道JavaScript是一門單線程語言,在筆試過程中不斷的遇到一些輸出結(jié)果的問題,考量的是對異步編程掌握情況。一般被問到異步的時(shí)候腦子里第一反應(yīng)就是Ajax,setTimse...
摘要:核心的異步延遲函數(shù),用于異步延遲調(diào)用函數(shù)優(yōu)先使用原生原本支持更廣,但在的中,觸摸事件處理程序中觸發(fā)會產(chǎn)生嚴(yán)重錯誤的,回調(diào)被推入隊(duì)列但是隊(duì)列可能不會如期執(zhí)行。 淺析 Vue 2.6 中的 nextTick 方法。 事件循環(huán) JS 的 事件循環(huán) 和 任務(wù)隊(duì)列 其實(shí)是理解 nextTick 概念的關(guān)鍵。這個網(wǎng)上其實(shí)有很多優(yōu)質(zhì)的文章做了詳細(xì)介紹,我就簡單過過了。 以下內(nèi)容適用于瀏覽器端 JS,...
摘要:如,不是定義常量么為什么還能改這就是我們今天要說的重點(diǎn)中的堆內(nèi)存與棧內(nèi)存在引擎中對變量的存儲主要有兩種位置,堆內(nèi)存和棧內(nèi)存。而堆內(nèi)存首先要在堆內(nèi)存新分配存儲區(qū)域,之后又要把指針存儲到棧內(nèi)存中,效率相對就要低一些了。 最近跟著組里的大佬面試碰到這么一個問題, Q:說說var、let、const的區(qū)別A:balabalabalabla...Q:const定義的值能改么?A:你逗我?不能吧 ...
閱讀 1994·2021-11-15 18:09
閱讀 889·2021-09-06 15:13
閱讀 2636·2021-08-23 09:43
閱讀 2016·2019-08-30 15:54
閱讀 2209·2019-08-30 13:56
閱讀 2476·2019-08-26 11:31
閱讀 3070·2019-08-26 10:56
閱讀 685·2019-08-26 10:28