突破字节前端2-1⾯试: JS异步编程问题应答范式及进阶(视频教学及完整源码笔记)

⼀、前⾔

本期让我们来聚焦Javascript异步

异步编程在现代软件开发中⾄关重要,它解决了阻塞和资源利⽤率两⼤核⼼问题,从根本上提升了程序的效率、响应能⼒和可扩展性

JavaScrip的异步⽆论在前端还是Node服务、⼯程化领域,都是基础中⼗分重要的组成部分。异步相关的问题,在⾯试中也是重点⾼频问题

思考以下⼏个问题,看看你对JavsSript异步编程了解的程度有多少?

  • 如果让你把线程、进程、Event Loop、SetTimeout、Ajax、 ReadFile、Promise、Generator、Async Await这些关键词分组,你会如何分?他们之间的关系是什么?

  • 你对Promise的理解是什么? Promise的核⼼解决了什么问题?

  • 你了解genrator⾃执⾏器吗? 它解决了前段异步编程中的什么问题?

  • Async await的本质是什么?

  • 上次公开课的request的⾼阶答法,如何设计http client, 可以⾃动识别调⽤的地⽅是否进⾏了错误处理?

本篇内容:https://github.com/encode-studio-fe/natural_traffic/wiki/scan_material5

⼆、Event Loop

【重点掌握】JavaScript异步基础 - 事件循环执⾏过程

事件循环是JavaScript实现异步的基础,与其他多线程的编程语⾔的实现不⼀致,因JavaScript单线程的特性,导致异步的实现需要基于Event Loop

我们先看⼀段代码:

这段代码是怎么执⾏的呢?

  • ⾸先JavaScript的解释器在读到 console.log('Sync Code') 的时候, 控制台输出了 'Sync Code'

  • 之后解释器调⽤setTimeout() ,设置了⼀个定时器,在2000ms后执⾏ console.log('AsyncCode');

  • 再次读到 console.log('Sync Code') , 控制台输出 'Sync Code'

  • 所有同步代码执⾏完毕,进⼊Event Loop过程

  • 两秒后向控制台输出console.log('Async Code');

同步执⾏与异步执⾏

同步执⾏的代码包含初始执⾏代码和异步创建的同步代码两种

异步执⾏的代码通过⼀些内置的API创建,常⻅的异步代码创建API有:

双端(浏览器、NodeJS)API及语法:

  • setTimeout

  • setinterval

  • Promise 相关API

浏览器端API:

  • MutationObserve

  • XMLHttpRequest

  • requestAnimationFrame

  • queueMicrotask

Node端API:

  • nextTick

  • ReadField等等

JavaScript的运⾏机制即为,执⾏完所有的同步代码后,进⼊Event Loop

让我们观察⽤于创建异步执⾏代码的API,可以发现,这些API的参数⼀定是⼀个回调函数

这些被包裹的待执⾏函数,会被推⼊⼀个等待执⾏的队列,Event Loop即为⼀个⽆限的循环过程,去检查队列中是否存在等待执⾏的函数。如果存在,将其压⼊调⽤栈执⾏,在JavaScript执⾏线程存在的⽣命周期中⼀直持续这个过程

伪代码如下

【重点掌握】宏任务微任务

宏任务与微任务

JavaScript将待执⾏栈分为宏任务与微任务。区别在于对于宏任务与微任务的执⾏的优先级不同

执⾏优先级

宏任务与微任务的创建API

所有创建异步的API,仅有少数的API可⽤于创建微任务,其余均是宏任务,记住这⼏个微任务即可创建微任务的API与语法:

  • Promise实例相关API

  • nextTick

  • queueMicrotask

【特殊】

requestAnimationFrame 是浏览器端特有的异步过程的创建API,其执⾏时机位于微任务和宏任务之间,并且还受限于浏览器是否有渲染任务(涉及到帧率)

三、Promise

【重点掌握】为什么会有Promise

  1. 控制权反转问题

所谓的控制权反转,即为在早期以callback(回调函数)来实现异步执⾏时,需要把异步执⾏函数做为回调传⼊到创建异步的函数中

如果是运⾏环境中的官⽅的API函数还好,但是如果是⼀个第三⽅封装的函数,将⽆法确定传⼊的回调函数会被如何执⾏

