Promise 简介
Promise 为异步编程提供了一种新的解决方案。
简单说Promise 是一个对象,在创建时结果是未知的,他允许你为异步操作返回成功和失败后的处理方法,这样就可以使异步方法像同步方法样有自己的返回值,只是他的返回值不是立即返回,而是一个代表未来出现结果的Promise对象。
三种状态
pending(待定的)、fulfilled(已解决/以实现)、rejected(已拒绝/没有实现)
三种状态之间的转换
从pending转换成fulfilled、从pending转换成rejected(即从进行中分别转向了成功和失败)。
基本用法
- 创建Promise实例
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
例子: 用Promise对象实现的 Ajax 操作
const getJSON = function(url) {
const promise = new Promise(function(resolve, reject){
const handler = function() {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
const client = new XMLHttpRequest();
client.open("GET", url);
client.onreadystatechange = handler;
client.responseType = "json";
client.setRequestHeader("Accept", "application/json");
client.send();
});
return promise;
};
getJSON("/posts.json").then(function(json) {
console.log('Contents: ' + json);
}, function(error) {
console.error('出错了', error);
});
Promise的原型方法
then(用于指定成功时的回调函数。)、catch(用于指定发生错误时的回调函数。)、
promise
.then(function(data) { //cb
// success
})
.catch(function(err) {
// error
});
finally(指定不管 Promise 对象最后状态如何,都会执行的操作)
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
例子:
console.log('here we go');
new Promise(resolve=>{
setTimeout(()=>{
resolve('hello');
},2000);
}).then(value=>{
console.log(value+ ' world');
(function (){
return new Promise(resolve=>{
setTimeout(()=>{
console.log("donna");
resolve("bangbang");
},4000)
});
}());
return false;
}).then(value=>{
setTimeout(()=>{
console.log(value+ " bingbing");
},3000)
打印的先后顺序为 here we go 、hello world 、false bingbign、donna
第一个then方法里面返回的Promise实例是在立即执行函数里面的,不是这个then方法的返回值,它的返回值是false,所以它不会等里面的定时器执行完,就跳到了下一个then方法中执行(记得value是上一个then方法返回的false),执行完之后,才去执行上面的定时器中的内容
const promise = new Promise(function(resolve, reject) {
try {
throw new Error('test');
} catch(e) {
reject(e);
}
});
promise.catch(function(error) {
console.log(error);
});
// 写法二
const promise = new Promise(function(resolve, reject) {
reject(new Error('test'));
});
promise.catch(function(error) {
console.log(error);
});
// 写法三
const promise = new Promise(function(resolve, reject) {
throw new Error('test');
});
promise.catch(function(error) {
console.log(error);
});
这三种方法是等价的,从上面我们也可以发现,reject方法的作用等同于抛出错误
resolve()
Promise.resolve()方法:有时需要将现有对象转为Promise对象,Promise.resolve方法就起到这个作用
Promise.resolve等价于new Promise(resolve=>resolve(‘foo’));
Promise.resolve方法的参数分四种情况。
-
参数是一个Promise实例
这种情况Promise.resolve将不做任何修改,原封不动地返回这个实例。
-
参数是一个thenable对象
thenable对象指的是具有then方法的对象。Promise.resolve方法会将这个对象转为Promise对象,然后立即执行thenable对象的then方法。
//使用Promise.resolve方法
let thenable = {
then:function(resolve){
resolve("donna");
}
}
Promise.resolve(thenable).then(value=>{
console.log(value);//donna
});
//上面的方法类似下面的这样
new Promise(resolve=>{
resolve("donna");
}).then(value=>{
console.log(value);
})
- 参数不是具有then方法的对象,或根本不是对象
如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的Promise对象,状态为resolved
let obj= {
str:function(){
console.log(123);
}
}
Promise.resolve(obj).then(value=>{
console.log(value);//{str:f}
});
上面的代码生成一个新的Promise对象的实例,由于对象obj不是thenable对象,返回Promise实例的状态从一一生成就是resolved,所以回调函数会立即执行,Promise.resolve方法的参数会同时传给回调函数
- 不带有任何参数
Promise.resolve方法允许调用时不带参数,直接返回一个resolved状态的Promise对象。所以如果希望得到一个Promise对象,比较方便的方法就是直接调用Promise.resolve方法
reject()
Promise.reject(reason)方法也会返回一个新的Promise实例,该实例的状态为rejected
注意:Promise.reject()方法的参数会原封不动传给后续方法的参数,这一点与Promise.resolve方法不一致
const thenable = {
then(resolve, reject) {
reject('出错了');
}
};
Promise.reject(thenable)
.catch(e => {
console.log(e === thenable)
})
// true
上面代码,Promise.reject方法的参数是一个thenable对象,执行以后,后面的catch方法的参数不是reject抛出的“出错了”这个字符串,而是thenable
例子:立即resolve的Promise对象,实在本轮“事件循环”的结束时,而不是在下一轮“事件循环”的开始时
setTimeout(()=>{
console.log("weiwei");
},0);
let thenable = {
str:function(){
console.log(123);
}
}
Promise.resolve(thenable).then(value=>{
console.log(value);//{str:f}
});
console.log("hongbao");//hongbao {str:f} weiwei
上面的代码中,setTimerout(fn,0),在下一轮“事件循环”开始时执行,Promise.resoolve()在本轮“事件循环”结束时执行,console.log(‘hongbao’)则是立即执行,因此最先输出。