单线程多线程
单线程模型:历史延续,JS是单线程模型,它在同一时间只能执行一个任务,其他的任务在后排队等待。
多线程模型:一次执行多个任务。
你的电脑开了很多的软件,打开任务管理器其实可以看到,这些软件都会开各自的进程,这些进程里有分为很多的线程,这些线程就相当于这个软件里的很多引擎,他们可以同时干着很多的事情。就像你开车一样,方向盘,发动机,空调等等,把汽车比做进程,那这些东西就是线程,他们可以同时干着自己的事情。
js中同步异步
同步:前一个任务结束后再执行后一个任务,程序的执行顺序与任务的排列顺序是一致的,同步的;同步任务都在主线程上执行,形成一个执行栈;
异步:同时执行多个任务,异步任务(大部分异步任务为回调函数)会被放在任务队列当中
js的执行是单线程的,那为什么我们平时看得的几十个接口请求可以同时返回来数据呢?那是因为js执行分为同步和异步,在浏览器分为两个队列,一个是同步队列,一个是异步队列。同步队列一般放那些同步代码的,比如console.log()、var a = 5;等等。异步队列有AJax请求、定时器、事件、回调函数等等。这里顺便提一嘴,服务端一般都是异步的,你想象一下假设服务端是同步的,那么我10个接口过来,它得一个接口完全返回数据之后在执行下个接口,这不得卡死。那这同步队列异步队列执行的机制是什么样子的呢?
JS执行机制
先执行执行栈中的同步任务
异步任务(回调函数)放在任务队列中
一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行.
js的运行环境
js的运行环境=>浏览器。那么这个环境有哪些引擎呢?
渲染引擎:负责页面的渲染
js引擎:负责js的预处理、解析和执行等
定时触发器引擎:负责处理定时事件,比如setTimeout,setInterval
事件触发引擎:负责处理dom事件
异步http请求引擎:处理http请求
这里要注意一下,渲染引擎和js引擎不能同时进行,渲染引擎在执行任务的时候,js引擎会被挂载,这是因为js引擎可以修改dom,如果一边渲染一边修改dom,浏览器也不知道怎么办好了。
宏任务和微任务
异步任务队列里又分宏任务和微任务。宏任务队列可以有多个,但是微任务队列只有一个
宏任务:script(全局任务),setTimeout,setInterval
微任务:process.nextTick, Promise, Object.observer
看个例子
setTimeout(_ => console.log(4))
new Promise(resolve => {
resolve()
console.log(1)
}).then(_ => {
console.log(3)
})
console.log(2)
// 输出结果:1,2,3,4
new Promise在实例化的过程中所执行的代码都是同步进行的,而then中注册的回调才是异步执行的。在同步代码执行完成后才回去检查是否有异步任务完成,并执行对应的回调,而微任务又会在宏任务之前执行。所以就得到了上面的输出1 2 3 4。
在来看个面试题
console.log('script start');
async function async1() {
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2 end');
}
async1()
setTimeout(function() {
console.log('setTimeout');
},0)
new Promise(resolve => {
console.log('Promise')
resolve()
}).then(function(){
console.log('promise1')
}).then(function(){
console.log('promise2');
})
console.log('script end');
// 输出顺序
/*
script start
async2 end
Promise
script end
async1 end
promise1
promise2
setTimeout
*/
首先输出script start没问题,然后await async2()会把console.log('async2 end');放到new Promise里去执行,而把console.log('async1 end')放到.then里去,那么这个时候async2 end会先执行,然后按顺序执行Promise和script end ,通过微任务比宏任务先执行的原则,async1 end被打印,按顺序promise1和promise2被打印,最终宏任务settimeout被打印