【Javascript】探究javascript中的堆/棧/任務隊列與併發模型 event loop的關係

堆/棧/隊列

在javascript中,存在調用棧 (call stack)內存堆(memory heap) ,程序中函數依次進入棧中等待執行,若執行時遇到異步方法,該異步方法會被添加到用於回調的任務隊列(task queue)中,【即JavaScript執行引擎的單線程擁有一個調用棧、內存堆和一個任務隊列】javascript

調用棧 (call stack):CallStack是用來處理函數調用與返回的。特色是先進後出,每次調用一個函數,Javascript運行時會生成一個新的調用結構壓入CallStack。而函數調用結束返回時,JavaScript運行時會將棧頂的調用結構彈出。因爲棧的LIFO特性,每次彈出的必然是最新調用的那個函數的結構。函數調用會造成了一個堆棧幀,存放基本數據類型的變量java

內存堆(memory head):引用數據類型被存放在堆中,在咱們進行淺複製時,咱們改變的只是引用數據類型在棧內存中的引用地址,實際上它在堆內存中的引用地址仍然沒有發生變化git

任務隊列(task queue):javaScript 運行時包含了一個待處理的任務隊列。github

併發模型 與 EventLoop

javascript引擎是單線程的,它的併發模型基於Event Loop(事件循環)算法

當線程中的同步任務執行完,執行棧爲空時,則從任務隊列(task queue)中取出異步任務進行處理。這個處理過程包含了調用與這個任務相關聯的函數(以及於是建立了一個初始堆棧幀)。當執行棧再次爲空的時候,也就意味着該任務處理結束,從任務隊列中取出下一個異步任務進行處理,不斷重複,這個過程是循環不斷的, 因此整個的這種運行機制又稱爲Event Loop(事件循環).promise

Task Queue 任務隊列

任務隊列有宏任務隊列微任務隊列,

  • 宏任務:script(全局任務), setTimeout, setInterval, setImmediate, I/O, UI rendering.
  • 微任務:process.nextTick, Promise, Object.observer, MutationObserver.
每次事件循環的時候:
  • 微任務/宏任務在相同做用域下,會先執行微任務,再執行宏任務
setTimeout(()=>{
        console.log('timer')
      })
      Promise.resolve('promise').then((res)=>{
        console.log(res)
      })
複製代碼

  • 宏任務處於微任務做用域下,會先執行微任務,再執行微任務中的宏任務
Promise.resolve('promise').then((res)=>{
        console.log(res)
        setTimeout(()=>{
          console.log('timer')
        })
      })
複製代碼

  • 微任務處於宏任務做用域下時,會先執行宏任務隊列中的任務,而後再執行微任務隊列中的任 務,在當前的微任務隊列沒有執行完成時,是不會執行下一個宏任務的。
Promise.resolve('promise1').then((res)=>{
          console.log(res)
          Promise.resolve('promise2').then((res)=>{
            console.log(res)
            Promise.resolve('promise3').then((res)=>{
              console.log(res)
            })
          })
          setTimeout(()=>{
            console.log('timer')
          })
        })
複製代碼

Event loop 在瀏覽器端與NodeJS中的差異 以及 NodeJS中關於setTimeout與setImmediate引起的問題瀏覽器

若是個人文章對你有幫助,歡迎關注個人博客,JS/Python/算法系列,碼不停題!!!
相關文章
相關標籤/搜索