1 .简介
// 宏任务进入宏任务队列,微任务进入微任务队列
// 当前宏任务执行完出队,检查微任务,依次执行
// 执行浏览器UI现成的渲染工作
// 检查是否有web worker 任务,有就执行这个
// 执行完本轮的宏任务,回到第二步,再次旬换,直到微任务和宏任务队列全部为空
// 微任务:MutationObserver,Promise.then(),fetch,V8的垃圾回收,Node里面的process.nextTick
// 宏任务:script,setTimeout,setInterval,setImmediate,I/O,UI
// event loop
// 单线程-任务队列,所有队伍需要排列,前一个任务结束,后一个才会执行,如果前一个任务耗时很长,就会一直等着
// 同步任务:再主现成上排队执行的任务,只有前一个任务执行完毕,才会执行下一个任务
// 异步任务:不进入主线程,进入任务队列的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行
//1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
// (2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
// (3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
// (4)主线程不断重复上面的第三步。
// 只要主线程空了,就回去读取任务对列
首先执行的是script任务,script任务是全局任务,属于宏任务
宏任务执行完毕,开始执行所有的微任务
微任务执行完毕,再取任务队列中的一个宏任务执行
// 事件和回调函数
// 1 .任务队列是一个事件的队列,IO完成一项任务,就在"任务队列"中添加一个事件,表示相关任务可以进入执行栈了,主线程可以读取这个里面的任务执行了
// 2 .setTimeout(fn,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,也就是说,尽可能早得执行。它在"任务队列"的尾部添加一个事件,因此要等到同步任务和"任务队列"现有的事件都处理完,才会得到执行
// 3 .HTML5标准规定了setTimeout()的第二个参数的最小值(最短间隔),不得低于4毫秒,如果低于这个值,就会自动增加。在此之前,老版本的浏览器都将最短间隔设为10毫秒。另外,对于那些DOM的变动(尤其是涉及页面重新渲染的部分),通常不会立即执行,而是每16毫秒执行一次。这时使用requestAnimationFrame()的效果要好于setTimeout()。
// setTimeout()只是将事件插入了"任务队列",必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。要是当前代码耗时很长,有可能要等很久,所以并没有办法保证,回调函数一定会在setTimeout()指定的时间执行
// 我们知道,当我们调用一个方法的时候,js会生成一个与这个方法对应的执行环境(context),又叫执行上下文。这个执行环境中存在着这个方法的私有作用域,上层作用域的指向,方法的参数,这个作用域中定义的变量以及这个作用域的this对象。 而当一系列方法被依次调用的时候,因为js是单线程的,同一时间只能执行一个方法,于是这些方法被排队在一个单独的地方。这个地方被称为执行栈。
// 先执行微任务,然后执行宏任务.当前执行栈执行完毕时会立刻先处理所有微任务队列中的事件,然后再去宏任务队列中取出一个事件。同一次事件循环中,微任务永远在宏任务之前执行
执行顺序
event loop它的执行顺序:
1 .一开始整个脚本作为一个宏任务执行
2 .执行过程中同步代码直接执行,宏任务进入
3 .宏任务队列,微任务进入微任务队列
4 .当前宏任务执行完出队,检查微任务列表,有则依次执行,直到全部执行完
5 .执行浏览器UI线程的渲染工作
6 .检查是否有Web Worker任务,有则执行
7 .执行完本轮的宏任务,回到2,依此循环,直到宏任务和微任务队列都为空
面试题
1 .
const promise1 = new Promise((resolve, reject) => {
console.log('promise1')
// 1:还在第一轮宏任务之内,所以这个会立马执行
})
console.log('1', promise1);
// 2:依照代码顺序执行,但是此时promise还没有返回值,所以Promise<pending>,此时的状态是pending
2 .
const promise=new Promise((resolve,reject)=>{
console.log(1)
//1 顺序执行
resolve('success')
//2 将promise状态改为resolved并且保存下来
console.log(2)
// 3 执行同步代码
})
console.log(promise)
// 4 此时promsie的值为resolved
promise.then((e)=>{
console.log(3)
})
// 6 :promise.then为微任务,将其加入微任务列表,等到5执行完毕,检查微任务列表,发现promise这个微任务,并且这个微任务状态为resolved,执行它
console.log(4)
// 5 执行同步代码
3 .
const promise=new Promise((resolve,reject)=>{
console.log(1)
console.log(2)
})
promise.then((e)=>{
console.log(3)
})
console.log(4)
// 1,2,4
// 不会显示3,因为promise里面没有执行resolve,reject
4 .
const promise=new Promise((resolve,reject)=>{
console.log('promise1')
// 1顺序执行
resolve('resolve')
// 2 顺序执行
})
const preomise2=promise.then(res=>{
console.log(res)
// 5:resolve
})
// 这个会被放到下一轮执行
console.log('1',promise)
// 3 .Promise<resolve>
console.log('2',promise2)
// 4 pending
5 .
const fn=()=>(new Promise((resolve,reject)=>{
console.log(1)
// 1:顺序执行
resolve('success')
//设定为resolve状态
}))
fn.then((res)=>{
console.log(res)
// 3:下一轮的微任务执行,success
})
console.log("start")
// 2:顺序执行
6 .
const fn=()=>{
new Promise((resolve,reject)=>{
console.log('1')
// 1:顺序执行
resolve('success')
// 将promise置为resolve
})
console.log('start')
// 2:顺序执行
}
console.log('2')
// 0:第一个执行
fn().then(res=>{
// fn函数执行
console.log(res)
// 下一轮执行
// 3:successs
})
6 .
console.log('start')
// 1:顺序执行
setTimeout(()=>{
console.log('time')
// 4:下一轮的宏任务执行这个
})
Promise.resolve().then(()=>{
console.log('resolve')
})
// 3:第一轮之后的微任务执行,这里其实不太准确,应该是执行then之后的操作,前面的在第一轮已经执行了
console.log('end')
// 2:顺序执行
7 .
const promise=new Promise((resolve,rejetc)=>{
console.log(1)
//1:顺序执行这一个
setTimeout(()=>{
console.log('timeStart')
// 3下一个宏任务执行这里
resolve('success')
// 4将promsie设置为resolve状态
console.log("timeEnd")
},0)
// 下一个宏任务执行这个
console.log(2)
// 1.1这里还要插入一个
})
promise.then((res)=>{
// 没有返回,所里这里什么都不执行
console.log(res)
// 5 .最后执行这一个
})
console.log(4)
//2顺序执行
8 .
setTimeout(()=>{
console.log('time1')
// 2:第二轮执行这个
setTimeout(()=>{
console.log('timer2')
},0)
// 这里放在了第三轮的宏任务
},0)
setTimeout(()=>{
console.log('timer2')
// 3:第二轮第二布执行这个
##这里不是第二轮,而是第三轮的宏任务
},0)
console.log('start')
// 1:第一个执行这个,因为剩下的都在下一个宏任务执行
9 .
setTimeout(()=>{
console.log('timer1')
// 2:第二轮的宏任务
Promise.resolve().then(()=>{
console.log('promise')
})
// 3 :第二轮的微任务
},0)
setTimeout(()=>{
console.log('timer2')
// 第三轮的宏任务
},0)
console.log('start')
// 1:顺序执行
10 .
Promise.resolve()
// 加到微1
.then(()=>{
console.log('promise1')
// 2:执行第一个微任务
const timer=setTimeout(()=>{
// 加到宏3
console.log("time2")
//5:
// 执行宏三
},0)
})
// 加到宏2
const timer1=setTimeout(()=>{
console.log('timer1')
// 3 :执行宏2
Promise.resolve().then(()=>{
console.log('promise2')
// 4
})
// 加入宏2的微任务,在这里会立马执行
},0)
console.log('start')
//1:顺序执行第一个代码:start
11.领导夹菜我转桌,领导敬酒我不喝,领导听牌我自摸,领导走路我坐车,领导讲话我唠嗑,领导唱k我切歌,领导私事我乱说,领导喝水我刹车
const promise1=new Promise((resolve,reject)=>{
// 加入宏2
setTimeout(()=>{
resolve('success')
},1000)
})
const promise2=promise1.then(()=>{
// 宏2的微任务队列
// throw new Error('error')
console.log('promise2 then')
})
console.log('promise1',promise1)
// 1.Promsie<pending>
console.log('promise2',promise2)
// 2.Promise<pending>
//加入宏三
setTimeout(()=>{
console.log('promise1',promise1)
// promsie<success>
console.log('promise2',promise2)
// promise{fulfilled undefined}
// 因为我并没有实际上给这个有返回值
},2000)
12 .
const promise1=new Promise((resolve,reject)=>{
// 放到宏2
setTimeout(()=>{
resolve('sucess')
console.log('timer1')
// 4 顺序执行
},1000)
console.log('promsie1里面的内容')
// 1:按照顺序执行
})
const promise2=promise1.then(()=>{
// 放到当前的微任务
// 这里是放到宏二的微任务,而不是当前的
console.log('promise then')
// 5:执行当前微任务 promise then
})
console.log('promise1',promise1)
// 2:promise1,pending
console.log('promise2',promise2)
// 3:promise2 undefined
// 3 :这里竟然第一次给的也是pending,而不是undefined
// 放到宏3
setTimeout(()=>{
console.log('timer2')
// 6
console.log('promise1',promise1)
// 7 success
console.log('promise2',promise2)
// 8 undefined,现在才是undefined
},2000)