JavaScript 是单线程的,也就是说,同一个时刻,JavaScript 只能执行一个工作,其余工作只能期待。
1. 为什么 JavaScript 是单线程的?
js 是运行于浏览器的脚本语言,因其常常波及操作 dom,如果是多线程的,也就意味着,同一个时刻,可能执行多个工作。
试想,如果一个线程批改 dom,另一个线程删除 dom,那么浏览器就不晓得该先执行哪个操作。
所以 js 执行的时候会依照一个工作一个工作来执行。
2. 为什么工作要分为同步工作和异步工作?
试想一下,如果 js 的工作都是同步的,那么遇到定时器、网络申请等这类型须要延时执行的工作会产生什么?
页面可能会瘫痪,须要暂停下来期待这些须要很长时间能力执行结束的代码
所以,又引入了异步工作。
- 同步工作:同步工作
不须要期待
可立刻看到执行后果,比方 console - 异步工作:异步工作
须要期待
肯定的时候能力看到后果,比方 setTimeout、网络申请
异步工作,又能够细分为宏工作和微工作。上面列举目前学过的宏工作和微工作。
工作(代码) | 宏 / 微 工作 | 环境 |
---|---|---|
script | 宏工作 | 浏览器 |
事件 | 宏工作 | 浏览器 |
网络申请(Ajax) | 宏工作 | 浏览器 |
setTimeout() 定时器 | 宏工作 | 浏览器 / Node |
fs.readFile() 读取文件 | 宏工作 | Node |
Promise.then() | 微工作 | 浏览器 / Node |
他们的执行过程是怎么的呢?
比方去银行排队办业务,每个人的业务就相当于是一个宏工作;
比方一个人,办的业务有存钱、买纪念币、买理财产品、办信用卡,这些就叫做微工作。
执行程序:
概念
1. 宏工作:以后调用栈中执行的代码成为宏工作。(主代码快,定时器等等)。
2. 微工作: 以后(此次事件循环中)宏工作执行完,在下一个宏工作开始之前须要执行的工作, 能够了解为回调事件。(promise.then,proness.nextTick 等等)。
3.宏工作中的事件放在 callback queue 中,由事件触发线程保护;微工作的事件放在微工作队列中,由 js 引擎线程保护。
事件循环(Event Loop)
事件循环就是一个在 “JavaScript 引擎期待工作 “,” 执行工作 “ 和 ” 进入休眠状态期待更多任务“ 这几个状态之间转换的有限循环。
引擎的个别算法:
-
当有工作时:
- 从最先进入的工作开始执行。
- 休眠直到呈现工作,而后转到第 1 步。
常见面试题
1.
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)
// 运行后果: 1, 3, 1000, 2
面试题剖析:
先剖析有几次事件循环? 有两次事件循环: 第一次先运行 script 标签外面的内容, 在执行栈中运行后, 先打印的是 1, 3; 在运行过程中遇到的微工作是要加到微工作队列外面期待, 当执行栈中的工作运行完后, 在执行微工作, 即打印 1000, 此时第一次循环完结, 第二次循环在执行栈中运行定时器, 则最总输入后果是:1, 3, 1000, 2
2.
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)
// 运行后果 : 1 5 10 6 2 3 4 7 8 9
3.
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)
// 运行后果: 1 3 4 5 1000 2
4.
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)
})
setTimeout(() => {resolve('setTimeout1')
console.log(5)
}, 0)
}).then(data => {console.log(data)
})
console.log(6)
// 运行后果: 2 3 6 p2 p1 1 4 5
能够做一下题, 增强了解