JavaScript運(yùn)行機(jī)制實例分析
本文實例講述了JavaScript運(yùn)行機(jī)制。分享給大家供大家參考,具體如下:
第一次寫博客目前研一第二學(xué)期,大二開始入門前端,然而長久以來都是對于框架的簡單調(diào)用,并未對其進(jìn)行深入研究,因此,這個博客是作為自我督促的開始。這篇博客的內(nèi)容源于前段時間寫一個微信小程序前端,發(fā)現(xiàn)頁面的渲染順序總與自己的預(yù)想相違背,因此近期看了一些關(guān)于JavaScript運(yùn)行機(jī)制的博客及文檔,有了一些基本的框架,接下來就來詳細(xì)看一下我所了解到的內(nèi)容。
JavaScript執(zhí)行順序首先,JavaScript是按照順序,一行一行執(zhí)行的,且JS只有一條線程,即不可能進(jìn)行兩條代碼同時執(zhí)行,也就是說,在一條代碼執(zhí)行時,它后面的所有代碼都需要等待,直到該代碼執(zhí)行結(jié)束,后面的才能繼續(xù)執(zhí)行。如果是這樣,就會導(dǎo)致用戶體驗度極其不好,例如一個請求發(fā)送給服務(wù)器,后續(xù)代碼就會一直等待,直到服務(wù)器返回結(jié)果,用戶才能進(jìn)行新的操作。
這又是怎么回事呢?
詳細(xì)解釋JavaScript執(zhí)行機(jī)制JavaScript執(zhí)行棧JavaScript是以壓棧的方式進(jìn)行代碼的執(zhí)行的,一開始執(zhí)行時棧內(nèi)為空,當(dāng)執(zhí)行開始,JS引擎會將代碼放入棧底,若該代碼包含其他函數(shù)的調(diào)用,則將被調(diào)用的函數(shù)放在棧頂,若該代碼未包含其他函數(shù)的調(diào)用,則執(zhí)行該函數(shù),執(zhí)行完成后出棧,以此類推,最終直到棧為空。
JavaScript的同步任務(wù)和異步任務(wù)事實上,真正的JS內(nèi)部分為同步任務(wù)和異步任務(wù),然而這并沒有改變JS單線程的特征。
同步任務(wù):執(zhí)行后直接返回結(jié)果,例:console.log();c = a + b 異步任務(wù):執(zhí)行后無法立刻返回結(jié)果,需要等待一定時間,才能執(zhí)行回調(diào)函數(shù),對返回結(jié)果進(jìn)行操作系統(tǒng)來說,JS存在一個主線程,它會首先執(zhí)行所有同步任務(wù),而異步任務(wù)都會先進(jìn)行注冊,然后主線程不會等待異步任務(wù)執(zhí)行結(jié)果的返回,而是繼續(xù)執(zhí)行下面的同步任務(wù)(在此過程中,如果異步任務(wù)返回結(jié)果,接下來的回調(diào)函數(shù)會放在Event Queue中等待),直到同步任務(wù)全部執(zhí)行完畢,主線程就會從Event Queue讀取任務(wù)進(jìn)行執(zhí)行。該過程會不斷循環(huán),即事件循環(huán)Event Loop。
事件循環(huán)是如何發(fā)生的不覺得奇怪嗎,如果按照上述同步任務(wù)和異步任務(wù)的執(zhí)行方式,那不是一輪就可以執(zhí)行完畢嗎,又何來的Event Loop?
這是個小細(xì)節(jié),異步任務(wù)存在多個時,每一個異步任務(wù)返回的結(jié)果所需的時間都是不同的,這就存在Event Queue以先進(jìn)先出的形式將返回結(jié)果進(jìn)行排隊,第一個異步任務(wù)返回結(jié)果,那么就將其放在隊列的首位,接下來的異步任務(wù)緊隨其后,就這樣排成一隊。當(dāng)主線程空閑時(即同步任務(wù)執(zhí)行完畢后),便從Event Queue中讀取事件,放入主線程執(zhí)行。而循環(huán)來自于,當(dāng)Event Queue執(zhí)行完畢后,過了一段時間,又有之前的異步任務(wù)返回結(jié)果,放到Event Queue中,監(jiān)控器檢測到Event Queue為非空,主線程又開始執(zhí)行Event Queue中的任務(wù)。
宏任務(wù)和微任務(wù)在解釋定義之前,我們先對異步任務(wù)進(jìn)行說明:
對服務(wù)器的異步請求:最常見的異步任務(wù),這涉及前后端的交互,需要服務(wù)器對請求進(jìn)行處理,并返回請求結(jié)果 setTimeout和setInterval:延時操作,后者為循環(huán)操作(都涉及延時值) Promise:JS用來處理異步操作的對象 process.nextTick(callback):類似node.js版的'setTimeout',在事件循環(huán)的下一次循環(huán)中調(diào)用 callback 回調(diào)函數(shù)。廣義上JS分為同步任務(wù)和異步任務(wù),在此對任務(wù)進(jìn)行更精細(xì)的定義:
macro-task(宏任務(wù)):包括整體代碼script,setTimeout,setInterval micro-task(微任務(wù)):Promise,process.nextTick在此,之所以提出宏任務(wù)和微任務(wù),是為了更好的理解事件循環(huán)!
執(zhí)行過程:
主線程會按順序先執(zhí)行第一次循環(huán)的宏任務(wù),然后將第一次循環(huán)遇到的微任務(wù)放入微任務(wù)的Event Queue中,將遇到的宏任務(wù)放入宏任務(wù)Event Queue中,在此特別注意!!第一次循環(huán)的宏任務(wù)是整體script代碼!!; 然后后執(zhí)行微任務(wù)的Event Queue; 第二次循環(huán)時,會從宏任務(wù)的Event Queue中取出第一個宏任務(wù),然后執(zhí)行當(dāng)前宏任務(wù)中包含的代碼,同樣將遇到的微任務(wù)放入微任務(wù)的Event Queue中,將遇到的宏任務(wù)放入宏任務(wù)Event Queue中; 再執(zhí)行當(dāng)前微任務(wù)的Event Queue中的任務(wù); 第三次循環(huán),從宏任務(wù)的Event Queue中取出第二個宏任務(wù)…(以此循環(huán))簡而言之,就是先執(zhí)行宏任務(wù),再執(zhí)行微任務(wù),特別注意兩點(diǎn)即可:
第一次循環(huán)的宏任務(wù)是整體script代碼 宏任務(wù)隊列是一次循環(huán)執(zhí)行一條宏任務(wù)這里看個例子:
console.log(’1’); setTimeout(function() { console.log(’2’); process.nextTick(function() { console.log(’3’); }) new Promise(function(resolve) { console.log(’4’); resolve(); }).then(function() { console.log(’5’) }) }) process.nextTick(function() { console.log(’6’); }) new Promise(function(resolve) { console.log(’7’); resolve(); }).then(function() { console.log(’8’) }) setTimeout(function() { console.log(’9’); process.nextTick(function() { console.log(’10’); }) new Promise(function(resolve) { console.log(’11’); resolve(); }).then(function() { console.log(’12’) }) }) //作者:ssssyoki //鏈接:https://juejin.im/post/59e85eebf265da430d571f89 //來源:掘金
輸出順序為:
1,7,6,8,2,4,3,5,9,11,10,12
總結(jié)在此博客中,或許包含一些你未曾聽過的名詞或方法,我并未對其進(jìn)行詳細(xì)解釋。之所以如此,是由于,于我個人,在看一些資料時,經(jīng)常遇到不懂的東西,我會選擇自己進(jìn)行查閱和理解,這樣更有效于記憶和通透的理解,就跟查單詞是一樣的,如果文本里直接告訴你,反而不會重視。
感興趣的朋友可以使用在線HTML/CSS/JavaScript代碼運(yùn)行工具:http://tools.jb51.net/code/HtmlJsRun測試上述代碼運(yùn)行效果。
更多關(guān)于JavaScript相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《JavaScript操作DOM技巧總結(jié)》、《JavaScript頁面元素操作技巧總結(jié)》、《JavaScript事件相關(guān)操作與技巧大全》、《JavaScript查找算法技巧總結(jié)》、《JavaScript數(shù)據(jù)結(jié)構(gòu)與算法技巧總結(jié)》、《JavaScript遍歷算法與技巧總結(jié)》及《JavaScript錯誤與調(diào)試技巧總結(jié)》
希望本文所述對大家JavaScript程序設(shè)計有所幫助。
相關(guān)文章:
1. 在Android中使用WebSocket實現(xiàn)消息通信的方法詳解2. python matplotlib:plt.scatter() 大小和顏色參數(shù)詳解3. Yii2.0引入CSS,JS文件方法4. JSP數(shù)據(jù)交互實現(xiàn)過程解析5. Python importlib動態(tài)導(dǎo)入模塊實現(xiàn)代碼6. vue使用webSocket更新實時天氣的方法7. 淺談python出錯時traceback的解讀8. android studio 打包自動生成版本號與日期,apk輸入路徑詳解9. Nginx+php配置文件及原理解析10. JavaMail 1.4 發(fā)布
