Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 日韩欧美久久一区二区,日韩中文字幕一区,男女拍拍拍免费视频网站

          整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          JS執行上下文的兩個階段做了些啥?

          咱們開始之前,有個問題大家可以一起討論: JS是解釋語言還是編譯語言?

          (JS)是一種解釋語言,有自己的編譯器形式,運行在JS引擎中。

          每個web瀏覽器都有自己的JS引擎形式,盡管目的一樣。Chrome 有 v8, Mozilla 有 spider monkey等,JS引擎只是將JS源代碼轉換成編譯器能夠理解的語言,然后執行它。

          執行上下文

          JS 代碼運行的環境構成了執行上下文,執行上下文決定哪段代碼可以訪問變量、函數、對象等。

          1.全局執行上下文

          任何時候碼第一次運行,或者當代碼不在任何函數中時,它都會進入全局執行上下文。在整個代碼執行過程中只有一個全局執行上下文。

          對于瀏覽器全局執行上下文,它做兩件事:

          1. 創建window對象。
          2. 將 this 指向了 windw 對象 (非嚴格模式)

          2. 函數執行上下文

          當函數執行時,它就創建一個新的函數執行上下文,可以有任意數量的函數執行上下文。

          執行堆棧/調用堆棧

          瀏覽器中JS解器是單線程,同一時間只能干一件事。代碼中有一個全局的執行上下文和無數個函數執行上下文,那么他們是按什么順序執行的呢?

          這里就需要一個 執行上下文棧 的概念了,JS引擎是通過創建執行上下文棧來管理執行上下文的。這里可以把執行上下文棧描述為一個存著函數調用的棧結構,執行順序遵循先進后出的原則,也就是說一個函數的執行上下文,在函數執行完畢之后,會被移除執行上下文棧。

          每當腳本在瀏覽器中加載時,堆棧中的第一個元素就是全局執行上下文。然而,當一個函數執行時,將創建一個執行上下文,并將其虛擬的放置在全局執行上下文之上。函數一旦執行完畢,就會從執行堆棧中彈出并將控制權交給到它下面的上下文中。

          咱們舉個例子,來模擬上述的過程:

          步驟1:當上述代碼加載到瀏覽器中時,JS引擎創建一個全局執行上下文(global execution context )并將其推入當前執行堆棧。

          步驟2:假設最后執行func1()調用,然后JS引擎為該函數創建一個新的執行上下文(function execution context),并將其推到全局執行上下文的頂部。

          步驟3:在func1()中,咱們調用了func2(),因此JS引擎為該函數創建一個新的執行上下文,并將其推到func1()執行上下文的頂部。

          步驟4:當func2()函數結束時,它的執行上下文從當前堆棧中彈出,控制權交給它下面的執行上下文,即func1()函數的執行上下文。

          步驟5:當func1()函數結束時,它的執行堆棧將從堆棧中刪除,控制權交給全局執行上下文。執行完所有代碼后,JS 引擎將從當前堆棧中刪除全局執行上下文。

          執行上下文階段

          執行上下文主要有兩個階段。

          1. 創建
          2. 執行

          創建階段

          函數創建時做的三件事:

          1.首先,為用域鏈內的每個函數或變量構建到外部環境的連接。告訴執行上下文它應該包含什么,以及它應該在哪里查找解析函數引用和變量值的方法。

          • 對于全局環境,外部環境為null。然而,全局環境內的所有環境都是以全局環境作為其外部環境的。
          • 例如:如果函數a包含在函數b中,這意味著a有一個外部環境b。

          2.接著,通過掃描作用鏈,創建一個環境記錄,其中全局上下文的創建和引用(web瀏覽器中的window)、變量、函數和函數參數都在內存中完成。

          3.最后,在第一步中創建的每個執行上下文中確定this的值(對于全局執行上下文,this指向的是window)。

          因此,咱們可以將創建階段表示為

          創建階段 = {
            scopeChain: {
                  /* 作用域鏈解析 */ 
              },    
            variableObject: {
                  /* arguments, 函數參數, 內部變量 等等*/ 
              },
            this: {},
          }

          variableObject: 初始化函數的參數variableObject,提升函數聲明和變量聲明。

          scopeChain: 在執行上下文的創建階段,作用域會在變量對象創建之后創建。作用域鏈本身包括變量對象。作用域負責解析變量,當被要求解析變量的時候,會從代碼嵌套結構的最內層開始,如果在最內層沒有找到對應變量,則依次向父級作用域中進行查找,直到尋找到最外層作用域。

          this: 確定this的指向,這里需要注意的事this的值是在執行的時候確定的,在定義的時候并不會確定。

          執行階段

          這是代碼開始在創建階段形成的執行上下文中運行的階段,并逐行分配變量值。

          在執行開始時,JS 引擎在其創建階段對象中尋找執行函數的引用。如果不能在自己的作用域內找到它,它將繼續向上查找,直到到達全局環境。

          如果在全局環境中沒有找到引用,它將返回一個錯誤。但是,如果找到了一個引用,并且函數執行正確,那么這個特定函數的執行上下文將從堆棧中彈出,JS 引擎將移動到下一個函數,在那里,它們的執行上下文將被添加到堆棧中并執行,依此類推。

          咱們通過示例查看上面的兩個階段,以便更好地理解它。

          1111

          在創建階段,全局執行上下文類似于這樣

          globalExecutionObj = {
              outerEnvironmentConnection: null,
              variableObjectMapping: {
                  name: uninitialized,
                  title: undefined,
                  date: uninitialized,
                  func1: func,
              },
              this: window //Global Object
          }

          **注意:**上面,let (name)和const (date)定義的變量在創建階段沒有任何關聯的值,但是var (title)定義的變量會被設置為undefined。

          這就是為什么咱們可以在聲明var定義的變量之前訪問它們**(雖然沒有定義)**,但是在聲明let和 const變量之前訪問它們時,會得到一個引用錯誤。

          這就是咱們所說的變量提升,即所有使用var的變量聲明都被提升它們的局部作用域(在函數內部聲明)或者全局作用域的頂部(在函數外部聲明的)。

          在執行階段,完成變量分配。所以全局執行上下文在執行階段類似如下:

          globalExectutionObj = {
              outerEnvironmentConnection: null,
              variableObjectMapping: {
                  name: "overflowjs.com",
                  title: "Execution context",
                  date: "5 july 2019",
                  func1: pointer to function func1,
              },
              this: window //Global Object
          }

          **注意:**在執行階段,如果JS引擎在源代碼中聲明位置找不到let變量的值,那么它將為其賦值undefined。

          現在,當func1執行,就會生成一個新的函數執行上下文,其創建階段類似如下:

          func1ExecutionObj = {
              outerEnvironmentConnection: Global,
              variableObjectMapping: {
                 arguments: {
                      0: 10,
                      length: 1
                  },
                  num: 10,
          
                  author: undefined,
                  val: uninitialized,
                  func2: undefined
                  fixed: uninitialized
                  addFive: pointer to function addFive()
              },
              this: Global Object or undefined
          }

          在執行階段類似如下:

          func1ExecutionObj = {
              outerEnvironmentConnection: Global,
              variableObjectMapping: {
                 arguments: {
                      0: 10,
                      length: 1
                  },
                  num: 10,
          
                  author: "Deepak",
                  val: 3,
                  func2: pointer to function func2() 
                  fixed: "Divine"
                  addFive: pointer to function addFive()
              },
              this: Global Object or undefined
          }

          函數執行完成后,將更新全局環境。然后全局代碼完成,程序結束。

          作用域與作用域鏈

          1.作用域

          JavaScript中的作用域分為三種:

          1. 全局作用域
          2. 函數作用域
          3. 塊級作用域(ES6)

          作用域最大的作用就是隔離變量或函數,并控制他們的生命周期。作用域是在函數執行上下文創建的時候定義好的,不是在函數執行的時候定義的。

          2.什么是作用域鏈

          當一個塊或者函數嵌套在另一個塊或函數中時,就發生了作用域的嵌套。在當前函數中如果JS引擎無法找到某個變量,就會往上級嵌套的作用域中去尋找,直到找到該變量或抵達全局作用域,這樣的鏈式關系成為作用域鏈(Scope Chain)。

          來個例子演示一下:

          var scope = 'global';
          
          function checkscope(s) {
              var scope = 'local scope';
              
              function f() {
                  return scope;
              }
              
              return f();
          }
          
          checkScope('scope');

          首先在checkscope函數聲明的時候,內部會綁定一個[[scope]]的內部屬性:

          checkscope.[[scope]] = [
            globalContext.VO
          ];

          接著在checkScope函數在執行之前,創建執行上下文checkscopeContext,并推入執行上下文棧:

          • 賦值函數的[[scope]]屬性初始化作用鏈
          • 創建變量對象
          • 將變量對象壓入作用域鏈的頂端
          // -> 初始化作用域鏈;
          checkscopeContext = {
            scope: [globalContext.VO],
          }
          
          // -> 創建變量對象
          checkscopeContext = {
            scope: [globalContext.VO],
            VO = {
              arguments: {
                0: 'scope',
                length: 1,
              },
              s: 'scope', // 傳入的參數
              f: function f(),
              scope: undefined, // 此時聲明的變量為undefined
            },
          }
          
          // -> 將變量對象壓入作用域鏈的最頂端
          checkscopeContext = {
            scope: [VO, globalContext.VO],
            VO = {
              arguments: {
                0: 'scope',
                length: 1,
              },
              s: 'scope', // 傳入的參數
              f: function f(),
              scope: undefined, // 此時聲明的變量為undefined
            },
          }

          執行階段,修改變量對象里面對應字段的值:

          checkscopeContext = {
            scope: [VO, globalContext.VO],
            VO = {
              arguments: {
                0: 'scope',
                length: 1,
              },
              s: 'scope', // 傳入的參數
              f: pointer to function f(),
              scope: 'local scope', // 變量賦值
            }
          }

          在代碼執行階段,會看到f函數的聲明代碼,給f函數綁定[[scope]]屬性:

          f.[[scope]] = [
            checkscopeContext.VO, // f函數的作用域還包括checkscope的變量對象
            globalContext.VO
          ];

          文本到這就結束了,希望對大伙有所幫助。


          作者:DEEPAK GUPTA 譯者:前端小智 來源:overflowjs.com

          原文:https://overflowjs.com/posts/Javascript-Execution-Context-and-Hoisting.html

          篇文章的目的是為了讓你徹底理解 JavaScript 的執行,如果你到本文最后還沒有理解,你可以揍我一頓。

          無論你是 JavaScript 新手還是老手,無論你是在面試工作,還是只是做常規的開發工作,通常會發現給定幾行代碼,你需要知道要輸出什么以及以什么順序輸出 . 由于 JavaScript 是一種單線程語言,我們可以得出以下結論:

          let a = '1';
          console.log(a);
          let b = '2';
          console.log(b);
          
          

          然而,JavaScript 實際上是這樣的:

          setTimeout(function(){
              console.log('start')
          });
          new Promise(function(resolve){
              console.log('start for');
              for(var i = 0; i < 10000; i++){
                  i == 99 && resolve();
              }
          }).then(function(){
              console.log('start then')
          });
          console.log('end');
          // Following the idea that JS executes in the order in which the statements appear, I confidently write down the output:
          // start
          // start for
          // start then
          // end
          
          

          在 Chrome 上查看它是完全錯誤的

          一、關于 JavaScript

          JavaScript 是一種單線程語言。Web-worker 是在最新的 HTML5 中提出的,但 JavaScript 是單線程的核心保持不變。所以所有 JavaScript 版本的“多線程”都是用單線程模擬的,所有的 JavaScript 多線程都是紙老虎!

          二、JavaScript 事件循環

          由于 JavaScript 是單線程的,它就像一個只有一個窗口的銀行。客戶需要一一排隊辦理業務。

          同樣,JavaScript 任務也需要一個一個地執行。如果一項任務花費的時間太長,則下一項也必須等待。

          那么問題來了,如果我們想瀏覽新聞,但新聞中包含加載緩慢的超高清圖像,我們的網頁是否應該一直卡住直到圖像完全顯示?所以聰明的程序員將任務分為兩類:

          • 同步任務
          • 異步任務

          當我們打開一個網站時,頁面的渲染過程是很多同步任務,比如渲染頁面骨架和頁面元素。

          需要大量時間的任務,比如加載圖片和音樂,都是異步任務。這部分有嚴格的文字定義,但本文的目的是以最小的學習成本徹底理解實現機制,所以我們用一張圖來說明:

          文字要表達的內容:

          同步和異步任務去不同的執行“地方”,同步任務去主線程,異步任務去事件表和注冊函數。

          當指定的事件完成時,事件表將此函數移至事件隊列。

          如果執行后主線程中的任務為空,事件隊列會讀取相應的函數,進入主線程執行。

          這個過程一遍又一遍地重復,稱為事件循環。

          我們怎么知道主線程棧是空的?JavaScript 引擎有一個監控進程,不斷檢查主線程堆棧是否為空,如果是,則檢查 Event Queue 以查看是否有任何函數等待調用。

          說了這么多,不如直接寫一段代碼:

          let data = [];
          $.ajax({
              url:www.javascript.com,
              data:data,
              success:() => {
                  console.log('success!');
              }
          })
          console.log('end');
          
          

          這是一個簡單的ajax請求代碼:

          • ajax 去事件表并注冊回調函數成功。
          • 執行 console.log(‘success’)。
          • ajax Event 完成,回調函數success 進入Event Queue。
          • 主線程從事件隊列中讀取成功并執行。

          相信通過上面的文字和代碼,你對JS的執行順序有了初步的了解。接下來,我們來看看進階話題:setTimeout。

          三、愛恨交加超時

          著名的 setTimeout 無需進一步解釋。setTimeout 的第一印象是異步執行可以延遲,我們經常這樣實現:

          setTimeout(() => {
           console.log(‘Delay 3 seconds’);
          },3000)
          
          

          當 setTimeout 用得越來越多時,問題也出現了。有時函數會在 3 秒的書面延遲后 5 或 6 秒內執行。怎么了?

          讓我們從一個例子開始:

          setTimeout(() => {
              task();
          },3000)
          console.log('console');
          

          按照我們之前的結論,setTimeout是異步的,應該先執行console.log。

          //console
          //task()
          

          去看看吧!這是正確的!然后我們修改之前的代碼:

          復制setTimeout(() => {
              task()
          },3000)
          sleep(10000000)
          
          

          控制臺上的 task() 在 Chrome 中執行需要超過 3 秒的時間。

          此時,我們需要重新思考setTimeout的定義。

          先說上面的代碼是如何執行的:

          • task() 進入事件表并注冊,定時器啟動。
          • 執行sleep,非常慢,非常慢,計時繼續。
          • task()進入Event Queue,但是,sleep太慢無法執行。
          • sleep終于結束了,task()終于從Event Queue執行到主線程。

          上述過程完成后,我們知道setTimeout是一個在指定時間后將任務添加到Event Queue(本例中為task())的函數。

          而且,由于是單線程任務,需要一個一個執行,如果上一個任務耗時過長,我們只能等待。導致實際延遲超過 3 秒。

          SetTimeout(fn,0) 是我們經常遇到的另一個代碼。可以立即完成嗎?

          SetTimeout (fn,0) 指定任務將在主線程上最早可用的空閑時間執行。這意味著一旦堆棧中的所有同步任務完成并且堆棧為空,主線程將立即執行。例如:

          //code1
          console.log('one');
          setTimeout(() => {
              console.log('two')
          },0);
          // result
          // one  
          // two
          //code2
          console.log('one');
          setTimeout(() => {
              console.log('two')
          },3000);
          // result
          // one
          // ... 3s later
          // two
          

          關于 setTimeout 要補充的一點是,即使主線程是空的,0 毫秒實際上也是無法到達的。根據 HTML 標準,最小值為 4 毫秒。有興趣的同學可以自行了解。

          四、恨與愛setInterval

          說了 setTimeout,你不能錯過它的孿生兄弟 setInterval。它們是相似的,只是后者是循環執行。對于執行順序,setInterval 將按指定的時間間隔將注冊的函數放入事件隊列中。如果上一個任務耗時過長,也需要等待。

          唯一需要注意的是,對于 setInterval(fn,ms),我們已經知道不是每 ms 秒執行一次 fn,而是每 ms 秒進入 Event Queue。一旦 setInterval 的回調 fn 花費的時間超過了延遲 ms,時間間隔就完全不可見了。請讀者細細品味這句話。

          五、Promise 和 process.nextTick(callback)

          我們已經看過傳統的計時器,然后,我們將探討 Promise 與 process.Nexttick(回調)的性能。

          Promise 的定義和功能這里就不介紹了,process.nexttick(回調)類似于node.js 版本的“setTimeout”,在事件循環的下一次迭代中調用回調函數。

          我們開始談正事吧。除了廣義的同步和異步任務,我們對任務有更詳細的定義:

          • 宏任務:包括整個代碼腳本、setTimeout 和 setInterval
          • 微任務:Promise、process.nexttick

          不同類型的任務會進入對應的Event Queue。例如,setTimeout 和 setInterval 將進入同一個事件隊列。

          事件循環的順序決定了 JS 代碼的執行順序。輸入整體代碼(宏任務)后,第一個循環開始。然后,執行所有微任務。然后再從宏任務開始,找一個任務隊列完成,然后,執行所有的微任務。如果聽起來有點繞,我們用本文開頭的代碼來說明:

          setTimeout(function() {
              console.log('setTimeout');
          })
          new Promise(function(resolve) {
              console.log('promise');
          }).then(function() {
              console.log('then');
          })
          console.log('console');
          
          • 此代碼作為宏任務進入主線程。
          • 當遇到 setTimeout 時,將其回調函數注冊并分發到宏任務 Event Queue。(注冊過程同上,下面不再贅述)。
          • 然后,遇到一個 Promise,立即執行 New Promise,然后將 then 函數分派到微任務事件隊列中。如果遇到console.log(),立即執行。
          • 好的,整個腳本作為第一個宏任務執行。什么是微任務?我們發現 then 是在 microtask Event Queue 中執行的。
          • 好了,第一輪的 Event loop 已經結束了,讓我們開始第二輪,當然是從宏任務 Event Queue 開始。我們在宏任務Event Queue中找到setTimeout對應的回調函數,立即執行。
          • 結束。

          事件循環、宏任務和微任務的關系如下圖所示:

          讓我們看一些更復雜的代碼,看看你是否真的了解 JS 的工作原理:

          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')
              })
          })
          
          

          第一輪事件循環流程分析如下:

          整個腳本作為第一個宏任務進入主線程,遇到console.log,打印1。

          • 當遇到 setTimeout 時,它的回調函數被調度到宏任務事件隊列。我們稱之為 setTimeout1。
          • 當遇到 process.nexttick() 時,將其回調函數調度到微任務事件隊列中。我們稱它為 process1。
          • 如果遇到 Promise,直接執行新的 Promise,打印 7,然后,分發到微任務 Event Queue,讓我們稱之為then1。
          • 再次遇到setTimeout,它的回調函數被分發到宏任務Event Queue中,我們稱之為setTimeout2。

          • 上表展示了第一輪Event loop的宏任務結束時各個Event Queue的情況。這時候已經輸出了1和7。
          • 我們找到了兩個微任務 process1 和 then1。
          • 執行process1,輸出6。
          • 執行 then1 print 8。

          好了,第一輪事件循環正式結束,本輪結果輸出1,7,6,8。所以第二個時間循環從 setTimeout1 宏任務開始:

          首先,print2。接下來是process.nexttick(),它也被分派到微任務事件隊列中,稱為process2。新的 Promise 立即執行輸出 4,然后也被分發到微任務事件隊列中,記為 then2。

          • 第二輪事件循環宏任務完成,我們發現 process2 和 then2 微任務可以執行。
          • 3的輸出。
          • 5的輸出。
          • 第二個事件循環結束,第二輪輸出2,4,3,5。
          • 第三個事件循環開始,此時只剩下setTimeout2,執行。
          • 所以它只print 9。
          • 將 process.nexttick() 分發到微任務事件隊列。記得process 3。
          • 只需執行 new Promise,print 11。
          • then 分配 microtask Event Queue,記為 then3。

          • 第三輪事件循環宏任務執行完成,執行兩個微任務process3和then3。
          • 10 的輸出。
          • 12的輸出。
          • 第三輪事件循環結束。第三輪輸出9,11,10,12。

          整個代碼,一共經過了3次事件循環,完整的輸出為1,7,6,8,2,4,3,5,9,11,10,12。

          六、寫在最后

          1、異步 JavaScript

          我們從一開始就說過 JavaScript 是單線程語言,無論什么新的框架和語法實現被稱為異步,實際上都是以同步的方式模擬的,所以牢牢掌握單線程很重要。

          2、事件循環

          事件循環是實現異步 JavaScript 的一種方法,也是 JavaScript 的執行機制。

          3、JavaScript的執行和運行

          在 Node.js、瀏覽器、Ringo 等不同的環境中執行和運行 JavaScript 是有很大區別的。雖然運行多指 JavaScript 解析引擎,但它是統一的。

          4、立即設置

          還有許多其他類型的微任務和宏任務,例如 setImmediate,它們不進行中介。

          5、在一天結束時

          JavaScript 是一種單線程語言。事件循環是 JavaScript 的執行機制。

          牢牢把握兩個基本點,以認真學習JavaScript為中心,早日實現成為前端高手的偉大夢想!

          來源: WEB前端開發社區

          在JavaScript的世界里,事件循環(Event Loop)是一個核心概念,它決定了JavaScript代碼的執行順序,尤其是異步代碼。理解事件循環對于編寫高效、響應迅速的JavaScript程序至關重要。本文將深入探討事件循環的原理,并通過實際代碼示例展示其在JavaScript編程中的應用。

          1. 理解事件循環

          1.1 JavaScript的執行模型

          JavaScript有一個基于單線程的事件循環執行模型。這意味著JavaScript代碼在一個單獨的線程上執行,一次只能執行一個任務。為了處理高延遲操作(如I/O),JavaScript采用了異步編程模型。

          1.2 任務隊列

          JavaScript中的任務分為兩種:宏觀任務(macrotasks)和微觀任務(microtasks)。宏觀任務包括例如setTimeout、setInterval、I/O操作等。微觀任務則包括例如Promise的回調、MutationObserver等。

          1.3 事件循環的工作流程

          事件循環的工作流程大致如下:

          1. JavaScript引擎首先執行全局腳本(main script)。
          2. 當執行到異步代碼時(如setTimeout),這些異步操作會被添加到相應的任務隊列中。
          3. 一旦全局腳本執行完畢,事件循環開始工作,首先處理所有完成的微觀任務。
          4. 處理完所有微觀任務后,事件循環選擇一個宏觀任務隊列中的任務,并執行它。
          5. 重復步驟3和4。

          2. 事件循環的實際應用

          2.1 setTimeout和setInterval

          示例代碼:

          console.log('開始');
          
          setTimeout(() => {
            console.log('setTimeout');
          }, 0);
          
          console.log('結束');
          

          輸出順序:開始 -> 結束 -> setTimeout

          2.2 Promise和async/await

          示例代碼:

          console.log('開始');
          
          Promise.resolve().then(() => {
            console.log('Promise');
          });
          
          console.log('結束');
          

          輸出順序:開始 -> 結束 -> Promise

          2.3 宏觀任務和微觀任務的交互

          示例代碼:

          console.log('開始');
          
          setTimeout(() => {
            console.log('setTimeout 1');
            Promise.resolve().then(() => {
              console.log('Promise 1');
            });
          }, 0);
          
          setTimeout(() => {
            console.log('setTimeout 2');
          }, 0);
          
          Promise.resolve().then(() => {
            console.log('Promise 2');
          });
          
          console.log('結束');
          

          輸出順序:開始 -> 結束 -> Promise 2 -> setTimeout 1 -> Promise 1 -> setTimeout 2

          3. 事件循環的性能考量

          雖然事件循環使得JavaScript能夠高效地處理異步操作,但在編寫代碼時,應避免過多地使用微觀任務,特別是在性能敏感的應用中。此外,理解事件循環對于調試異步代碼也非常重要。

          總結

          事件循環是JavaScript中一個核心的概念,它決定了異步代碼的執行順序。通過理解事件循環,我們可以更有效地編寫和管理異步操作,從而創建響應迅速且高效的JavaScript程序。在實際應用中,無論是使用setTimeout、Promise,還是async/await,事件循環都扮演著至關重要的角色。然而,在享受事件循環帶來的便利的同時,也需要注意性能和代碼結構的問題,確保程序的高效運行和可維護性。


          主站蜘蛛池模板: 精品国产一区二区三区久久狼 | 在线观看一区二区三区视频| 亚洲AV无码一区二区三区性色| 国产精品第一区揄拍无码| 精品中文字幕一区在线| 精品一区二区三区在线成人| 一区二区三区国产| 日韩一区二区三区在线观看| 国产在线一区观看| 精品无码国产一区二区三区麻豆| 人妻AV中文字幕一区二区三区| 综合无码一区二区三区| 日韩在线一区二区三区免费视频| 香蕉久久ac一区二区三区| 在线观看亚洲一区二区| 日韩人妻一区二区三区蜜桃视频| 一区二区三区影院| 久久精品国产第一区二区| 人成精品视频三区二区一区| 精品视频一区二区观看| 国产视频一区在线播放| 日韩一区二区三区在线| 国产aⅴ精品一区二区三区久久| 欧美av色香蕉一区二区蜜桃小说| 国内精品一区二区三区东京| 无码国产精品一区二区免费虚拟VR | 国产福利电影一区二区三区,日韩伦理电影在线福 | 在线观看国产区亚洲一区成人| 激情综合丝袜美女一区二区| 国产成人一区二区在线不卡| 国产成人高清亚洲一区久久| 精品成人一区二区三区免费视频| 人妻在线无码一区二区三区| 在线观看中文字幕一区| 亚洲国产综合精品一区在线播放| 中文字幕一区二区三区四区 | 一区二区三区四区在线视频| 一区二区三区四区电影视频在线观看| 日亚毛片免费乱码不卡一区| 丰满爆乳一区二区三区| 亚洲影视一区二区|