ES6规定,Promise对象是一个构造函数,用来生成Promise实例。
//下面代码创造了一个Promise实例。
var promise = new Promise(function(resolve,reject){
// to do
if(){
resolve(value);//成功
}else{
reject(values);//失败
}
});
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是
resolve
和
reject
。它们是两个函数,由JavaScript引擎提供,不用自己部署。
resolve
函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从Pending变为Resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject
函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从Pending变为Rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
//Promise实例生成以后,可以用then方法分别指定Resolved状态和Reject状态的回调函数。
promis.then(function(value){
//success
},function(error){
//fail
});
then
方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为Resolved时调用,第二个回调函数是Promise对象的状态变为Reject时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。
//Promise新建后就会立即执行。
let promise = new Promise(function(resolve,reject){
console.log('Promise');
resolve();
});
promise.then(function(){
console.log('Resolved!');
});
console.log('Hello!');
//Promise
//Hello!
//Resolved!
//上面代码中,Promise新建后立即执行,所以首先输出的是“Promise”。
//然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以“Resolved”最后输出。
下面是异步加载图片的例子。
function loadImgAsync(url){
return new Promise(function(resolve,reject){
var img = new Image();
img.onload = function(){
resolve(img);
};
img.onerror = function(){
reject(new Error('wrong img!'));
};
img.src = url;
})
}
//上面代码中,使用Promise包装了一个图片加载的异步操作。如果加载成功,就调用resolve方法,否则就调用reject方法。
如果调用
resolve
函数和
reject
函数时带有参数,那么它们的参数会被传递给回调函数。
reject
函数的参数通常是Error对象的实例,表示抛出的错误;
resolve
函数的参数除了正常的值以外,还可能是另一个Promise实例,表示异步操作的结果有可能是一个值,也有可能是另一个异步操作,比如像下面这样。
var p1 = new Promise(function(resolve,reject){
// to do
});
var p2 = new Promise(function(resolve,reject){
resolve(p1);
});
//p1和p2都是Promise的实例,但是p2的resolve方法将p1作为参数,即一个异步操作的结果是返回另一个异步操作。
//注意,这时p1的状态就会传递给p2,也就是说,p1的状态决定了p2的状态。
//如果p1的状态是Pending,那么p2的回调函数就会等待p1的状态改变;
//如果p1的状态已经是Resolved或者Rejected,那么p2的回调函数将会立刻执行
var p3 = new Promise(function(resolve,reject){
setTimeout(() => reject(new Error('Error!')),3000);
});
var p4 = new Promise(function(resolve,reject){
setTimeout(() => resolve(p3),1000);
});
p4.then(result => console.log(result))
.catch(error => console.log(error));
//Error: Error!
//上面代码中,p1是一个Promise,3秒之后变为rejected。p2的状态在1秒之后改变,resolve方法返回的是p1。
//由于p2返回的是另一个 Promise,导致p2自己的状态无效了,由p1的状态决定p2的状态。所以,后面的then语句都变成针对后者(p1)。
//又过了2秒,p1变为rejected,导致触发catch方法指定的回调函数。
1,Promise.prototype.then
Promise实例具有then
方法,也就是说,then
方法是定义在原型对象Promise.prototype上的。它的作用是为Promise实例添加状态改变时的回调函数。前面说过,then
方法的第一个参数是Resolved状态的回调函数,第二个参数(可选)是Rejected状态的回调函数。
2,Promise.prototype.catch
Promise.prototype.catch
方法是
.then(null, rejection)
的别名,用于指定发生错误时的回调函数。
var promise = new Promise(function(resolve,reject){
throw new Error('test!');
});
promise.catch(function(error){
console.log(error);
});
//Error: test!
上面代码中,
promise
抛出一个错误,就被
catch
方法指定的回调函数捕获。注意,上面的写法与下面两种写法是等价的。
var promise = new Promise(function(resolve,reject){
try{
throw new Error('test!');
}catch (e){
reject(e);
}
});
promise.catch(function(error){
console.log(error);
});
//写法2
var promise1 = new Promise(function(resolve,reject){
reject(new Error('tese!'));
});
promise1.catch(function(error){
console.log(error);
});
//比较上面两种写法,可以发现reject方法的作用,等同于抛出错误。
3,promise.all()
Promise.all
方法用于将多个Promise实例,包装成一个新的Promise实例
var p = Promise.all([p1,p2,p3]);
//上面代码中,Promise.all方法接受一个数组作为参数,p1、p2、p3都是Promise对象的实例,
//如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为Promise实例,再进一步处理。
//(Promise.all方法的参数可以不是数组,但必须具有Iterator接口,且返回的每个成员都是Promise实例。)
p
的状态由p1
、p2
、p3
决定,分成两种情况。
(1)只有p1
、p2
、p3
的状态都变成fulfilled
,p
的状态才会变成fulfilled
,此时p1
、p2
、p3
的返回值组成一个数组,传递给p
的回调函数。
(2)只要p1
、p2
、p3
之中有一个被rejected
,p
的状态就变成rejected
,此时第一个被reject
的实例的返回值,会传递给p
的回调函数。
4,premise.race()
Promise.race
方法同样是将多个Promise实例,包装成一个新的Promise实例
var p = Promise.race([p1,p2,p3]);
//上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。
//那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
//Promise.race方法的参数与Promise.all方法一样,如果不是 Promise 实例,
//就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理
//下面是一个例子,如果指定时间内没有获得结果,就将Promise的状态变为reject,否则变为resolve。
const p = Promise.race([
fetch('/resource-that-may-take-a-while'),
new Promise(function(resolve,reject){
setTimeout(() => reject(new Error('request timeout')),5000);
})
]);
p.then(response => console.log(response))
.catch(error => console.log(error));
//上面代码中,如果5秒之内fetch方法无法返回结果,变量p的状态就会变为rejected,从而触发catch方法指定的回调函数
5,promise.resolve()
有时需要将现有对象转为Promise对象,
Promise.resolve
方法就起到这个作用
//Promise.resolve等价于下面的写法
Promise.resolve('foo');
//等同于
new Promise(resolve => resolve('foo'));
Promise.resolve
方法的参数分成四种情况。
(1)参数是一个Promise实例
如果参数是Promise实例,那么
Promise.resolve
将不做任何修改、原封不动地返回这个实例。
(2)参数是一个
thenable
对象
//thenable对象指的是具有then方法的对象,比如下面这个对象
let thenable = {
then:function(resolve,reject){
resolve(42);
}
};
//Promise.resolve方法会将这个对象转为Promise对象,然后就立即执行thenable对象的then方法
let p = Promise.resolve(thenable);
p.then(s => console.log(s));//42
//上面代码中,thenable对象的then方法执行后,对象p1的状态就变为resolved,从而立即执行最后那个then方法指定的回调函数,输出42
(3)参数不是具有then
方法的对象,或根本就不是对象
如果参数是一个原始值,或者是一个不具有
then
方法的对象,则Promise.resolve
方法返回一个新的Promise对象,状态为Resolved
。var p = Promise.resolve('hello!');
p.then(s => console.log(s));//hello!
//上面代码生成一个新的Promise对象的实例p。
//由于字符串Hello不属于异步操作(判断方法是它不是具有then方法的对象),
//返回Promise实例的状态从一生成就是Resolved,所以回调函数会立即执行。
//Promise.resolve方法的参数,会同时传给回调函数。
(4)不带有任何参数
Promise.resolve
方法允许调用时不带参数,直接返回一个Resolved
状态的Promise对象。
所以,如果希望得到一个Promise对象,比较方便的方法就是直接调用
Promise.resolve
方法。var p = Promise.resolve();
p.then(function(){
// to do
});
需要注意的是,立即
resolve
的Promise对象,是在本轮“事件循环”(event loop)的结束时,而不是在下一轮“事件循环”的开始时。
setTimeout(function () {
console.log('three');
}, 0);
Promise.resolve().then(function () {
console.log('two');
});
console.log('one');
// one
// two
// three
//上面代码中,setTimeout(fn, 0)在下一轮“事件循环”开始时执行,
//Promise.resolve()在本轮“事件循环”结束时执行,console.log(’one‘)则是立即执行,因此最先输出。
6,promise.reject()
Promise.reject(reason)
方法也会返回一个新的 Promise 实例,该实例的状态为rejected
。上面代码生成一个Promise对象的实例var p = Promise.reject('error'); //等同于 var p = new Promise((resolve,reject) => reject('error')); p.then(null,s => console.log(s));
p
,状态为rejected
,回调函数会立即执行。
注意,Promise.reject()
方法的参数,会原封不动地作为reject
的理由,变成后续方法的参数。
这一点与Promise.resolve
方法不一致。
const thenable = { then(resolve,reject){ reject('error'); } }; Promise.reject(thenable) //.catch(e =>{ // console.log(e === thenable); //}); .catch(e => console.log(e === thenable)); // true //上面代码中,Promise.reject方法的参数是一个thenable对象,执行以后, //后面catch方法的参数不是reject抛出的“出错了”这个字符串,而是thenable对象。