也可以理解为,控制权反转即把将要执⾏的异步过程和创建异步的函数的执⾏进⾏了耦合,为了解决这个问题,那么就需要把「执⾏过程调⽤」改变为「消息通知」,即创建异步任务的函数不再负责直接调⽤后续的异步过程,⽽是仅仅「发送」异步过程的结果,后续的调⽤由发起⽅⾃⾏控制。这即是Promise解决控制反转问题的核⼼。

Promise如何解决的?

通过状态机,Promise只负责告知当前的异步过程执行的状态(pending-等待/fulfilled-正常/rejected-异常),并设计了对应的API来响应状态的变化

一个Promise的状态只可以改变一次,且只能从pending改变为fulfilled/rejected

初始化

Promise通过初始化创建来包裹异步过程,并在合适的时机修改状态机。

1.通过构造函数中注入的resolve和reject方法

创建微任务

当Promise构造函数中的resolve\reject被执行时,会把通过Promise实例中通过.then()传入的函数创建一个微任务。所以Promise.then创建的微任务实际是通过resolve\reject来创建的

回调地狱

【重点掌握】Promise链式调⽤

通过Promise实例的API(then catch finally)会返回⼀个新的Promise实例

API接受的函数的返回值可以是任意值,Promise会判断返回值的类型并进⾏相应的处理

返回Promise

返回thenable(函数或者对象的原型链上有then, 且then为函数):promise 把resolve传⼊到then的参数中

返回其他值: 直接返回⼀个resolved的promise

【重点掌握】Promise核⼼API

Promise.all(iterable):Promise.all())接受一个Promise 实例组成的迭代器(例如数组)作为参数,并返回一个新的Promise实例。当所有输入的Promise都resolved时,这个新的Promise才会resolved,并且返回一个包含所有输入Promise resolved 值的数组。如果其中任何一个Promise 被reject,Promise.all()也会立即reject,并且返回的Promise会包含第一个被reject 的Promise的错误信息。

Promise.allSettled(iterable)Promise.allSettled()类似于Promise.all(),但它会在所有输入的Promise都settle(resolved 或rejected)后才返回。它返回一个对象数组,每个对象描述了对应的Promise 的状态和结果。对于resolved 的Promise,对象包含status:"fulfilled"和value属性;对于rejected 的Promise,对象包含status:"rejected"和reason属性。

Promise.race(iterable):Promise.race()接受一个Promise实例组成的迭代器作为参数,并返回一个新的Promise实例。只要其中任何一个输入的Promise状态发生改变(resolved或rejected),Promise.race(就会立即返回,并使用该Promise 的结果作为自己的结果。

如果迭代器为空,则返回的Promise将永远pending。

Promise.resolve(value):Promise.resolve(value)用于创建一个已经resolved 的Promise实例。如果value本身是一个Promise 实例,则该方法会返回这个Promise 实例;如果value是一个thenable对象(即具有.then())方法的对象),则Promise.resolve()会调用该对象的.then()方法,并根据其返回值来决定新的Promise的状态;如果value不是Promise 或thenable 对象,则返回一个以该值为resolved值的Promise 实例。

Promise.reject(reason) : Promise.reject(reason) ⽤于创建⼀个已经rejected 的Promise 实例。 reason 是reject 的原因。

......

刷题资源

https://github.com/encode-studio-fe/natural_traffic/wiki/scan_material5

以上资源获取,希望能帮助到你们,祝大家12月或者1月求职顺利,一些寒假找前端实习的宝宝可以试试这些刷题资源哈~比较新!

相关推荐
quikai19812 小时前
python练习第四组
开发语言·前端·python
Better Bench2 小时前
git与github协作开发的常用命令
git·github
爱上妖精的尾巴2 小时前
5-40 WPS JS宏 综合实例应用-5(求字符串中的最大值记录)
开发语言·前端·javascript·wps·js宏·jsa
TT哇2 小时前
【@NotBlank】@NotBlank与@NotEmpty与@NotNull区别
java·开发语言
曹卫平dudu2 小时前
用Trea来快速生成一个浏览器插件
前端
dorisrv2 小时前
React 状态管理:Zustand 快速上手指南
前端·react.js
lenkco2 小时前
修改QtConcurrent::run支持任意参数
开发语言·c++·qt
byc2 小时前
Android 存储目录<内部存储,外部存储app专属,外部存储公共>
android·面试
逛逛GitHub2 小时前
逛逛今天推荐 4 个 GitHub 开源项目,非常实用。
github