前后端中的异步和事件机制 | 前后端开发

e38dd38b5b82c16d9a7732e416c41a74.png

前言

在前后端程序设计开发工作中,小伙伴们一定都接触过事件、异步这些概念。出现这些概念的原因之一是,我们的代码在执行过程中所涉及的逻辑在不同的场合下执行时间的期望是各不相同的。为了尽量做到充分利用CPU等资源做尽可能多的事,免不了通过异步和事件机制的配合来实现系统资源分时复用的效率最大化。相信这个时候后端开发同学肯定会说,我们多线程、协程等并发编程的概念和机制都流行很久了,但大家有没有思考过,服务端各种语言比如golang, JAVA等已经在语言层面帮大家做了相当多的系统底层封装工作。抽象到系统层面,相信大家都知道大名鼎鼎的epoll机制,其核心目标还是实现系统资源分时复用的效率最大化。下面就让我们一起来看看,前后端应用开发场景中异步和事件机制有什么异同吧。

前端中的异步和事件机制

相信前端同学对异步和事件机制会更加敏感,这主要是因为JavaScript的特性导致异步和事件成了语言学习中的必会核心知识点之一。

4ae479175ce71c2687cbd39fd4131c29.png

作为浏览器脚本语言,JavaScript 的主要用途是与用户互动,以及操作 DOM。若以多线程的方式操作这些 DOM,则可能出现操作的冲突。假设有两个线程同时操作一个 DOM 元素,线程 1 要求浏览器删除 DOM,而线程 2 却要求修改 DOM 样式,这时浏览器就无法决定采用哪个线程的操作。当然,我们可以为浏览器引入“锁”的机制来解决这些冲突,但这会大大提高复杂性,所以 JavaScript 从诞生开始就选择了单线程执行。

另外,因为 JavaScript 是单线程的,在某一时刻内只能执行特定的一个任务,并且会阻塞其它任务执行。那么对于类似 I/O 等耗时的任务,就没必要等待他们执行完后才继续后面的操作。在这些任务完成前,JavaScript 完全可以往下执行其他操作,当这些耗时的任务完成后则以回调的方式执行相应处理。这些就是 JavaScript 与生俱来的特性:异步与回调。

当然对于不可避免的耗时操作(如:繁重的运算,多重循环),HTML5 提出了Web Worker,它会在当前 JavaScript 的执行主线程中利用 Worker 类新开辟一个额外的线程来加载和运行特定的 JavaScript 文件,这个新的线程和 JavaScript 的主线程之间并不会互相影响和阻塞执行,而且在 Web Worker 中提供了这个新线程和 JavaScript 主线程之间数据交换的接口:postMessage 和 onMessage 事件。但在 HTML5 Web Worker 中是不能操作 DOM 的,任何需要操作 DOM 的任务都需要委托给 JavaScript 主线程来执行,所以虽然引入 HTML5 Web Worker,但仍然没有改线 JavaScript 单线程的本质。

9fa2daa7e4dbe3fcf283cb98244a6b26.png

单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。js引擎执行异步代码而不用等待,是因有为有 消息队列和事件循环。

消息队列:消息队列是一个先进先出的队列,它里面存放着各种消息。

事件循环:事件循环是指主线程重复从消息队列中取消息、执行的过程。

实际上,主线程只会做一件事情,就是从消息队列里面取消息、执行消息,再取消息、再执行。当消息队列为空时,就会等待直到消息队列变成非空。而且主线程只有在将当前的消息执行完成后,才会去取下一个消息。这种机制就叫做事件循环机制,取一个消息并执行的过程叫做一次循环。整个机制如下图所示:

77b113b801e9b48116444b43a8fb330c.png

这里有几个概念:事件循环、调用栈(执行站)、微任务、宏任务、事件队列机制如下图所示:

f6c7d0c530e74eca8c3c5adcbffff43c.png

其中上图中的web api和对应的queue在实际应用场景对应两个:微任务和微任务队列、宏任务和宏任务队列,微任务和宏任务的定义包含:

594867c09a43f4a3fc6e545eb9da3a72.png

ba76cd182b7f1cee3555dc4053a70c06.png

不同类型的任务会进入对应的Event Queue,比如setTimeout和setInterval会进入相同(宏任务)的Event Queue。而Promise和process.nextTick会进入相同(微任务)的Event Queue。

1.「宏任务」、「微任务」都是队列,一段代码执行时,会先执行宏任务中的同步代码。

2.进行第一轮事件循环的时候会把全部的js脚本当成一个宏任务来运行。

3.如果执行中遇到setTimeout之类宏任务,那么就把这个setTimeout内部的函数推入「宏任务的队列」中,下一轮宏任务执行时调用。

4.如果执行中遇到 promise.then() 之类的微任务,就会推入到「当前宏任务的微任务队列」中,在本轮宏任务的同步代码都执行完成后,依次执行所有的微任务。

5.第一轮事件循环中当执行完全部的同步脚本以及微任务队列中的事件,这一轮事件循环就结束了,开始第二轮事件循环。

6.第二轮事件循环同理先执行同步脚本,遇到其他宏任务代码块继续追加到「宏任务的队列」中,遇到微任务,就会推入到「当前宏任务的微任务队列」中,在本轮宏任务的同步代码执行都完成后,依次执行当前所有的微任务。

7.开始第三轮,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值