文章转载至:前端进阶攻略作者:前端进阶什么是promise?Promise是一种异步编程的解决方案,比传统的回调函数和事件更加合理和强大。所谓Promise,简单来说就是一个容器,里面装着一些在未来会结束的东西(通常是异步操作)。从语法上讲,Promise是一个对象,可以从中获取异步操作的消息。特点:物体状态不受外界影响。Promise对象表示一个异步操作,具有三种状态:pending(进行中)、fulfilled(成功)和rejected(失败)。只有异步操作的结果才能确定它是哪个状态,其他任何操作都不能改变这个状态。这也是Promise这个名字的由来。状态一旦改变,就不会再改变,随时都可以得到这个结果。Promise对象的状态变化只有两种可能:*从pending到fulfilled和从pending到rejected。只要这两种情况发生,状态就会冻结,不会再发生变化。给Promise对象加上回调函数,也会立即得到这个结果。有了Promise对象,就可以在同步操作的过程中表达异步操作。缺点:首先,Promise不能被取消。一旦创建,将立即执行,不能中途取消。其次,如果不设置回调函数,Promise内部发生的错误无法反映到外部。pending的时候,没办法知道进度到哪了。基本用法ES6规定Promise对象是一个用于生成Promise实例的构造函数。以下代码创建一个Promise实例。Promise构造函数接受一个函数作为参数,函数的两个参数是resolve和reject。它们是两个函数,由JavaScript引擎提供,你不需要自己部署。resolve函数的作用是将Promise对象的状态从“未完成”变为“成功”。(也就是从pending到resolved)。异步操作成功时调用,将异步操作的结果作为参数传递;reject函数的作用是将promise对象的状态从“未完成”变为“失败”(即从pending变为rejected)。当异步操作失败时调用,并将异步操作报告的错误作为参数传递。Promise实例生成后,可以使用then方法分别指定resolve状态和rejected状态的回调函数。then方法可以接受两个回调函数作为参数。当promise对象的状态变为已解决时调用第一个回调函数,当promise对象的状态变为拒绝时调用第二个回调函数。第二个功能是可选的,不一定需要提供。这两个函数都接受从Promise对象传递的值作为参数。上面代码中,timeout方法返回一个Promise实例,代表一段时间后会发生的结果。在指定的时间后,Promise实例的状态变为已解决,then方法绑定的回调函数将被触发。Promise在创建后立即执行。上面的代码中,使用Promise封装了一个图片加载的异步操作。如果加载成功,则调用resolve方法,否则调用rejected方法。Promise.prototype.then()Promise实例有一个then方法,也就是说then方法定义在原型对象上。它的作用是为Promise实例添加状态变化时的回调函数。前面提到then方法的第一个参数是resolved状态的回调函数,第二个参数是rejected状态的回调函数(可选)。then方法返回一个新的Promise实例(注意,不是原来的Promise实例),所以可以写成链式,即在then方法之后再调用一个then方法。Chained则可以指定一组回调函数依次调用。这时候之前的回调函数可能会返回一个Promise对象(即有异步操作)。这时候,一个回调函数会等待Promise对象的状态发生变化,然后再被调用。上面代码中,第一个then方法指定的回调函数返回一个Promise对象。这时,第二个方法指定的回调函数会等待新的Promise对象的状态改变。如果变为resolved,则调用funcA,如果状态变为rejected,则调用funcB.Promise.prototype.catch()Promise.prototype.catch方法是.then(null,rejection)的别名,用于指定何时发生错误回调。在上面的代码中,getJSON方法返回一个Promise对象。如果对象状态变为resolved,则调用then方法指定的回调函数;如果异步操作抛出错误,状态将变为拒绝,并调用catch方法指定的回调函数。打回来。另外,如果then方法指定的回调函数抛出错误,也会被catch方法捕获。如果Promise状态已经变为resolved,则抛出错误是无效的。因为Promise的状态一旦改变,就会永久保持那个状态,不会再改变。Promise对象的错误具有冒泡性,会向后传递,直到被捕获,也就是说错误总会被下一个catch语句捕获。Promise.prototype.finally()finally方法用于指定无论Promise对象的最终状态如何都将执行的操作。4、Pomise.all的Promise.all(iterable)方法返回一个Promise实例,当iterable参数中的所有promise都“resolved”或者参数不包含promise时,回调完成(resolve);如果参数之一的承诺失败(拒绝),并且此实例回调失败(拒绝)。失败的原因是第一个失败的承诺的结果。具体代码如下:Promse.all在处理多个异步进程时非常有用。比如一个页面需要等待两个或多个ajax数据返回后才能正常显示。在此之前,只显示加载图标。需要注意的是,Promise.all获取到的成功结果数组中的数据顺序与Promise.all接收到的数组顺序一致,即p1的结果在前,即使是p1的结果p1的获取时间晚于p2的获取时间。这带来了一个很大的好处:在前端开发请求数据的过程中,偶尔会出现多次发送请求,并按照请求顺序获取和使用数据的场景,使用Promise.all无疑可以解决这个问题。5.Promise.race使用Promise.race(iterable)方法返回一个承诺。一旦迭代器中的承诺被解决或拒绝,返回的承诺将被解决或拒绝。Promse.race顾名思义就是race的意思,意思是Promise.race([p1,p2,p3])中无论哪个结果很快得到,就返回那个结果,不管结果本身是否处于成功状态或失败的状态。原理还是挺简单的,但是在实际使用中,我还没有想到会用到什么使用场景。示例:超时取消下面我们看看如何使用Promise.race来实现超时机制。当然XHR有timeout属性,也可以用它来轻松实现超时功能,但是为了同时支持多个XHR超时或者其他功能,我们采用了通俗易懂的异步方式来取消正在进行的进程通过超时在XHR中运行。让Promise等待指定的时间首先我们来看一下Promise中如何实现timeout。所谓超时,就是在一定时间后执行某些操作。使用setTimeout时很容易理解。首先说说Promise中一个简单调用setTimeout的函数。delayPromise(ms)返回一个承诺对象,该对象在参数指定的毫秒数过去后执行onFulfilled操作。与直接使用setTimeout函数相比,只是在编码上略有不同,如下图。这里promise对象的概念很重要,请记住。Promise.race中的超时我们可以把刚才的delayPromise和其他promise对象放到Promise.race中,实现一个简单的超时机制。函数timeoutPromise(compareobjectpromise,ms)接收两个参数,第一个是需要使用超时机制的promise对象,第二个参数是超时时间,返回一个由Promise.race创建的竞争promise对象。之后,我们可以使用timeoutPromise编写具有超时机制的代码,如下所示。虽然超时会抛出异常,但这种情况下我们无法区分异常是_正常错误_还是_超时错误_。为了区分Error对象的类型,我们定义了一个Error对象的子类TimeoutError。扩展知识:自定义Error对象Error对象是ECMAScript的内置对象。但是由于stacktrace等原因,我们无法完美的创建一个继承自Error的类,但是我们这里的目的只是为了区别于Error,我们将创建一个TimeoutError类来达到我们的目的。在ECMAScript6中,可以使用类语法来定义类之间的继承关系。为了让我们的TimeoutError能够支持类似于errorinstanceofTimeoutError的使用方式,我们还需要做如下工作。我们定义了TimeoutError类和构造函数,它继承了Error原型。它可以像普通的Error对象一样使用,只需使用throw语句,如下所示。有了这个TimeoutError对象,我们就可以很容易的区分捕获到的是超时导致的错误还是其他原因导致的Error对象。??看完三件事,如果你觉得这篇内容对你很有启发,请你帮我三个小忙:点击“同意”,让更多人看到这篇内容(喜不喜欢我赞同,都是流氓-_-)关注我不要迷路~让我们成为长期关系关注我的专栏(前端高级架构帮助),并为您发送前端高级面试问题
