代码执行的过程中,必然不会存在同时执行的另一行代码,就像使用以后进行疯狂
,如果没有关闭弹框,控制台是不会显示出一条
信息的。
代码执行了大量计算,比方说在前端暴力破解密码之类的鬼操作,这就会导致后续代码一直在等待,页面处于假死状态,因为前边的代码并没有执行完。
代码都是同步执行的,这会引发很严重的问题,比方说我们要从远端获取一些数据,难道要一直循环代码去判断是否拿到了返回结果么?
注册一个回调函数,比如说发一个网络请求,我们告诉主程序等到接收到数据后通知我,然后我们就可以去做其他的事情了。
通知到我们,但是此时可能程序正在做其他的事情,所以即使异步完成了也需要在一旁等待,等到程序空闲下来才有时间去看哪些异步已经完成了,可以去执行。
注册一个异步任务就会被放在这个任务队列中,就像在银行中排号,如果叫到你的时候你不在,那么你当前的号牌就作废了,柜员会选择直接跳过进行下一个客户的业务处理,等你回来以后还需要重新取号
添加一些微任务的,就像在柜台办理业务,你前边的一位老大爷可能在存款,在存款这个业务办理完以后,柜员会问老大爷还有没有其他需要办理的业务,这时老大爷想了一下:“最近P2P爆雷有点儿多,是不是要选择稳一些的理财呢”,然后告诉柜员说,要办一些理财的业务,这时候柜员肯定不能告诉老大爷说:“您再上后边取个号去,重新排队”。 博客中的代码片段: 就是作为宏任务来存在的,而 代码
添加的“”而往后推。
?或者 ? console.log(4))new Promise(resolve => {
resolve()
console.log(1)
}).then(_ => {
console.log(3)
})
console.log(2)
则是具有代表性的微任务,上述代码的执行顺序就是按照序号来输出的。
在实例化的过程中所执行的代码都是同步进行的,而中注册的回调才是异步执行的。
代码执行完成后才回去检查是否有异步任务完成,并执行对应的回调,而微任务又会在宏任务之前执行。
输出结论。
代码
{- console.log(4)+})+new Promise(resolve => {+ resolve()+ console.log(1)+}).then(_ => {- console.log(3)+})+console.log(2)
已经先设置了定时器(相当于取号),然后在当前进程中又添加了一些的处理(临时添加业务)。
中实例化,其输出依然会早于
的宏任务:
console.log(4))new Promise(resolve => { resolve() console.log(1) }).then(_ => { console.log(3) Promise.resolve().then(_ => { console.log('before timeout') }).then(_ => { Promise.resolve().then(_ => { console.log('also before timeout') }) }) }) console.log(2)
调用的,一般都会在里边有其他的异步操作,比如
、
之类的操作。
注册了一个宏任务,而非是微任务。
中,的实现可以是微任务,也可以是宏任务,但是普遍的共识表示(至少
是这么做的),
应该是属于微任务阵营的
姑且也算是宏任务吧,
在为,下次页面重绘前所执行的操作,而重绘也是作为宏任务的一个步骤来存在的,且该步骤晚于微任务的执行
是一个单进程的语言,同一时间不能处理多个任务,所以何时执行宏任务,何时执行微任务?我们需要有这样的一个判断逻辑存在。
。
task1// > task2// > task3// > special micro task// > task4// > special macro task
循环来表示,是因为在循环内部可以很方便的进行之类的操作(添加一些任务),从而使迭代的次数动态的增加。
只是负责告诉你该执行那些任务,或者说哪些回调被触发了,真正的逻辑还是在进程中执行的。
的作用,那么在真实的浏览器中是什么表现呢?
这一项感觉有点儿笼统,有太多的东西都可以称之为,点击一次,上传一个文件,与程序产生交互的这些都可以称之为。
结构:
#outer {
padding: 20px;
background: #616161;
}
#inner {
width: 100px;
height: 100px;
background: #757575;
}
console.log('promise')) // 注册微任务
setTimeout(_ => console.log('timeout')) // 注册宏任务
requestAnimationFrame(_ => console.log('animationFrame')) // 注册宏任务
$outer.setAttribute('data-random', Math.random()) // DOM属性修改,触发微任务}new MutationObserver(_ => {
console.log('observer')
}).observe($outer, {
attributes: true})
$inner.addEventListener('click', handler)
$outer.addEventListener('click', handler)
,其执行顺序一定是: -> -> -> -> -> -> -> -> -> 。
创建了一个宏任务,也就是说在这次任务中会去触发。
和两个微任务,遂执行之。
事件会冒泡,所以对应的这次会触发两次函数(、一次在
),所以会优先执行冒泡的事件(),也就是说会重复上述的逻辑。
,实际上修改了的属性,这会导致页面的重绘,而这个的操作是同步执行的,也就是说的回调会早于所执行。
元素的触发方式变为,那么会得到不一样的结果。
下的输出顺序大致是这样的:
-> -> -> -> -> -> -> -> 。
的执行顺序不一样的原因是这样的,因为并不是用户通过点击元素实现的触发事件,而是类似这样的方式,我个人觉得并不能算是一个有效的,在执行了一次回调注册了微任务、注册了宏任务以后,实际上外边的并没有执行完。
。
,等到这两次都执行完毕后才会去检查有没有微任务、有没有宏任务。
的这种触发事件的方式个人认为是类似,可以理解为同步执行的代码
console.log('click'))
document.body.click()
document.body.dispatchEvent(new Event('click'))
console.log('done')// > click// > click// > done
的监听不会说同时触发多次,多次修改只会有一次回调被触发。
{
console.log('observer') // 如果在这输出DOM的data-random属性,必然是最后一次的值,不解释了}).observe(document.body, {
attributes: true})
document.body.setAttribute('data-random', Math.random())
document.body.setAttribute('data-random', Math.random())
document.body.setAttribute('data-random', Math.random())// 只会输出一次 ovserver
,文中有动画版的讲解
上与浏览器稍微有些不同,这里是的地址。
以及宏任务的。
为一次执行完毕后调用。
则是通过计算一个延迟时间后进行执行。
,而这时定时器已经处于可执行回调的状态了。
,这时才会执行。
console.log('setTimeout'))
setImmediate(_ => console.log('setImmediate'))
一定会在之前触发了:
console.log('setTimeout'))
setImmediate(_ => console.log('setImmediate'))
let countdown = 1e9while(countdonn--) { } // 我们确保这个循环的执行速度会超过定时器的倒计时,导致这轮循环没有结束时,setTimeout已经可以执行回调了,所以会先执行`setTimeout`再结束这一轮循环,也就是说开始执行`setImmediate`
先执行:
{
setTimeout(_ => console.log('timeout'))
setImmediate(_ => console.log('immediate'))
})// 如果使用一个设置了延迟的setTimeout也可以实现相同的效果
和的微任务实现,在代码执行的过程中可以随时插入,并且会保证在下一个宏任务开始之前所执行。
{ // 这里将永远不会执行
console.log('init!')
})
对象时是同步执行的,在实例化完成以后就立马发送了事件。
监听事件的这一步。
来解决这个问题:
{ this.emit('init')
}) // 同理使用其他的微任务
// 比如Promise.resolve().then(_ => this.emit('init'))
// 也可以实现相同的效果 }
}
流程查找有没有微任务,然后再发送事件。
会导致报警,后续的代码永远不会被执行,这是对的,参见上边使用的双重循环实现的即可,相当于在每次循环执行中都对数组进行了操作,这样循环永远也不会结束
本质上还是基于的一些封装,而是属于微任务的一种。所以在使用关键字与效果类似:
console.log(4))
async function main() {
console.log(1)
await Promise.resolve()
console.log(3)
}
main()
console.log(2)
时传入的代码,await之后的所有代码都是在中的回调