本文已参与[新人创作礼]活动,一起开启掘金创作之路
如想深入了解请参考:
JS单线程
在 JavaScript 中我们听到最多的词可能就是所谓的“单线程”,所以导致了在 JS 中所谓的异步并行模型和许多后台语言是不同的。简而言之,虽然 JavaScript 是在单线程中去执行所有的操作,但它会基于事件循环(EventLoop)的过程去实现所谓的“异步”,从而给我们造成多线程的感觉。
Event Loop
在JavaScript中,任务被分为两种,一种宏任务(MacroTask)也叫Task,一种叫微任务(MicroTask)
宏任务
script全部代码、setTimeout、setInterval、setImmediate。
微任务
Process.nextTick(Node独有)、Promise
浏览器中的Event Loop
Javascript 有一个 main thread 主线程和 call-stack 调用栈(执行栈),所有的任务都会被放到调用栈等待主线程执行。
JS调用栈
JS调用栈采用的是后进先出的规则,当函数执行的时候,会被添加到栈的顶部,当执行栈执行完成后,就会从栈顶移出,直到栈内被清空。
同步任务和异步任务
Javascript单线程任务被分为同步任务和异步任务,同步任务会在调用栈中按照顺序等待主线程依次执行,异步任务会在异步任务有了结果后,将注册的回调函数放入任务队列中等待主线程空闲的时候(调用栈被清空),被读取到栈内等待主线程的执行。
事例
实例1
<body>
<script>
//ES6新增了promise对象,那任务就不能简单的分为同步任务和异步任务了.
//那要如何划分:
//同步任务:
//宏任务: script标签 计时器 事件 ajax请求(axios本质)
//微任务: then await
//事件循环:
//1.进入到script标签,就进入到了第一次事件循环.
//2.找到同步任务
//3.找到宏任务,放入到宏任务队列里.
//4.找到微任务,放入到微任务队列里.
//5.先执行完这一次事件循环的所有同步任务,再依次的去执行微任务,微任务队列清空了就表示这一次事件循环结束了.
//6.去宏任务队列中找一个任务出来.进入到第二次事件循环
//... ..... ......
//依次反复知道清空宏任务队列,那就结束了.
console.log(1);
setTimeout(() => {
console.log(2);
new Promise((resolve, reject) => {
console.log(3);
resolve();
console.log(4)
}).then(res => {
console.log(5);
})
console.log(6)
}, 0)
console.log(7);
new Promise((resolve, reject) => {
console.log(8);
resolve();
console.log(9)
}).then(res => {
console.log(10);
})
</script>
</body>
实例2
<body>
<script>
console.log(1)
setTimeout(function () {
console.log(2)
}, 0)
const p = new Promise((resolve, reject) => {
resolve(1000)
})
p.then(data => {
console.log(data)
})
console.log(3)
</script>
</body>
实例3
<body>
<script>
console.log(1)
setTimeout(function () {
console.log(2)
new Promise(function (resolve) {
console.log(3)
resolve()
}).then(function () {
console.log(4)
})
})
new Promise(function (resolve) {
console.log(5)
resolve()
}).then(function () {
console.log(6)
})
setTimeout(function () {
console.log(7)
new Promise(function (resolve) {
console.log(8)
resolve()
}).then(function () {
console.log(9)
})
})
console.log(10)
</script>
</body>
实例4
<body>
<script>
console.log(1)
setTimeout(function () {
console.log(2)
}, 0)
const p = new Promise((resolve, reject) => {
console.log(3)
resolve(1000) // 标记为成功
console.log(4)
})
p.then(data => {
console.log(data)
})
console.log(5)
</script>
</body>
实例5
<body>
<script>
new Promise((resolve, reject) => {
resolve(1)
new Promise((resolve, reject) => {
resolve(2)
}).then(data => {
console.log(data)
})
}).then(data => {
console.log(data)
})
console.log(3)
</script>
</body>
实例6
<body>
<script>
setTimeout(() => {
console.log(1)
}, 0)
new Promise((resolve, reject) => {
console.log(2)
resolve('p1')
new Promise((resolve, reject) => {
console.log(3)
setTimeout(() => {
resolve('setTimeout2'); //'混淆你的'
console.log(4)
}, 0)
resolve('p2')
}).then(data => {
console.log(data); //'p2'
})
setTimeout(() => {
resolve('setTimeout1'); //'混淆你的'
console.log(5)
}, 0)
}).then(data => {
console.log(data); //'p1'
})
console.log(6)
</script>
</body>
实例7
<body>
<script>
console.log(1);
async function fnOne() {
console.log(2);
await fnTwo(); // 右结合先执行右侧的代码, 然后等待
console.log(3);
}
async function fnTwo() {
console.log(4);
}
fnOne();
setTimeout(() => {
console.log(5);
}, 2000);
let p = new Promise((resolve, reject) => { // new Promise()里的函数体会马上执行所有代码
console.log(6);
resolve();
console.log(7);
})
setTimeout(() => {
console.log(8)
}, 0)
p.then(() => {
console.log(9);
})
console.log(10);
</script>
<script>
console.log(11);
setTimeout(() => {
console.log(12);
let p = new Promise((resolve) => {
resolve(13);
})
p.then(res => {
console.log(res);
})
console.log(15);
}, 0)
console.log(14);
</script>
</body>