Event Loop 与深刻理解同步异步

JS 执行机制
网景当初设计js只花了十天的时间,最初的动机非常单纯,就是为了给单调的网页增加些许交互,所以需要操作dom,所以这就决定它必须是一门单线程语言,如果是多线程的话会引发一个问题在同一时间同时操作DOM 一个增加一个删除JS就不知道到底要干嘛了,但是在webWorker 下是可以开启多线程的但是不允许操作DOM

单线程就意味着所有的任务都需要排队,后面的任务需要等前面的任务执行完才能执行,如果前面的任务耗时过长,后面的任务就需要一直等,一些从用户角度上不需要等待的任务就会一直等待,这个从体验角度上来讲是不可接受的,所以JS中就出现了异步的概念
 

同步任务
代码从上到下按逐行执行

异步任务
1.宏任务
script(整体代码)、setTimeout、setInterval、UI交互事件、postMessage、Ajax

2.微任务
Promise.then catch finally、MutaionObserver、process.nextTick(Node.js 环境)

运行机制

所有的同步任务都是在主进程执行的形成一个执行栈,主线程之外,还存在一个"任务队列",异步任务执行队列中先执行宏任务,然后清空当次宏任务中的所有微任务,然后进行下一个tick如此形成循环,什么叫tick,就是每次执行一次微任务队列里的所有的任务叫tick,nextTick的作用就是将它里面的任务添加到微任务队列的末尾。

这里有个点需要关注,我们的代码其实都是写在script里面的,所以所有的同步任务其实是内嵌在一个大的异步任务script中,所以看上去好似微任务先执行,其实他们的逻辑应该是这样:

理解事件循环必须得首先深刻理解同步和异步的概念

同步是最符合人体直觉,有先后顺序,即第二行的同步代码势必晚执行于第一行,如我们常见的赋值操作,控制台打印等都是同步任务

异步:所有非同步任务即为异步任务,具体阐述可以理解成此段代码无法立即返回结果,或者是有可能阻碍js主线程,这时候浏览器就会开启一个异步任务队列(注意这里的数据结构是'队列',遵循先进先出的原则),把它们一个一个挂进异步任务队列,任务队列里优先处理本script代码块中的微任务,清空之后再往任务队列里面宏任务,而这里的处理,指的其实就是把任务队列里的任务,按照先进先出的原则,添加到js主线程的执行栈里(当执行栈里没有同步任务的时候,就会去任务队列里寻找有无异步任务)

很多人难以理解单线程和异步的概念,为什么明明js是单线程,又怎么“分心”处理异步。

js的单线程指的是一个浏览器页面进程有且只有一个js的执行线程,即js主进程,同一时刻只会有一段代码在执行

而异步机制其实是基于js的异步模型,在run time实现的机制。虽然js执行是单线程的,但它的运行时却不是,例如异步请求是由两个线程:js执行主线程和事件触发线程共同完成。js的执行线程会首先发起异步请求通知浏览器,此时浏览器就会开启一条http请求线程来执行请求,(所以这下知道为什么ajax是基于浏览器的xmlhttprequest了吧),js通知之后就已经收工,不会傻傻的等返回结果,而是会去执行其他代码,然后在未来的某一时刻事件触发线程监听到之前发起的http请求已完成,它就会把完成事件所绑定的回调函数插入到异步队列里,并把请求返回结果传入回调函数的参数。又例如定时器任务,是由浏览器的定时器线程所执行的,所以它的参数是一个回调函数,便于在计时结束后将任务追加进任务队列。

        所谓异步的实现其实是js主线程与浏览器Api(定时器、xhr、dom、bom等其实都是浏览器Api,都不归属于js)通信所共同完成的,在js主线程真正执行的,只有“通知”这个动作,所以他们没有冲突,其实整套流程下来也就是发布订阅模式了。

猜你喜欢

转载自blog.csdn.net/apple_52957499/article/details/128742692