<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 一、棧(stack) > 學習編程的時候,經常會看到stack這個詞,它的中文名字叫做"棧"。 理解這個概念,對于理解程序的運行至關重要。容易混淆的是,這個詞其實有三種含義,適用于不同的場合,必須加以區分。 <br> <br> ## 含義一:數據結構 stack的第一種含義是一組數據的存放方式,特點為LIFO,即**后進先出**(Last in, first out)。 <br> ![](https://box.kancloud.cn/0bfd496a679a94344736cc29fb3681e8_385x260.png) <br> 在這種數據結構中,數據像積木那樣一層層堆起來,后面加入的數據就放在最上層。使用的時候,最上層的數據第一個被用掉,這就叫做"后進先出"。 ``` // 用數組對 棧結構 進行模擬 var stack = []; // push就相當于放羽毛球進去,專業術語叫壓棧 stack.push('1號羽毛球'); stack.push('2號羽毛球'); stack.push('3號羽毛球'); // pop就相當于拿一個羽毛球出來, 專業術語叫彈棧 stack.pop(); ``` <br> ## 含義二:代碼運行方式 stack的第二種含義是"調用棧"(call stack),表示函數或代碼像堆積木一樣存放,以實現層層調用。 <br> ![](https://box.kancloud.cn/db72d02c411342045393de826dd5875f_562x303.png) 1. 運行console.log(1),這個時候瀏覽器就會把console.log(1)丟進調用棧 <br> ![](https://box.kancloud.cn/ab313f90b2f472b07a5d14d0c28278ac_857x376.png) 2. 因為調用棧有東西,所以js解析器就會去執行,console.log(1)執行完畢,就會彈出調用棧,瀏覽器控制臺就會打印1 <br> <br> 剩下的代碼如此類推,見下圖 <br> ![](https://box.kancloud.cn/dd344f564d69467357bf3946ea3fb9be_932x387.png) ![](https://box.kancloud.cn/209a446976c9f2047e6447b506745669_856x376.png) ![](https://box.kancloud.cn/9c5b207c626aa1537a4838df66357288_893x370.png) ![](https://box.kancloud.cn/4a0c25429d8467b8779c3fdc940965d5_859x384.png) 調用像積木一樣堆起來,就叫做"調用棧"。程序運行的時候,總是先完成最上層的調用,然后將它的值返回到下一層調用,直至完成整個調用棧,返回最后的結果。 <br> <br> ## 含義三:存儲數據的區域 stack的第三種含義是存放數據的一種內存區域。程序運行的時候,需要內存空間存放數據。一般來說,系統會劃分出兩種不同的內存空間:一種叫做stack(棧),另一種叫做heap(堆)。棧是存基本數據類型,堆存引用數據類型。 <br> <br> 我們來看看下面的代碼: ``` var a = 20; var b = 'abc'; var c = true; var d = { m: 20 }; var e = d; e.m = 30; console.log(d.m) ??? ``` <br> <br> ![](https://box.kancloud.cn/aa987499988edaf05b86cf051f20cff7_722x303.png) 1. js解析器會去找var,然后把聲明的變量都賦值undefined并且存到棧內存 <br> <br> ![](https://box.kancloud.cn/4dd90c627a6503c38fac54d1449c4967_728x317.png) 2. 然后第二次讀取代碼的時候會執行聲明賦值,基本數據類型就存儲在棧內存,對象就存儲到堆內存,棧里面的d通過地址訪問堆里面關聯對象 <br> <br> ![](https://box.kancloud.cn/1220e76405bdaf477bea0f8e0af78cb7_736x337.png) <br> <br> # 二、任務隊列 JS是單線程,一次只能執行一個任務,所以所有任務都需要排隊,前一個任務結束,才會執行后一個任務。如果前一個任務耗時很長,后一個任務就不得不一直等著。 如果排隊是因為計算量大,CPU忙不過來,倒也算了,但是很多時候CPU是閑著的,比如Ajax操作從網絡讀取數據),不得不等著結果出來,再往下執行。 其實主線程完全可以不管Ajax請求,掛起處于等待中的任務,先運行排在后面的任務。等到請求返回了結果,再回過頭,把掛起的任務繼續執行下去。 于是,所有任務可以分成兩種,一種是同步任務(synchronous),另一種是異步任務(asynchronous)。同步任務指的是,在主線程上排隊執行的任務,只有前一個任務執行完畢,才能執行后一個任務;異步任務指的是,不進入主線程、而進入"任務隊列"(task queue)的任務,只有"任務隊列"通知主線程,某個異步任務可以執行了,該任務才會進入主線程執行。 <br> 具體來說,異步執行的運行機制如下。(同步執行也是如此,因為它可以被視為沒有異步任務的異步執行。) (1)所有同步任務都在主線程上執行,形成一個執行棧(execution context stack)。 (2)主線程之外,還存在一個"任務隊列"(task queue)。只要異步任務有了運行結果,就在"任務隊列"之中放置一個事件。 (3)一旦"執行棧"中的所有同步任務執行完畢,系統就會讀取"任務隊列",看看里面有哪些事件。那些對應的異步任務,于是結束等待狀態,進入執行棧,開始執行。 (4)主線程不斷重復上面的第三步。 <br> 下圖就是主線程和任務隊列的示意圖。 ![](https://box.kancloud.cn/7b324ea98928a6097a95deb458e4e05b_581x420.png) 只要主線程空了,就會去讀取"任務隊列",這就是JavaScript的運行機制。這個過程會不斷重復。 <br> 下面我們看一個例子: ``` console.log(1); setTimeout(function (){ console.log(2); }, 0); console.log(3); ``` 下面是這段代碼的執行流程圖: <br> ![](https://box.kancloud.cn/ce1b57f2d3e1f9cb12fb8e7bee140d16_1288x585.png) <br> ![](https://box.kancloud.cn/8ea1af7f9a6a1d2719a0d9c7767276bc_1275x593.png) <br> ![](https://box.kancloud.cn/071e808f743bec8fcbaa69408724394b_1312x574.png) 延時器是外部API,異步的,所以放Web APIs里面執行,不阻塞主線程的調用棧 <br> ![](https://box.kancloud.cn/aa3407ac9ee49165079d17799b1f4d04_1274x577.png) 因為調用棧為空,這個時候```console.log(3)```進主線程的調用棧 <br> ![](https://box.kancloud.cn/cc7e6732d7fb2f3d76263b53c6edc832_1282x563.png) <br> ![](https://box.kancloud.cn/5b203e33463d98fd51d64729e0e2d5c2_1286x577.png) 定時器執行完畢,回調函數進任務隊列 <br> ![](https://box.kancloud.cn/5e8173916ed272f5ba53ed2e28871c92_1290x576.png) 事件循環會不斷的檢測調用棧以及隊列是否有東西,這個時候它發現調用棧為空,隊列又有任務,所以回調函數進主線程的調用棧 <br> ![](https://box.kancloud.cn/13550c9943beb5b4ed51271c126c3276_1344x570.png) 回調函數1執行后就執行```console.log(2)```,```console.log(2)```進調用棧 <br> ![](https://box.kancloud.cn/102aa1ded5888aeeeca2cf257ddc9c79_1346x553.png) <br> ![](https://box.kancloud.cn/5de37b21ed9904b3266862c45c75c7c5_1320x556.png) <br> > 主線程調用棧從"任務隊列"中讀取事件并執行,這個過程是循環不斷的,所以整個的這種運行機制又稱為Event Loop(事件循環)。 <br> <br> <br> ``` for (var i = 1; i <= 3; i++) { setTimeout(function () { console.log(i); }, 0); } ``` <br> ![](https://box.kancloud.cn/6efa07d55bd9a0ecaebe8b73bcd008bb_1392x562.png) <br> ``` for (var i = 1; i <= 3; i++) { if(i == 1){ setTimeout(function () { console.log(i); }, 100); } if(i == 2){ setTimeout(function () { console.log(i); }, 50); } if(i == 3){ setTimeout(function () { console.log(i); }, 150); } } ``` ![](https://box.kancloud.cn/c8a841d07267426a04ab4fbe26a20851_1379x546.png) ## 宏任務與微任務 宏任務有:settimeout、setInterval 微任務有:Promise 事件環檢測隊列,如果有微任務,那么微任務一定比宏任務先執行,如果微任務隊列清空了,才開始執行宏任務 <br> ### 經典例題1 ``` setTimeout(function () { console.log(1); Promise.resolve().then(() => { console.log(3); }); }, 0); Promise.resolve().then(() => { console.log(2); setTimeout(function () { console.log(4); }, 0); }); ``` 定時器1的回調1進宏任務隊列,promise2的回調2進微任務隊列,因為微任務比宏任務快,所以先打印2,然后執行定時器4,回調4排在回調1后面,然后回調2執行完畢,微任務清空完畢,宏任務的回調1開始打印1,然后回調3進微任務隊列,有微任務就執行微任務打印3,最后打印4。 答案:2 1 3 4 <br> ### 經典例題2 ``` setTimeout(function () { console.log(1); Promise.resolve().then(() => { console.log(2); }); }, 0); Promise.resolve().then(() => { console.log(3); Promise.resolve().then(() => { console.log(4); Promise.resolve().then(() => { console.log(5); }); }); setTimeout(function () { console.log(6); }, 0); }); ``` <br> ### 經典例題3 ``` setTimeout(function () { console.log(1); Promise.resolve().then(() => { console.log(2); }); }, 0); ### 經典例題3 Promise.resolve().then(() => { console.log(3); Promise.resolve().then(() => { console.log(4); setTimeout(function () { console.log(5); }, 0); }); Promise.resolve().then(() => { console.log(6); }); }); ``` <br> ### 拓展 ``` Promise.resolve().then(() => { console.log(1); }); // vue的nextTick是最快的微任務 this.$nextTick(() => { console.log(2); }); ``` <br> ### 經典例題4 ``` setTimeout(function () { console.log(1); }, 0); this.$axios.post('/users/signin', { account:'admin', password:'admin' }).then(res => { console.log(2); }); ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看