异步之优雅的解决方案

您所在的位置:网站首页 钓鱼岛最后是如何解决的 异步之优雅的解决方案

异步之优雅的解决方案

2024-03-08 20:27| 来源: 网络整理| 查看: 265

0. 前言

在这篇文章中,我们来聊一聊关于异步问题,最优雅的解决方案 —— promise。在前面的文章中,我们介绍了异步和在ES6出来之前的异步解决方案,回调。在上一篇文章的最后,我们提到了回调可能会导致的一些问题:

调用回调过早 调用回调过晚 调用回调的次数太少或太多 没有把所需的环境/参数成功传递给回调函数 吞掉可能出现的错误和异常

在这篇文章中,我们就来看一看promise是如何解决这些问题的。在文章的最后,我们还会手写promise。本篇文章的参考资料有:

《你所不知道的JavaScript》promise相关内容 《前端开发核心知识进阶》中, 你以为我真的想让你手写promise吗 章节内容 1. promise

我们知道,在JavaScript中判断一个值的类型采用的是鸭子类型(duck typing),即如果它看起来像只鸭子,叫起来象只鸭子,那它一定就是一只鸭子。同样的,在JavaScript内部的语言机制中对于promise的检测也是基于这个原理。在《你所不知道的JavaScript》书中,对于识别Promise的描述如下:

在JavaScript中,识别Promise(或者行为类似于Promise的东西)就是定义某种称为thenable的东西,将其定义为任何具有then()方法的对象和函数。我们认为这样的值就是Promise一致的thenable

换句话说,识别某个东西是否为promise,就是检测它是否具有then()方法。然后,我们通过一个实际的例子来刨析一下Promise的原理。

ajax('some url') .then( data => { // 完成处理函数 }, error => { // 拒绝处理函数 } )

通过上述代码,我们来刨析Promise的实质:

Promise构造函数返回一个Promise对象的实例,这个返回的Promise对象具有一个then方法。在then方法中,调用者可以定义两个参数,分别是决议完成时的处理函数(onfulfilled)和决议被拒绝时的处理函数(onrejected)。其中,onfulfilled通过参数可以获取Promise对象经过resolve处理后的值,onrejected可以获取Promise对象经过reject处理后的值。

通俗的讲,Promise就是对事件的一个决议。既然是一个决议,那么决议的结果就一定是两个,接收或拒绝。Promise的then方法提供了由用户定义的对于两个决议结果的处理onfulfilled函数和onreject函数。

关于Promise,需要注意的是:如果又任何其他代码无意或恶意地给 Object.prototype , Array.prototype 或任何其他原生原型添加 then(),它们都会被认作Promise,你无法控制也无法预测。

这里,小编就要吐槽了。JavaScript虽然简洁明了,但是也出奇的危险。

2. Promise是否能解决回调的问题

现在,我们来回顾一下回调引起的一些问题:

调用回调过早 调用回调过晚(或不被调用) 调用回调此说过少或过多 未能传递所需的环境和参数 吞掉可能出现的错误和异常

关于这些问题,我们需要回顾一下回调调用的机制 —— 事件循环:当回调的条件满足之后,将回调相关的代码块添加到事件循环队列中,由事件循环队列对它的执行进行控制。由于事件循环队列不是由JavaScript语言机制来控制,而是由环境决定的,这就导致了很多不可控因素。从而导致上述问题的发生。在回调中,这些问题的发生都是由于事件循环队列不可控造成的。

而Promise则是产生在事件循环队列之上的任务队列这个概念上的。所谓的任务队列,可以这样理解:它是挂载在时间训话队列的每个tick之后的一个队列。在事件循环队列的每个tick中,可能出现的一部动作不会导致一个完整的新事件添加到事件循环队列中,而会在当前tick的任务队列末尾添加一个项目。

在Promise中,一个Promise对象只能被决议一次,而决议的结果要么是拒绝,要么是接受。而对于接收或拒绝的结果处理的异步代码会在决议做出之后执行,而且这些代码一定会被调用。因此,不存在调用过早或过晚的问题。而决议的结果和相关的处理代码是被绑定的,一旦决议做出,就会调用相关的处理代码,而Promise决议只能做一次,做出决议之后则无法更改。这就保证了then()方法中被传入的函数只能执行一次,所以也解决掉了调用次数过少或过多的问题。决议做出之后,就会产生一个结果,而处理代码将决议的结果作为参数传入,因此,传递参数的问题也被解决。一旦决议被拒绝,一定会有一个理由,这个理由就是代码中抛出的异常或错误。因此,promise也不可能吞并可能出现的错误和异常。

如前所述,回调中会遇到的问题,Promise都完美的解决掉了。因此,我们说Promise是异步问题的优雅解决方案。

3. Promise 相关 API

在这一部分中,我们来关注一下Promise相关的API。

new Promise()构造器: 首先来看用法: var p = new Promise( function(resolve, reject) { // resolve()用于决议/完成这个promise // reject()用于拒绝这个promise })

使用 new 关键字调用Promise的构造函数时,需要传入一个回调函数,这个函数需要接收两个参数,它们也是函数类型的参数,通常被称为 resolve 和 reject,分别表示完成这个Promise的处理逻辑和拒绝这个Promise的处理逻辑。在Promise对象创建时的回调函数是同步或立即被调用的,它定义了应该什么时候完成Promise决议,什么时候拒绝Promise决议。

Promise.resolve() 和 Promise.reject(): Promise.resolve(value)方法返回一个给定值解析后的Promise对象;Promise.reject() 方法返回一个带有拒绝原因的Promise对象。

Promise.then() 和 Promise.catch(): 这两个方法是Promise的经典方法了,.then()方法表示接受Promise决议之后的处理逻辑,.catch()方法表示拒绝Promise决议之后的处理逻辑

Promise.all() 和 Promise.race(): 这两个方法传入的参数都是数组,返回值都是一个Promise对象。不同的是:对于Promise.all()来说,只有传入的所有Promise都完成返回Promise才完成,如果有Promise被拒绝,返回的主Promise回立即被拒绝,并抛弃任何其他promise的结果;对于Promise.race()来说,只有第一个决议的promise完成决议,并且其决议结果称为返回promise的决议。

下文指路:异步之优雅的解决方案——promise(下)



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3