棧和隊列
- 棧(Stack):是一種後進先出的數據結構,進出口在同一個端口;
function a(){
console.log('a')
function b(){
console.log('b');
function c(){
console.log('c');
}
c();
}
b();
}
a();
// => a b c
// 函數調用順序是a b c, 而作用域銷燬的過程依次是c b a
- 堆(Queue):又叫隊列,是一種先進先出的數據結構,進出口在不同的端口。
// 隊列(堆)執行時按照放置的順序依次執行
// 先進先出
setTimeout(function(){
console.log(1)
});
setTimeout(function(){
console.log(2)
});
setTimeout(function(){
console.log(3)
});
// => 1 2 3
瀏覽器事件環
-
宏任務和微任務
macrotask:
setTimeout
,setInterval
,事件
,script,ajax
,MessageChannel
,
setImmediate(IE)
,MessageChannel
,I/O
,requestAnimationFrame
microtask:
promise.then()
、MutationObserver
- 執行順序
// 宏 異步1
setTimeout(() => {
console.log('setTimeout1');
// 微 異步
Promise.resolve().then(data => {
console.log('then3');
});
},1000);
// 微 異步2
Promise.resolve().then(data => {
console.log('then1');
});
// 微 異步3
Promise.resolve().then(data => {
console.log('then2');
// 宏 異步4
setTimeout(() => {
console.log('setTimeout2');
},1000);
});
// 同步
console.log(2);
// 2 then1 then2 setTimeout1 then3 setTimeout2
- 先執行棧中的內容,也就是同步代碼,所以2被輸出出來;
- 然後清空微任務,所以依次輸出的是 then1 then2;
- 因代碼是從上到下執行的,所以1s後 setTimeout1 被執行輸出;
- 接着再次清空微任務,then3被輸出;
- 最後執行輸出setTimeout2
// 宏 異步
setTimeout(() => {
console.log(2);
// 微 異步
Promise.resolve().then(() => {
console.log(6);
});
}, 0);
// 微 異步
Promise.resolve(3).then((data) => {
console.log(data);
return data + 1;
// 微 異步
}).then((data) => {
console.log(data)
// 宏 異步
setTimeout(() => {
console.log(data + 1)
return data + 1;
}, 1000)
// 微 異步
}).then((data) => {
console.log(data);
});
// 3 4 undefined 2 6 5
// 宏 異步
setTimeout(() => {
console.log(1);
// 微 異步
Promise.resolve().then(data => {
console.log(2);
});
}, 0);
// 微 異步
Promise.resolve().then(data => {
console.log(3);
// 宏 異步
setTimeout(() => {
console.log(4)
}, 0);
});
// 同步
console.log('start');
// start 3 1 2 4
// 宏 異步
setTimeout(function () {
console.log(1);
// 微 異步
Promise.resolve().then(function () {
console.log(2);
});
});
// 宏 異步
setTimeout(function () {
console.log(3);
});
// 微 異步
Promise.resolve().then(function () {
console.log(4);
});
// 同步
console.log(5);
//5 4 1 2 3
// 宏 異步
setTimeout(() => {
console.log('A');
}, 0);
var obj = {
func: function () {
// 宏 異步
setTimeout(function () {
console.log('B')
}, 0);
// 同步
return new Promise(function (resolve) {
console.log('C');
resolve();
})
}
};
// 微 異步
obj.func().then(function () {
console.log('D')
});
// 同步
console.log('E');
// C E D A B
node事件環
- 宏任務和微任務
macrotask:
setTimeout
,setInterval
,setImmediate
,I/O
microtask:
promise.then
,process.nextTick
- 執行順序
Node中是先執行主棧中的代碼,執行完,先清空一輪微任務,再執行宏任務隊列中的第1個,把宏任務執行了,再次去清空微任務
setTimeout(()=>{
console.log("timer1")
Promise.resolve().then(data=>{
console.log("then1")
})
})
Promise.resolve().then(data=>{
console.log("then2")
setTimeout(()=>{
console.log("timer2")
})
})
Promise.resolve().then(data=>{
console.log("then3")
})
// then2 then3 timer1 then1 timer2
setTimeout(()=>{
console.log("timer1")
Promise.resolve().then(data=>{
console.log("then3")
})
})
setTimeout(()=>{
console.log("timer2")
})
Promise.resolve().then(data=>{
console.log("then1")
})
Promise.resolve().then(data=>{
console.log("then2")
})
// then1 then2 timer1 then3 timer2
// then1 then2 timer2 timer1 then3
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')
})
})
// 1 7 6 8 2 4 9 3 11 10 5 12