1、 Promise简介
Promise是一个对象,从它可以获取异步操作的消息。Promise提供统一的API,各种异步操作都可以用同样的方法进行处理。
Promise对象有以下两个特点:
1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:Pending
(进行中)、Resolved
(已完成,又称Fulfilled
)和Rejected
(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从Pending
变为Resolved
和从Pending
变为Rejected
。只要这两种情况发生,状态就固定,会一直保持这个结果。就算再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同。
注意:事件的特点是,如果错过了它,再去监听,是得不到结果的。 有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。 Promise也有一些缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。 如果某些事件不断地反复发生,一般来说,使用stream模式是比部署Promise更好的选择。
Promise 浏览器支持的情况:
Promise 是 ES6 新增加的,所以一些旧的浏览器并不支持,苹果的 Safari 10 和 Windows 的 Edge 14 版本以上浏览器才开始支持 ES6 特性。
具体支持情况:
Chrome 58、Edge 14、Firefox 54、Safari 10、Opera 55
2、Promise 的使用
Promise 构造函数只有一个参数,是一个函数,这个函数在构造之后会直接被异步运行,所以我们称之为起始函数。起始函数包含两个参数 resolve
和 reject
。
例如,
new Promise(function (resolve, reject) {
var x = 0;
var y = 1;
if (y == 0) reject("除数不能为零");
else resolve(x / y);
}).then(function (value) {
console.log("x / y = " + value);
}).catch(function (err) {
console.log(err);
}).finally(function () {
console.log("End");
});
输出结果:
x / y = 0
End
注意:
resolve
和 reject
都是函数,其中调用 resolve
代表一切正常,reject
是出现异常时所调用的。Promise 类有 .then()
.catch()
和 .finally()
三个方法,这三个方法的参数都是一个函数,.then()
可以将参数中的函数添加到当前 Promise 的正常执行队列,.catch()
则是设定 Promise 的异常处理序列,.finally()
是在 Promise 执行的最后一定会执行的序列。 .then()
传入的函数会按顺序依次执行,有任何异常都会直接跳到 catch
序列。
例如,
// 第一步:model层的接口封装
const promise = new Promise((resolve, reject) => {
// 这里做异步任务(比如ajax 请求接口。这里暂时用定时器代替)
setTimeout(function() {
var data = { retCode: 0, msg: 'qianguyihao' }; // 接口返回的数据
if (data.retCode == 0) {
// 接口请求成功时调用
resolve(data);
} else {
// 接口请求失败时调用
reject({ retCode: -1, msg: 'network error' });
}
}, 100);
});
// 第二步:业务层的接口调用。这里的 data 就是 从 resolve 和 reject 传过来的,也就是从接口拿到的数据
promise.then(data => {
// 从 resolve 获取正常结果
console.log(data);
}).catch(data => {
// 从 reject 获取异常结果
console.log(data);
});
Promise 处理 多次 Ajax 请求:
/*
基于Promise发送Ajax请求
*/
function queryData(url) {
var promise = new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState != 4) return;
if (xhr.readyState == 4 && xhr.status == 200) {
// 处理正常情况
resolve(xhr.responseText); // xhr.responseText 是从接口拿到的数据
} else {
// 处理异常情况
reject('接口请求失败');
}
};
xhr.responseType = 'json'; // 设置返回的数据类型
xhr.open('get', url);
xhr.send(null); // 请求接口
});
return promise;
}
// 发送多个ajax请求并且保证顺序
queryData('http://localhost:3000/api1')
.then(
data1 => {
console.log(JSON.stringify(data1));
// 请求完接口1后,继续请求接口2
return queryData('http://localhost:3000/api2');
},
error1 => {
console.log(error1);
}
)
.then(
data2 => {
console.log(JSON.stringify(data2));
// 请求完接口2后,继续请求接口3
return queryData('http://localhost:3000/api3');
},
error2 => {
console.log(error2);
}
)
.then(
data3 => {
// 获取接口3返回的数据
console.log(JSON.stringify(data3));
},
error3 => {
console.log(error3);
}
);
3、函数返回Promise对象
返回值为一个 Promise 对象的函数称作 Promise 函数,它常常用于开发基于异步操作的库。
例如,
/*
基于Promise发送Ajax请求
*/
function queryData(url) {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState != 4) return;
if (xhr.readyState == 4 && xhr.status == 200) {
// 处理正常情况
resolve(xhr.responseText);
} else {
// 处理异常情况
reject('接口请求失败');
}
};
xhr.responseType = 'json'; // 设置返回的数据类型
xhr.open('get', url);
xhr.send(null); // 请求接口
});
}
// 发送多个ajax请求并且保证顺序
queryData('http://localhost:3000/api1')
.then(
data1 => {
console.log(JSON.stringify(data1));
return queryData('http://localhost:3000/api2');
},
error1 => {
console.log(error1);
}
)
.then(
data2 => {
console.log(JSON.stringify(data2));
// 注意:返回的是 Promise 实例对象,
// 如果返回的是具体值时,则会产生一个新的默认的 promise实例,来调用这里的then,
// 确保可以继续进行链式操作获取结果。相当于return 'cjavapy';
return new Promise((resolve, reject) => {
resolve('cjavapy');
});
},
error2 => {
console.log(error2);
}
)
.then(data3 => {
console.log(data3);
});
4、Promise方法(Promise.all()和Promise.race())
Promise.all():并发处理多个异步任务,所有任务都执行成功,才能得到结果。
Promise.race(): 并发处理多个异步任务,只要有一个任务执行成功,就能得到结果。
Promise.all()示例:
var p1 = Promise.resolve(1),
p2 = Promise.resolve(2),
p3 = Promise.resolve(3);
Promise.all([p1, p2, p3]).then(function (results) {
console.log(results); // [1, 2, 3]
});
或者
/*
封装 Promise 接口调用
*/
function queryData(url) {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState != 4) return;
if (xhr.readyState == 4 && xhr.status == 200) {
// 处理正常结果
resolve(xhr.responseText);
} else {
// 处理异常结果
reject('服务器错误');
}
};
xhr.open('get', url);
xhr.send(null);
});
}
var promise1 = queryData('http://localhost:3000/p1');
var promise2 = queryData('http://localhost:3000/p2');
var promise3 = queryData('http://localhost:3000/p3');
Promise.all([promise1, promise2, promise3]).then(result => {
console.log(result);
});
Promise.race()示例:
var p1 = Promise.resolve(1),
p2 = Promise.resolve("error1"),
p3 = Promise.reject("error2");
Promise.race([p1, p2, p3]).then(function (results) {
console.log(results); //1
});
或者
/*
封装 Promise 接口调用
*/
function queryData(url) {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState != 4) return;
if (xhr.readyState == 4 && xhr.status == 200) {
// 处理正常结果
resolve(xhr.responseText);
} else {
// 处理异常结果
reject('服务器错误');
}
};
xhr.open('get', url);
xhr.send(null);
});
}
var promise1 = queryData('http://localhost:3000/p1');
var promise2 = queryData('http://localhost:3000/p2');
var promise3 = queryData('http://localhost:3000/p3');
Promise.race([promise1, promise2, promise3]).then(result => {
console.log(result);
});