欢迎光临散文网 会员登陆 & 注册

大前端进击之路(二)|JavaScript异步编程

2021-01-04 13:27 作者:光耀三十洲  | 我要投稿

打工人!打工魂!前端才是人上人!此系列总结于大前端进击之路过程中的学习,如果文章中有不对的地方,希望大家能进行批评改正,互相进步。

经典面试题

我们先来看一道经典的面试题,让我们的小脑袋瓜子思考起来~如果你对这道题有清晰的思路并且了解背后的原因,那么请直接点赞评论加关注!!!!!

JS采用单线程模式工作的原因

为了回答这个问题我们首先需要知道JS的执行环境是单线程的,是因为JS语言最早是运行在浏览器端的语言,目的是为了实现页面上的动态交互。实现动态交互的核心就是DOM操作,因此决定了JS必须是单线程模式工作。我们来假设一下如果JS是多线程一起工作的,其中一个线程修改了一个DOM元素,另外的一个线程同时又要删除这个DOM元素,那么此时浏览器就懵逼了,无法明确以哪个工作线程为准。所以为了避免线程同步的问题,JS就被设计成了单线程的工作模式。

注意,我们这里说的单线程是JS的执行环境是单线程,浏览器中是多线程的。

单线程的优势和弊端

采用单线程的工作模式可以节省内存,节约上下文切换时间,没有锁的问题。但弊端也很明显,如果中间有一个任务需要花费大量的时间,那么后面的任务就需要等待这个任务完成后才能执行,就会出现假死的情况,对用户很不友好。为了解决这个问题JS给出了两种执行模式:同步模式(Synchronous)和异步模式(Asynchronous)

同步模式和异步模式

同步模式

同步模式其实很好理解,举个栗子:

我们如果按照同步模式煮面的话,首先先将锅里装上水,打开火开始烧水,等待水烧开,再将面、鸡蛋、火腿肠等材料拿出,材料准备好后放入锅中进行煮,煮好后开始干饭。

在这里其实我们已经能够看出来问题,我们必须等到水烧开后才去准备要煮的材料。回到概念里就是在同步模式下我们的代码是依次执行,后一个任务必须等待前一个任务结束才能开始执行。程序执行的顺序和代码编写的顺序是完全一致的。在单线程模式下,大多数任务都是以同步模式执行。

异步模式

上个例子中我们在等待水烧开的过程中什么都没干,很浪费时间,我们可以在烧水的过程中将食材都准备好,等到水烧开后直接放入。

我们在烧水的过程中去干了别的事情,就属于异步模式,异步模式中不会等待异步任务的结束才开始执行下一个同步的任务,都是开启过后就立即执行下一个任务。

异步模式对于JS很重要,没有异步模式的话我们就无法同时处理大量的耗时任务,就会给用户带来卡顿和假死的体验。对于我们开发者来说,会给我们打开代码执行的顺序混乱的问题。

EventLoop事件循环和消息队列

  • EventLoop是一种循环机制,主线程从消息队列中读取任务并按照顺序执行,这个过程是循环不间断的。

  • 消息队列是存放异步任务的地方,当我们的同步任务都执行完毕后,EventLoop会从消息队列中依次取出异步任务放到调用栈中进行执行。

宏任务和微任务

  • 宏任务可以理解为每次执行栈执行的代码就是一个宏任务

    浏览器为了让JS内部宏任务与DOM操作能够有序的执行,会在一个宏任务执行结束后,下一个宏任务执行开始前,对页面进行重新渲染。

    宏任务包括:script整体代码、setTimeout、setInterval、I/O、UI交互事件、MessageChannel等。

  • 微任务可以理解为每个宏任务执行结束后立即执行的任务,发生在宏任务后,渲染之前,执行微任务。

    所以微任务的响应速度相比宏任务会更快,因为无需等待UI渲染

    微任务包括:Promise.then、MutaionObserver、process.nextTick(Node.js环境下)等。

图片取自掘金,侵即删

异步编程方案的本质—回调函数

回调函数:由调用者定制,交给执行者执行的函数。

我们通过 callback 回调函数、事件发布/订阅、Promise 等来组织代码,本质都是通过回调函数来实现异步代码的存放与执行。

更优异步编程统一方案——Promise

Promise概述

Promise概念MDN传送门

关于Promise概念性内容就不在赘述了,可直接点击传送门前往MDN查看。简单来说如果我们是用传统的回调函数方式来完成复杂的异步流程,就会无法避免大量的回调函数嵌套,产生回调地狱的问题。为了避免回调地狱让我们开始愉快的Promise的学习时光吧!

Promise案例

我们用Promise来封装一个AJax

Promise的链式调用

误区

  • 嵌套使用的方式是使用Promise最常见的误区。我们要使用promise的链式调用的方法尽可能保证异步任务的扁平化。

链式调用的理解

  • promise对象then方法,返回了全新的promise对象。可以再继续调用then方法,如果return的不是promise对象,而是一个值,那么这个值会作为resolve的值传递,如果没有值,默认是undefined

  • 后面的then方法就是在为上一个then返回的Promise注册回调

  • 前面then方法中回调函数的返回值会作为后面then方法回调的参数

  • 如果回调中返回的是Promise,那后面then方法的回调会等待它的结束

Promise的异常处理

  • then中回调的onRejected方法

  • .catch()

了解更多,请点击:https://www.bilibili.com/video/BV13a4y1n7tS/


作者:跟兔虫
链接:https://juejin.cn/post/6913476532333707271
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


大前端进击之路(二)|JavaScript异步编程的评论 (共 条)

分享到微博请遵守国家法律