先从一个例子入手:javascript
(function() {
console.log('开始执行')
setTimeout(function fun1() {
console.log('第一个延时函数消息')
})
console.log('一条消息')
setTimeout(function fun2() {
console.log('第二个延时函数消息')
}, 0)
console.log('结束')
})();
复制代码
输出结果很容易知道:java
//开始执行
//一条消息
//结束
//第一个延时函数消息
//第二个延时函数消息
复制代码
在js事件模型中,运行时从最早进入队列的消息开始处理队列中的消息,这不难理解,但上述代码为何setTimeout延时为0也会延后执行?promise
这是由于在js中,bash
- 全部的同步任务在主线程上按顺序执行,前一个任务执行完毕,才能执行后一个任务
- 主线程以外有一个任务队列,像setTimeout,promise.then,await promise这种的异步任务在任务队列上先按等级再按顺序排队,等级是什么鬼?异步任务也是分等级的,promise.then排第一梯队,await promise排第二梯队,,最后就是setTimeout,按等级排好队后再按顺序排好队(见下面示例)
- 当主线程中的同步任务执行完毕后,就会通知任务队列中的任务:主线程上的同步任务执行好了,大家能够来主线程了。而后排好队进入主线程,开始执行异步任务
- 总的来说就是只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。这个过程会不断重复。
setTimeout(()=>{
console.log("11")
})
setTimeout(()=>{
console.log("12")
},0)
function promise_func(){
return new Promise((resolve,reject)=>{
resolve("异步输出结果")
})
}
promise_func().then(data=>{
console.log('then', data)
})
async function fun1(){
console.log('await1', await promise_func())
}
fun1()
async function fun2(){
console.log('await2', await promise_func())
}
fun2()
promise_func().then(data=>{
console.log('then2', data)
})
console.log("22")
复制代码
打印结果:异步
22
then 异步输出结果
then2 异步输出结果
await1 异步输出结果
await2 异步输出结果
11
12
复制代码
事件模型中加入消息队列神马的通常来讲你不去关心是看不清摸不着的,但根据setTimeout你能够稍微简单的感觉到里面的一些状况async
很少说,先放一个简单例子:函数
(function() {
console.log('开始');
setTimeout(function cb() {
console.log('第一个延时器的消息');
},1001);
console.log('一条消息');
setTimeout(function cb1() {
console.log('第二个延时器的消息');
}, 1000);
console.log('结束');
})()
复制代码
可能你会有点犹豫了,其实结果是:ui
开始
一条消息
结束
第一个延时器的消息
第二个延时器的消息
复制代码
为啥第一个延时1.001s比第二个延时1.000s要先执行呢,咱们先从setTimeout提及spa
setTimeout没跟同步函数一块儿被加入到消息队列,而是等待同步消息队列执行结束开始加入,延迟参数表明消息被实际加入到队列的最小延迟时间线程
若是队列中没有其它消息,在这段延迟时间过去以后,消息会被立刻处理。可是,若是有其它消息,setTimeout 消息必须等待其它消息处理完。
上述代码中,第一个延时函数被加入到消息队列,并当即开始执行,等待1.001s后输出结果,在第一个延时函数加入到队列并当即执行这一过程当中,第二个延时函数也加入了队列,这个加入到队列的过程是须要必定时间的,这个时间取决于cpu的处理速度,固然这个时间是很是短的。
上面是一个简单例子,咱们夸大一下这个例子,试着让最后一个延时1秒的函数等待更多的时间再去执行,比第一个延时1.0002s的延时函数还要慢,方案就是在这过程当中让更多的延时函数加入消息队列。
(function () {
console.log('开始')
setTimeout(function cb() {
console.log('第一个延时器的消息')
}, 1002)
console.log('一条消息')
for (let i of new Array(1000)) {
setTimeout(function cb1() {
console.log('nb')
}, 2000)
}
setTimeout(function cb1() {
console.log('最后一个延时器的消息')
}, 1000)
console.log('结束')
})()
复制代码
执行结果:
开始
一条消息
结束
第一个延时器的消息
最后一个延时器的消息
nb
nb
...
...
复制代码
第一个延时函数被加入到消息队列,并当即开始执行,等待1.002s后输出结果,当在最后一个延时函数加入队列前循环加入1000个延时函数时, 最后一个延时函数是等待前面全部延时函数加入队列后才开始加入并执行,这个加入队列的过程花费了一段时间,致使1.002s后第一个延时函数执行结果最早被输出
这些示例虽然简单,但能很好地帮助理解setTimeout延时的含义以及js的事件模型