目录
-
js单线程
- JavaScript是单线程的语言 , 也就是同一个时间只能做一件事 , 而随之而来的就是为什么JavaScript不能是多个线程呢?
- JavaScript作为浏览器脚本语言 , 主要是与用户互动, 以及操作DOM节点 , 而这就决定了它只能是单线程 , 否则会带来复杂的同步问题
- 例如 : 如果个线程在某个DOM节点上添加内容 , 而另一个线程删除了这个节点 , 那么浏览器以哪个为准 ? 亦或者发送Ajax请求 , 一个请求是增加文章 , 而另一个是删除文章 , 以哪个为准 . 所以为了避免复杂性 , 从一诞生 , JavaScript就是单线程 , 这是这门语言的核心特征
- 单线程就意味着 , 所有的任务需要排队 , 前一个任务结束之后才会执行后一个任务, 但如果前一个任务是一个时间很长的计时器或者一个点击事件 , 后一个任务就不得不一直等着.
- 而设计者意识到这个问题 , 于是 , 所有的任务分为两种 , 同步任务和异步任务
-
同步任务和异步任务
- 同步任务是指 : 在主线程上排队执行的任务 , 只有前一个任务执行完毕 , 才能执行后一个任务
- 异步任务指的是: 不进入主线程 , 而进入到任务队列(事件队列) , 只有任务队列通知主线程, 某个异步任务可以执行了 , 该任务才会进入主线程执行
- 同步任务 : for , if , new promise ...语句 , new promise对象里面的简单语句(不涉及异步任务)表现为同步任务
- 异步任务 : 定时器 , 点击事件 , 网络请求(Ajax)
- 异步任务又分为: 宏任务和微任务
-
事件循环
- 具体来说 , 异步执行的运行机制如下
- 所有的同步任务都在主线程执行 , 形成一个执行栈
- 主线程之外 , 还存在一个任务队列 , 只要异步任务有了允许结果 , 就在任务队列之中放置一个事件
- 只要执行栈中的所有的同步任务执行完毕 , 系统就会读取任务队列,看看里面都有哪些事件, 那些对应的异步任务 , 于是结束等待状态 , 进入执行栈,开始执行
- 主线程不断重复上面的三步
- 主线程从任务队列中读取事件 , 这个过程是循环不断的 , 所以整个的这种运行机制又称为Event Loop(事件循环)
- 具体来说 , 异步执行的运行机制如下
-
宏任务和微任务
- JavaScript 把任务队列分为宏任务队列和微任务队列
- 宏任务: 消息队列中的任务称为宏任务
-
整个script标签
-
异步 Ajax 请求、
-
setTimeout、setInterval、
-
文件操作
-
其它宏任务
-
- 微任务 : 由 js 引擎自身提供的是微任务
-
Promise.then
-
process.nextTick
-
-
- 每个宏任务都有一个微任务队列 , 在宏任务结束前会执行微任务里面的任务.
- 如果在执行宏任务的过程中 , 产生了新的微任务 , 同样会将该微任务添加到微任务队列中
- 也就是说在执行微任务过程中产生的新的微任务并不会推迟到下个宏任务中执行 , 而是在当前的宏任务中继续执行 , 直到执行完所有微任务之后,再继续执行下一个宏任务。
-
具体例子
-
下面例子可以判断你自己掌握多少
-
// 同步任务 console.log(1) // 只要看到了加了时间, 那么一定是等时间满足了, 才会加入到队列中 setTimeout(() => { console.log(2) // 异步任务 宏任务 }, 1000) setTimeout(() => { console.log(4) // 异步任务 宏任务 }, 0) console.log(3) // 同步任务 // 打印 1 3 4 2
-
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
-
console.log(1) // 同步任务 01 setTimeout(function() { console.log(2) new Promise(function(resolve) { console.log(3) resolve() }).then(function() { console.log(4) }) }) // new promise里面的同步任务可以直接执行 new Promise(function(resolve) { console.log(5) // 同步任务 02 resolve() // 微任务 先排队ing (主线程执行栈执行完毕 , 开始微任务) console.log(1) // 同步任务 01 setTimeout(function() { console.log(2) new Promise(function(resolve) { console.log(3) resolve() }).then(function() { console.log(4) }) }) // new promise里面的同步任务可以直接执行 new Promise(function(resolve) { console.log(5) // 同步任务 02 resolve() // 微任务 先排队ing (主线程执行栈执行完毕 , 开始微任务) // console.log(11) // 就算下面有 也直接执行完5 然后11 }).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) // 同步任务 03 // 打印 1 5 10 6 2 3 4 7 8 9 }).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) // 同步任务 03 // 打印 1 5 10 6 2 3 4 7 8 9
-
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)
-
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) // 3 2 1
-