js如何实现异步的?--事件循环
1.事件队列(宏任务、微任务)
为什么js是单线程? 作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。
为什么分为宏任务和微任务?
这种设计是为了给紧急任务一个插队的机会,否则新入队的任务永远被放在队尾。区分了微任务和宏任务后,本轮循环中的微任务实际上就是在插队,这样微任务中所做的状态修改,在下一轮事件循环中也能得到同步。
我们倾向于拿到一个结果就去处理这个结果,如果只有宏任务,那只有等到所有的任务执行完才能拿到结果进行处理。那如果第二个任务需要根据第一个任务的执行结果进行处理,就必须设置成这种模式。
1)js中的任务分为同步任务和异步任务
同步任务是指:当前主线程将要消化执行的任务,这些任务一起形成执行栈(execution context stack)。
异步任务是指:不进入主线程,而是进入任务队列(task queque),即不会马上进行的任务。
2)事件循环(或JS运行机制、 异步过程:),流程如下:
step1:主线程读取并执行JS同步代码;
step2: 主线程遇到异步任务,就new一个 Worker进行处理。主线程继续执行同步代码;
step3: 异步线程处理完毕(Ajax返回、DOM事件触发、Timer到等),将相应的回调推入任务队列;
step4:主线程清空微任务队列;
step5:主线程执行队首一个宏任务;
step6:重复step4、step5。
3)常见的宏任务:用户I/O、onclick、setTimeout、setInterval、AJAX、
常见的微任务:nextTick、promise的then、catch、
4)宏任务是浏览器发起的,微任务是js引擎发起的
2.web Worker
1)浏览器中主要的线程包括,UI渲染线程,JS引擎线程,事件触发线程,http请求线程,定时触发线程 。
2)JS作为脚本语言,它的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程。但是单线程的语言,有一个很致命的问题,即如果一个脚本语言在执行时,其中某一块的功能在执行时耗费了大量的时间,那么就会造成阻塞。JS为我们提供了一个Worker的类,它的作用就是为了解决这种阻塞的现象。当我们使用这个类的时候,它就会向浏览器申请一个新的线程。这个线程就用来单独执行一个js文件。webworker仅仅能进行计算任务,不能操作DOM,所以本质上还是单线程。
在新线程中使用postMessage()方法可以向主线程中发送一些数据,主线程中使用worker的onmessage事件来接收这些数据,这样就实现了js的多线程执行和多线程之间数据的传递。
3)异步编程的方式:回调函数、发布订阅、promise(es6)、generator、async/await