1. <ul id="0c1fb"></ul>

      <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
      <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区

      RELATEED CONSULTING
      相關(guān)咨詢
      選擇下列產(chǎn)品馬上在線溝通
      服務(wù)時(shí)間:8:30-17:00
      你可能遇到了下面的問題
      關(guān)閉右側(cè)工具欄

      新聞中心

      這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
      了解JS中的執(zhí)行上下文、執(zhí)行棧、事件循環(huán)

      本篇文章帶大家了解一下Javascript中的執(zhí)行上下文和執(zhí)行棧、事件循環(huán)。有一定的參考價(jià)值,有需要的朋友可以參考一下,希望對(duì)大家有所幫助。

      橫山網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián)建站,橫山網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為橫山超過千家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\成都外貿(mào)網(wǎng)站建設(shè)要多少錢,請(qǐng)找那個(gè)售后服務(wù)好的橫山做網(wǎng)站的公司定做!

      下面的這些概念,無論是執(zhí)行上下文、 還是執(zhí)行棧,它在規(guī)范中的概念都很抽象,很多內(nèi)容的理解實(shí)際靠的都是想象力,若有錯(cuò)誤之處,還請(qǐng)指正。

      執(zhí)行上下文

      簡而言之,執(zhí)行上下文(Execution Context)是正在運(yùn)行的可執(zhí)行代碼所處環(huán)境的抽象,用于追蹤一段代碼中變量的求值。這是我總結(jié)過來的概念,可能有些不準(zhǔn)確,也可以參考真正的規(guī)范定義。

      不過總的來說,有三個(gè)關(guān)鍵點(diǎn):

      只有可執(zhí)行代碼才會(huì)有執(zhí)行上下文

      執(zhí)行上下文是有狀態(tài)的:運(yùn)行狀態(tài)(Perform)、掛起狀態(tài)(Suspend)以及恢復(fù)(Resume)。處于Perfrom狀態(tài)的執(zhí)行上下文稱之為運(yùn)行時(shí)執(zhí)行上下文(Running Execution Context)

      執(zhí)行上下文完全不等價(jià)于詞法環(huán)境,硬說關(guān)系,也只是前者引用了后者而已。

      執(zhí)行一個(gè)JS腳本時(shí),可以有多個(gè)執(zhí)行上下文存在,但是 運(yùn)行時(shí)上下文只有唯一一個(gè)(異步也是如此,至于為什么提了四個(gè)……三大天王有四個(gè)不是常識(shí)么……)。

      并且ES規(guī)范中規(guī)定,可執(zhí)行代碼有下面幾個(gè):

      全局代碼

      函數(shù)代碼

      Eval語句

      模塊代碼

      換言之,看以下代碼:

        var g=111
        function f(){
            console.log(g);
            for(let i =0; i < 10; i++){
                console.log(i);
            }
        }
        f();  /// (*)

      如果上面的代碼運(yùn)行,只會(huì)產(chǎn)生兩個(gè)執(zhí)行上下文:

      全局

      函數(shù)f

      但是如果將標(biāo)注(*)的行注釋掉,那么最終只有一個(gè)執(zhí)行上下文,因?yàn)楹瘮?shù)f根本就不會(huì)執(zhí)行,自然就不會(huì)有相應(yīng)的執(zhí)行上下文了。里面唯一一個(gè)迷惑的是,就是for-loop了,但它根本不是可執(zhí)行代碼,所以它是函數(shù)執(zhí)行上下文的一部分。

      執(zhí)行上下文的重要組成部分

      一個(gè)執(zhí)行上下文,可以抽象為:

      ExecutionContext = {
          State: <>
          LexEnv = {
              This:< ... > ,
              OuterEnv:< ... > ,
              DecRec:{
                  //... identifiername-variable
              }    }
          VaEnv = {
              This:< ... > ,
              OuterEnv:< ... > ,
              VarRec:{
                  //... identifiername-variable
              }    }
      }

      事實(shí)上,在一個(gè)執(zhí)行上下文中有兩個(gè)相當(dāng)重要的組件:LexicalEnvironmentComponent(詞法環(huán)境組件)和VariableEnvironmentComponent(變量環(huán)境組件)。詞法環(huán)境組件指向當(dāng)前代碼中的詞法環(huán)境(LexEnv), 變量環(huán)境組件指向當(dāng)前代碼的變量環(huán)境(VarEnv)。

      關(guān)于執(zhí)行上下文不得不說的二三事中,有一個(gè)很重要的部分就是作用域鏈,但是在執(zhí)行上下文中并沒有看到相關(guān)內(nèi)容。不過作用域鏈的確存在,它就在[[Scope]]內(nèi)部屬性中,通過瀏覽器可以直接看到。

      不過也可以這樣理解,在一個(gè)執(zhí)行上下文被創(chuàng)建時(shí),不僅會(huì)創(chuàng)建當(dāng)前詞法環(huán)境的LexEnv,也會(huì)創(chuàng)建LexEnv.OutEnvLexEnv.OutEnv.OutEnv…,直至延伸到全局為止。

      執(zhí)行上下文的創(chuàng)建與銷毀

      1、創(chuàng)建一個(gè)新執(zhí)行上下文(ExecutionContext , EC)

      2、創(chuàng)建當(dāng)前詞法環(huán)境(LexEnv 和 VarEnv )

      3、將該執(zhí)行上下文的LexicalEnvironmentComponentVariableEnvironmentComponent指向當(dāng)前環(huán)境下的LexEnvVarEnv中。

      4、將新執(zhí)行上下文推入執(zhí)行棧中,并成為運(yùn)行時(shí)執(zhí)行上下文。

      5、對(duì)可執(zhí)行代碼塊內(nèi)的標(biāo)識(shí)符進(jìn)行實(shí)例化和初始化:

      收集當(dāng)前詞法環(huán)境內(nèi)所有聲明的標(biāo)識(shí)符歸入DecRec中,所有var聲明的標(biāo)識(shí)符歸入VarNames集合中,在此階段會(huì)進(jìn)行標(biāo)識(shí)符名檢測(cè),若與let/const/...聲明的標(biāo)識(shí)符與VarNames中的標(biāo)識(shí)符重復(fù), 報(bào)錯(cuò)。

      DecRec中的標(biāo)識(shí)符進(jìn)行實(shí)例化,并設(shè)為uninitializedVarNames中的標(biāo)識(shí)符綁定在ObjRec中,實(shí)例化后直接初始化為undefined

      對(duì)于function聲明的函數(shù),將直接指向函數(shù)對(duì)象,并也會(huì)綁定到ObjRec中,這是瀏覽器默認(rèn)行為。

      6、運(yùn)行代碼。

      非var聲明的標(biāo)識(shí)符會(huì)在聲明處進(jìn)行初始化(默認(rèn)為undefined)。

      完成所有變量的賦值,并可能會(huì)一直在變化。

      7、運(yùn)行完畢從執(zhí)行棧中彈出。

      備注:

      關(guān)于This綁定,大部分情況可以用過去的說法解釋,然而某些情況下卻不盡然。閉包我會(huì)在下一篇介紹。執(zhí)行上下文,我個(gè)人認(rèn)為并不如何重要,但是卻能在許多情形下起到極為關(guān)鍵的作用,所以還是有必要去深入認(rèn)識(shí)一下。關(guān)于執(zhí)行上下文和詞法環(huán)境的關(guān)系,最多是前者引用了后者,僅此而已。誠然,有許多情況沒必要用執(zhí)行上下文來說明,但是永遠(yuǎn)避免不了違和感。

      執(zhí)行棧與事件循環(huán)

      執(zhí)行棧(Execution Stack)就是由執(zhí)行上下文構(gòu)成的堆棧,類似于Call Stack

      1、當(dāng)Javascript引擎遇到一段可執(zhí)行代碼時(shí),新建一個(gè)執(zhí)行上下文。

      2、將它推入執(zhí)行棧中。并設(shè)置為運(yùn)行時(shí)執(zhí)行上下文。

      如果存在其他執(zhí)行上下文。那么將當(dāng)前執(zhí)行上下文掛起然后再將新執(zhí)行上下文推入執(zhí)行棧中。

      3、執(zhí)行上下文運(yùn)行完畢,彈出銷毀恢復(fù)并將原執(zhí)行上下文設(shè)為運(yùn)行時(shí)。

      總覺得這些沒什么好說的,但是水一下吧

      執(zhí)行棧最重要的部分并非是執(zhí)行棧概念本身,而是與任務(wù)隊(duì)列的關(guān)系,它是事件循環(huán)的入門關(guān)鍵概念之一。

      眾所周知,Javascript語言是單線程的,此處的執(zhí)行棧就相當(dāng)于主線程的調(diào)用棧,也是唯一一個(gè)調(diào)用棧,至于什么是主線程可以查閱相關(guān)資料,這里有些超綱了……

      那么javascript是如何實(shí)現(xiàn)異步的?

      確切來說,這不是Javascript核心的部分,它是結(jié)合瀏覽器API(如Web Worker, Browser-context了解一下)實(shí)現(xiàn)的。

      在事件循環(huán)中(事件處理過程),有兩個(gè)極其重要的概念:

      任務(wù)序列: Task Quenue事件: Event

      這兩個(gè)概念,是抽象滴。

      在Javascript中,一個(gè)任務(wù)也可以稱之為事件,通常是一個(gè)函數(shù)回調(diào),由許多任務(wù)組成的隊(duì)列,就是所謂的任務(wù)序列了。任務(wù)序列有很多分類,例如:作業(yè)序列(Job Quenue)、消息序列(Message Quenue),本質(zhì)沒區(qū)別。

      不必再深入了解,現(xiàn)在需要記住的是:一個(gè)任務(wù)序列中的任務(wù)如果想要被執(zhí)行,就必須將它取出放入執(zhí)行棧中。

      舉一個(gè)抽象點(diǎn)的例子:

      例如下面的代碼:

            var temp = 10;
            console.log('push task1');
            setTimeout(function task1(){
              temp+=10;
              console.log(temp+'task1 okay! ');
            },1000)
            console.log('taskquenue=[task1]; push task2');
            setTimeout(function task2(){
              temp*=10;
              console.log(temp+'task2 okay! ');
            },500) 
           console.log('taskquenue=[task1,task2]; push task3');
            setTimeout(function task3(){
              temp*= -0.2;
              console.log(temp+'task3 okay! ');
            },1500)
            console.log('taskquenue=[task1, task2,task3]');

      輸出如下:

      push task1
      taskquenue=[task1]; push task2
      taskquenue=[task1,task2]; push task3
      taskquenue=[task1, task2,task3]
      100task2 okay! 
      110task1 okay! 
      -22task3 okay!

      setTimeout是一個(gè)定時(shí)器,它能夠?qū)⑷蝿?wù)放到任務(wù)隊(duì)列中。如圖:

      添加作業(yè)task1
      添加作業(yè)task2
      添加作業(yè)task3

      執(zhí)行到此處,task1task2task3都被放入了任務(wù)隊(duì)列; 然后執(zhí)行棧全部執(zhí)行完畢后,開始處理任務(wù)隊(duì)列中的任務(wù)。

      為什么任務(wù)隊(duì)列中的任務(wù)必須在執(zhí)行棧空時(shí)后執(zhí)行呢?

      這里我也不清楚,這畢竟真正涉及了底層內(nèi)容;只是有些明白為何這樣,不過擔(dān)心誤導(dǎo)他人,就算了。一般而言, 關(guān)于任務(wù)序列的相關(guān)概念沒有如此簡單,還涉及了很多東西,例如阻塞、調(diào)度(Schedule)等,這些方面可以參考其他諸如C++Java這類多線程的語言或是看看操作系統(tǒng)這方面的內(nèi)容。如果只是簡單的業(yè)務(wù)實(shí)現(xiàn),不需要了解這么多底層的東西。

      現(xiàn)在開始處理任務(wù)吧:

      處理task2
      處理task1
      處理task3

      好了,一個(gè)事件循環(huán)就這么結(jié)束了。
      然后Javascript引擎進(jìn)入休眠階段(Javascript引擎永不結(jié)束!),等待有新的任務(wù)執(zhí)行,然后開始下一個(gè)事件循環(huán)。

      備注:這里只是一個(gè)簡單例子事件循環(huán)可以有多個(gè)任務(wù)隊(duì)列任務(wù)序列共分為兩種: 微任務(wù)序列和宏任務(wù)序列我們的script代碼,就是宏任務(wù)序列之一。最后: Javascript引擎

      這是我精讀Javascript系列第三篇,猝不及防的就到了事件循環(huán),看起來一下子就深入好多好多…… 但是我覺得這才是最不合理程安排,大多的文檔都把任務(wù)序列和調(diào)用棧給分開了,但是在~~_____~~,它們本應(yīng)該就是一體,不應(yīng)該以任何方便的理由將它們分開。

      深入Javascript, 除了看規(guī)范,最好也看下JS引擎的實(shí)現(xiàn)文檔,有些進(jìn)階內(nèi)容,不在規(guī)范中,而是在這些文檔里(請(qǐng)自己Google查找,百度也能搜索到)。

      如果對(duì)Javascript引擎比較感興趣的,可以參考:

      MDN About_JavascriptChromium V8參考Github V8

      雖然,極其不建議新手一下子看V8源代碼,那種頭痛欲裂又渾身顫抖不止的感覺實(shí)在是過癮之極啊……

      相關(guān)教程推薦:JavaScript視頻教程

      網(wǎng)站名稱:了解JS中的執(zhí)行上下文、執(zhí)行棧、事件循環(huán)
      網(wǎng)頁鏈接:http://www.ef60e0e.cn/article/cpdscp.html

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区
      1. <ul id="0c1fb"></ul>

        <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
        <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

        延川县| 永和县| 景洪市| 屯留县| 舞钢市| 武穴市| 裕民县| 醴陵市| 文安县| 运城市| 灵丘县| 手游| 莎车县| 隆化县| 揭阳市| 吴堡县| 磴口县| 祥云县| 东兴市| 常宁市| 铜梁县| 黔南| 栖霞市| 济宁市| 卓资县| 手游| 永清县| 班玛县| 辛集市| 额尔古纳市| 海盐县| 新化县| 耒阳市| 商河县| 长子县| 德州市| 革吉县| 沐川县| 宁陕县| 黔西| 鄂尔多斯市|