浏览器事件循环原理

Javascript为什么是单线程的?

浏览器js的作用是操作DOM,这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?

怎么理解JS异步编程的?

可以提高js单线程执行机制下的处理效率的,针对一些耗时操作例如:接口的请求调用、文件的读写操作,通过js异步编程的方式,不会造成堵塞;
常用的JS异步编程的处理方式有回调函数、事件、Promise、Generator、Async Await。

什么是同步任务?什么是异步任务?

1、所谓同步任务,就是非耗时任务,在主线程当中直接执行的任务;
2、异步任务,又称耗时任务,分为宏任务和微任务;如果是宏任务(setTimeOut等)需要去其它线程等待完毕后加入宏任务队列,然后由下一轮的事件循环取出后加入执行栈中执行;
如果是微任务就放入微任务队列,在本轮时间循环中取出执行;

2.什么是微任务?什么是宏任务?它们有什么区别?

1、微任务和宏任务都是异步任务,宏任务是指在主线程之外的任务,比如定时器、事件回调等。
2、而微任务是指在主线程任务执行完毕之后立即执行的任务,比如Promise的then方法和MutationObserver的回调函数等。
3、宏任务和微任务的区别在于宏任务在任务队列中排队,每次只执行一个任务,而微任务在任务队列之后执行,每次执行所有微任务。

任务队列

任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。

(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。

(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。

(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。

(4)主线程不断重复上面的第三步。

主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。

浏览器中的事件循环

参考 http://lynnelv.github.io/js-event-loop-browser

为了协调事件(event),用户交互(user interaction),脚本(script),渲染(rendering),网络(networking)等,用户代理(user agent)必须使用事件循环(event loops)。

To coordinate events, user interaction, scripts, rendering, networking, and so forth, user agents must use event loops as described in this section. Each agent has an associated event loop.

  • 事件:PostMessage, MutationObserver等
  • 用户交互: click, onScroll等
  • 渲染: 解析dom,css等
  • 脚本:js脚本执行

事件循环的本质

在浏览器或者nodejs环境中,运行时对js脚本的调度方式就叫做事件循环。

宏任务与微任务

除了广义的同步任务和异步任务,JavaScript 单线程中的任务可以细分为宏任务(macrotask)和微任务(microtask)。

  • macrotask: script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering。

  • microtask:process.nextTick, Promise, Object.observe, MutationObserver。

  1. 宏任务进入主线程,执行过程中会收集微任务加入微任务队列。
  2. 宏任务执行完成之后,立马执行微任务中的任务。微任务执行过程中将再次收集宏任务,并加入宏任务队列。
  3. 反复执行1,2步骤
  • 事件处理过程
    关于macrotask和microtask的理解,光这样看会有些晦涩难懂,结合事件循坏的机制理解清晰很多,下面这张图可以说是介绍得非常清楚了。
    在这里插入图片描述
    把任何耗时的操作都给其他线程(IO线程、定时器线程,DB线程等)做,做完之后向事件队列(多线程安全的队列,其他线程是生产者,逻辑线程是消费者)丢事件。
高频面试题
  • 面试题一
setTimeout(() => {
  console.log('setTimeout');
}, 0);

Promise.resolve().then(() => {
  console.log('promise');
  Promise.resolve().then(() => {
    console.log('promise2');
  });
});

console.log('main');

在这里插入图片描述
在这里插入图片描述

每轮事件循环执行一个宏任务和所有的微任务。

  • 面试题二
setTimeout(() => {
  Promise.resolve().then(() => {
    console.log('promise');
  });
}, 0);

Promise.resolve().then(() => {
  setTimeout(() => {
  	console.log('setTimeout');
  }, 0);
});

console.log('main');

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一共存在三轮事件循环。
任务队列一定会保持先进先出的顺序执行。

主线程上:
console.log('start')
new Promise((resolve) => {
  console.log('resolve')
})
console.log('end')
打印顺序: start -- resolve -- end
promise对象的then方法总是被异步调用的
await指令会暂停异步函数的执行,并等待Promise执行,然后继续执行异步函数,并返回结果。(异步函数如果不阻塞,程序正常执行,如果阻塞,不会影响主线程上执行其它任务)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值