同步异步与web worker
同步与异步(待完善)
https://www.jianshu.com/p/e865c3a7ba10
为什么要有异步?
- js是单线程语言,浏览器只分配给js一个主线程,用来执行任务(函数),但一次只能执行一个任务,这些任务形成一个执行栈排队等候执行,但前端的某些任务是非常耗时的,比如网络请求,定时器和事件监听,如果让他们和别的任务一样,都老老实实的排队等待执行的话,执行效率会非常的低,甚至导致页面的假死。所以,浏览器为这些耗时任务开辟了另外的线程,主要包括http请求线程,浏览器定时触发器,浏览器事件触发线程,这些任务是异步的。
什么是同步,什么是异步
- 同步任务是指在主线程上排队执行的任务,只有前一个任务执行完毕,后一个同步任务才能执行。
- 异步任务是指不在主线程、而是在任务队列中的任务。只有当任务队列通知主线程,并且执行栈为空时,该任务队列中的任务才会进入主线程执行。
例子
例如setTimeout(function(){console.log(1);},50);
主线程发现异步任务丢给异步处理模块处理,异步处理模块执行计时操作,当50ms到了后,会触发定时事件,这个时候,就会把回调函数放到任务队列里。整个程序就是通过这样的一个个事件驱动起来的。
常见的异步
定时器事件、回调事件、ajax、生命周期回调都是异步代码
事件循环:
事件循环过程被称为"tick";
- 当主进程遇到到异步任务的时候,就将他丢给异步处理模块(如webAPIs等),接着执行同步任务,直到Stack为空;
- 在此期间异步处理模块(如webAPIs等)完成这个事件,把回调函数放入任务队列中等待;
- 当主进程中执行栈为空时,事件循环(Event Loop)把任务队列中的一个任务放入主进程中,回到第1步。
任务队列与微任务队列
存储异步操作添加的相关事件回调
-
异步操作会将相关回调添加到任务队列中。宏任务添加到任务队列中,微任务添加到微任务队列中.
-
异步操作是由浏览器内核的 webcore 来执行的,webcore 包含3种 webAPI,分别是 DOM Binding、network、timer模块
setTimeout
会由浏览器内核的 timer 模块来进行延时处理,当时间到达的时候,才会将回调函数添加到任务队列中。on事件
由浏览器内核的 DOM Binding 模块来处理,当事件触发的时候,回调函数会立即添加到任务队列中。ajax
(XMLHttpRequest) 则会由浏览器内核的 network 模块来处理,在网络请求完成返回之后,才将回调添加到任务队列中。
任务与微任务
我们把异步任务分为任务(task)
和 微任务(Microtask)
:
浏览器为了能够使得JS内部task与DOM任务能够有序的执行,会在一个task执行结束后,在下一个task 执行开始前,对页面进行重新渲染 (task->渲染->task->...)
任务就是一般的异步任务
微任务通常来说就是需要在当前主线程(stack)为空后立即执行的任务
目前见到的微任务
promise.then/catch/finally,对 .then/catch/finally 处理程序的执行会成为微任务。
queueMicrotask(func),它对 func 进行排队,以在微任务队列中执行。
Mutation Observer(变动观察器)是监视DOM变动的接口
同步异步执行流程:
- 主线程中的执行栈放的同步代码,先执行
- 主线程唯一(只有一个主线程)主线程将执行栈里的代码执行完毕。事件循环才开始执行
- 主线程中执行栈为空,才会进行事件循环来观察要执行的事件回调。
- 当事件循环检测到微任务队列中有任务就取出相关事件回调放入执行栈中由主线程执行,
- 如果微任务队列中没有任务,就去任务队列中查找,如果任务队列中有任务就取出相关事件回调放入执行栈中由主线程执行,
- 如果没有进行下次循环
web Worker
https://www.ruanyifeng.com/blog/2018/07/web-worker.html
一般用法:
主线程
let worker=new worker('分线程路径');
Worker.postMessage(要传递的数据);
worker.onmessage=function(e){
console.log(e.data); //传递回来的值
}
分线程
function fn(n){
if(n<=2){
return 1;
}
return fn(n-1)+fn(n-2);
}
slef.onmessage=function(e){
vardata=fn(e.data) //接收传递回来的值,并调用fn
self.postMessage(data) //将计算出来的值传递回去
}