Promise对象
javascript中实现异步编程的四种方式。分别是1.回调函数 2.事件监听 3.发布、订阅事件 4.promise对象
Promises对象是在CommonJS工作组提出的一种规范,目的是为异步编程提供统一接口。现已在ECMAScript2015(ES6)中实现。
Promise
对象用于延迟(deferred) 计算和异步(asynchronous ) 计算.。一个Promise对象代表着一个还未完成,但预期将来会完成的操作。
Promise
对象是一个返回值的代理,这个返回值在promise对象创建时未必已知。它允许你为异步操作的成功或失败指定处理方法。 这使得异步方法可以像同步方法那样返回值:异步方法会返回一个包含了原返回值的 promise 对象来替代原返回值。
Promise
对象有以下几种状态:
pending: 表示一个初始状态, 非 fulfilled 或 rejected。
fulfilled: 成功的操作。
rejected: 失败的操作。
每一个异步任务都会返回一个Promise对象,该对象有一个then方法,允许指定回调函数。可以根据Promise对象的状态相应的去执行对应的回调函数。
二、常用的API
1.Promise.prototype.then()
promise实例具有then方法,因此then方法是定义在原型对象promise.prototype上的。它的作用是为promise实例添加状态改变时的回调函数。
then()方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。then方法返回的是一个新的promise实例,非原来的那个promise实例,因此可以采用链式写法,then方法之后还可调用一个then方法。
var p=new Promise(function(resolve,reject){ resolve("ok"); }); p.then(function(value){console.log(val)}, function(err)(console.log(err)) );
then方法的第二个参数一般不推荐写。有以下两个原因:第一个原因,由于是链式操作,这个then方法之后还可能会有其他操作,如果此时把错误捕捉的函数放在后面方法前边的话,并且之后再无错误捕获方法,then之后的错误就会捕捉不到。第二个原因是在then方法里面,两个参数都是回调函数写了一大堆,这样结构看起来比较混乱。
所以下面就有了这个方法,一般写在链式写法的最后。这样就可以捕获到前面所有的错误。
2.Promise.prototype.catch()
这个方法是.then(null,rejection)的别名,这也能看出这个方法是专门只能用来捕获错误信息,用于指定发生错误时的回调函数。
但是使用这个这个方法的时候要注意一下几点:
(1)当promise状态已经变成resolved的时候,再抛出错误时是无效的。看下面的代码。
var promise=new promise(function(resolve,reject){ resolve("ok"); throw new Error("test"); }); promise.then(function(value){consloe.log(val); }) .catch(function(error){console.log(err)});
promise状态在resolve("ok");之后就会把promise的状态变为resolved,之后抛出错误也不会把promise状态变为rejected,所以catch方法并不会捕获到错误。
Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected。只要这两种情况有任意一种发生,状态就相当于凝固了,不会再变了,会一直保持这个结果。
(2)尽量将catch方法写在链式操作的最后,原因上面都已经说过了,也正是捕获错误不推荐写then方法的原因之一。错误会一直冒泡到最后,catch放在最后会捕捉到所有错误。当catch设置的过早,并且之后在没有catch方法的话,那么这个catch之后发生的错误不会被捕获到。
(3)当没有使用catch方法指定错误处理函数的回调函数时,promise对象里面抛出的错误不会传递到外层的代码。
3.Promise.resolve()
这个方法的作用就是将现有的对象转化为Promise对象,进而可以执行这些方法。
Promise.resolve("foo"); //这就相当于下面这种写法 new Promise(function(resolve){ resolve("foo"); });
4.Promise.all()
这个方法用于将多个promise实例,包装成一个新的promise实例。
var p=Promise.all([p1,p2,p3]);
p1,p2,p3都是promise对象的实例,如果不是的话,则会调用Promise.resolve()方法,将参数转化为Promise实例,之后再继续进行进一步的处理。
并且要注意一下两点:
(1)只有当p1,p2,p3状态都变为fulfilled之后,p的状态才会变为fulfilled。
(2)只要p1.p2,p3中有任意一个状态变为rejected,p的状态就会变为rejected。
三、实现异步编程的原理
大概原理就是正如它们所说Promise对象相当于是一个状态机,在其内部使用resolve方法,使其由初始状态变为成功时的fulfilled状态或者执行失败后的rejected状态。这时内部的工作就完成了,开始由外部监听其内部的状态的改变,调用then()方法(catch()方法相当于then内部的第二个参数方法)对应的状态调用对应的处理函数。这样就大概是Promise对象实现异步编程的原理。