异步的那些事(三)--Promise

从上一篇看出,简单封装后的deferred与如今的Promise非常相似,尤其是最后那个返回dtd.promise()的例子,则直接返回了一个promise对象。介绍了promise的前世以后,再来看看它的今生。

如今的promise,有异常捕获,可多个串联,Promise.all和Promise.race等用法。下面将根据promise的用法由浅入深的举例子。

首先,可以通过Promise将一个异步操作new成Promise的一个实例,从而我们在这个实例上进行更加优雅的操作,而不是之前的用callback形式,从前面的学习可以知道这样做解耦了代码,很好体现了编程界 开放封闭 的原则。这个例子见下图,通过promise对加载图片操作进行封装。从而有对w的链式操作。这里有个小知识点,想要第二个.then操作接收到数据,从而处理数据,在第一个.then操作后面要返回接收到的数数据(而这个数据针对这个例子是我们封装操作的时候传进去的img信息)。

Promise构造函数接受一个函数作为参数,该函数的参数分别是resolve和reject两个函数,它们由JS引擎提供,不用我们部署。resolve函数的作用是,执行resolve后,将Promise对象状态从'pending'变为'resolved'(.then中的第一个函数在监听到这个状态变化,则会执行),同时可以传递参数出去;reject函数作用则是,执行完它将Promise对象状态从'pending'变为'rejected'(.then中的第二个函数在监听到这个状态变化,则会执行),也可以传递参数出去。所以说在封装异步操作为Promise对象时候,一定注意不要主动去触发resolve或者reject,否则你将得不到你想要的结果。比如下面的这个例子,我们在封装Promise对象的时候直接触发了reject,而不是在img.onerror时候才触发它,并且这个例子里面传入一个字符串。可以看出,由于状态发生变化,.then的第二个函数或者.catch监听到了则做出应对。

下面再接着举一个封装ajax的例子,方便与上面例子一些细节比较。(这里我觉得ajax在1.5之后已经支持类似的链式操作,实际用的时候也不用封装也能达到相同的效果(可以看我前面的一篇文章Deferred有举例),但是为什么还有很多人去封装成promise再用,我也在思考?)

以前我们用ajax时候偶尔会遇到这样的问题,当我们需要将程序中的数据传递到callback函数里面,我们可能会采用下面的写法:


现在有了promise我们可以做的更加优雅,因为resolve可以传递参数,但是貌似规定只能传一个参数,所以我们可以用数组或者对象形式,将我们要传的多个参数进行包装,用数组传递例子如下:

实际工作中我们总要对promise实例进行异常处理,在.这里我们用.catch捕获异常,一般来说,我们不要在.then方法中定义rejected状态的函数(then的第二个参数),而总是用catch方法。这个写法跟我们以前用的try{}catch{}的用法很相似。在《ECMAScript6入门》一书中学习到,catch的方法其实是指Promise.prototype.catch,它是.then(null,rejection)的别名,用于指定发生错误时的回调函数,但是请注意当Promise状态已经变成resolved,再抛出错误是无效的,看下面的第二个图片。

实际工作中,我们经常要控制异步操作的执行顺序,比如ajax的顺序执行,或者图片的顺序加载。比如实现图片的顺序加载的例子如下,在第一个实例后返回第二个实例。

   Promise.all接收一个promise数组,待全部完成之后,统一执行success,比如下面的例子,打印出来的图片宽度与上面一致,注意这里返回的是一个数组,因为是一组promise实例的返回。

Promise.race接受一个promise数组,其中任何一个完成,就执行success。

你可能感兴趣的:(异步的那些事(三)--Promise)