js的內存機制-棧,堆

棧存儲

棧:6種基本數據類型,string,number,null, undefined, bool, symbolajax

特色:按值訪問
存貯的值的大小固定
由系統自動分配內存空間
空間小,運行效率高
先進後出,後進先出 棧中的DOM,ajax,setTimeout會依次進入到隊列中,當棧中代碼執行完畢後,再將隊列中的事件放到執行棧中依次執行。promise

const a = 20;
 let b = a;
 b = 30;
 console.log(a, b); // 20, 30
 //棧存儲,棧裏存了個a 20,將a的值賦值給b,此時棧裏存了a 20, b 20,而後改變b的值爲30,此時棧裏存的是a 20,b 30
複製代碼

堆存儲

堆:引用數據類型-object,arr
特色:存儲引用數據類型 按引用訪問 存儲的值大小不定,可動態調整 主要用來存放對象 空間大,可是運行效率相對較低 無序存儲,可根據引用直接獲取bash

const m = {a: 10, b: 20};
const n = m; 
n.a = 20;console.log(m,n) // {a: 20, b: 20,} {a: 20, b: 20}

複製代碼

eg:const obj = {a: 1, b: 2}; 
堆內存中存儲的是{a: 1, b: 2};而棧內存中存儲obj,棧內存中變量名obj對應的值指向與堆內存中的{a: 1, b: 2}
複製代碼

js不容許直接操做堆內存中的值,因此當咱們要訪問堆內存中的數據的時候,咱們訪問的是存儲在棧內存中的指針,而後再從堆內存中獲取數據異步

const obj = {
      arr: [2,3,5,6],
    };
let c = obj.arr;
const d = {arr: obj.arr,};c.splice(0, 1);
console.log(c, d); // [3,5,6] [3,5,6] obj.arr存儲在堆中,不管賦值多少次,改變的都是指針的引用,因此d的值相應的也被改變
複製代碼
// d值不被改變,就須要轉換一下
const obj = {
      arr: [2,3,5,6],
    };
let c = obj.arr; const d = {arr: [...obj.arr],};c.splice(0, 1);
console.log(c, d) // [3,5,6], [2,3,5,6]
const obj = {
      arr: [2,3,5,6],
    };
let c = obj.arr; const d = {arr: JSON.parse(JSON.stringify(obj.arr)),};c.splice(0, 1);
console.log(c, d) // [3,5,6], [2,3,5,6]
複製代碼

看下圖加深理解

看一下下面的幾個例子,打印出來的是什麼?

eg1:
console.log('script start');

setTimeout(function() {
  console.log('setTimeout');
}, 0);

Promise.resolve().then(function() {
  console.log('promise1');
}).then(function() {
  console.log('promise2');
});

console.log('script end');
複製代碼

首先任務進入執行棧,先執行打印出script start script end ,而後setTimeout是一個宏任務,會被放進隊列裏,Promise是一個微任務,也會被放進隊列裏,當主線程內的任務執行完畢爲空,會將隊列中的放進去,而後遵循這先進後出,後進先出的原則,先打印出promise1 promise2 因此結果爲: script start script end promise1 promise2 setTimeout函數

eg2:
console.log(1)

setTimeout(function(){
    console.log(4);
})
let promise2 = new Promise(function(resolve,reject){
    console.log(3)
    resolve(100)
}).then(function(data){
    console.log(100)
})
console.log(2)
// 1 3 2 100 4
setTimeout是宏任務,而Promise.then是微任務 這裏的new Promise()是同步的,因此是當即執行的。
複製代碼
  • 任務進入執行棧-》判斷是同步任務仍是異步任務-》
  • 同步-》進入主線程-》任務所有執行完畢-》讀取任務隊列中的結果,進入主線程執行
  • 異步-》進入事件表-》註冊回調函數-》進入事件隊列-》讀取任務隊列中的結果,進入主線程執行
  • 意思:同步和異步任務分別進入不一樣的執行"場所",同步的進入主線程,異步的進入Event Table並註冊函數 當指定的事情完成時,Event Table會將這個函數移入Event Queue。 主線程內的任務執行完畢爲空,會去Event Queue讀取對應的函數,進入主線程執行。 上述過程會不斷重複,也就是常說的Event Loop(事件循環)。
結論:棧裏的代碼永遠先執行,而後再從隊列中加入事件,依次執行

微任務與宏任務

微任務:原生promise

宏任務 setTimeout,script,setInterval,setImmediate

微任務和宏任務都屬於隊列,不屬於棧中,先執行宏任務,將宏任務放入事件表eventqueue中,而後執行微任務,將微任務放入eventqueue中,當往外面拿的時候先從微任務裏拿這個回調函數,而後再從宏任務的queue上面拿宏任務的回調函數(先進後出)oop

  • setTimeout這個函數,是通過指定時間後,把要執行的任務加入到事件隊列中,又由於是單線程任務須要一個一個執行,若是前面的任務須要的時間過久,那隻能等,致使真正的延遲時間遠遠大於本身設定的
  • setTimeout(Fn, 0);不表明當即執行,指定某個任務在主線程最先可得的空閒時間執行,只要主線程執行棧內的同步任務所有完成,棧爲空就立刻執行。
相關文章
相關標籤/搜索