什么是promise?
总所周知,JS是单线程的。但是我们又要让它实现多线程的效果,最大众的方法就是用异步。而promise就是更简洁方便的异步编程方案。
// 平常我们所使用的异步,如AJAX
...
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
}
}
...
使用promise后
const ajax = function(url) {
const promise = new Promise(function(resolve, reject){
const handler = function() {
if (this.readyState == 4 && 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;
};
// 下面是精华
ajax("/posts.json").then(function(json) {
console.log('Contents: ' + json);
}, function(error) {
console.error('出错了', error);
});
这样就比原生的js方法简洁明了很多,并且有利于复用。这种链式写法的好处在于,先统一执行AJAX逻辑,不关心如何处理结果,然后,根据结果是成功还是失败,在将来的某个时候调用success函数或fail函数。
promise的用法
首先,promise是一个对象,我们使用它时,必须要new一个Promise实例。
var p = new Promise(function);//这里传入的参数是需要执行的函数
其次,promise使用方法
var p = new Promise(function(resolve,reject){
if(xxxx){
resolve("yes");
}else{
reject("no");
}
});
p.then(function(successState){
console.log(successState);
}).catch(function(failState){
console.log(failState);
})
这里可以显然易见,
1. 创建promise实例,实例传入要执行的函数。函数可以传入两个参数(函数):一个是函数执行成功后需要回调的函数,一个是失败后需要回调的函数。
2. 创建完毕后,使用then来传入resolve,使用catch来传入reject。
promise的好处显然可见: 是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了,也方便复用。
promise使用方法扩展
promise之resolve(promise)
有一点需要注意的是,resolve函数返回的是promise对象。即使不是promise对象的参数传入resolve函数,返回的依然是promise对象。
var original = Promise.resolve('我在第二行');
var cast = Promise.resolve(original);
cast.then(function(value) {
console.log('value: ' + value);
});
console.log('original === cast ? ' + (original === cast));
/*
* 打印顺序如下,这里有一个同步异步先后执行的区别
* original === cast ? true
* value: 我在第二行
*/
promise串用
var a = 1;
var p = new Promise((resolve,reject)=>{
if(a === 1){
resolve("yes1");
}else{
reject("no1");
}
});
var p2 = new Promise((resolve,reject)=>{
if(a === 1){
resolve("yes2");
}else{
reject("no2");
}
});
p.then((state1)=>{
console.log(state1); // yes1
return p2;
//这里返回一个设置好的promise是为了下面的then传参。
//如果没有这个p2,虽然下面的then也可以用,但是state2参数为underfined
}).then((state2)=>{
console.log(state2); // yes2
}).catch((failState)=>{
console.log(failState);
});
这里有必要说一下,promise的catch方法是冒泡传递的,所以把它放在最后没毛病。只要中间过程中有个reject了,后面的将不会再执行,并且返回reject();如,
var a = 1;
var p = new Promise((resolve,reject)=>{
if(a === 1){
resolve("yes1");
}else{
reject("no1");
}
});
var p2 = new Promise((resolve,reject)=>{
if(a === 2){ //这里判断条件改为2
resolve("yes2");
}else{
reject("no2");
}
});
var p3 = .... //与上面 p1,p2一样
p.then((state1)=>{
console.log(state1); // yes1
return p2; // 返回reject(),故下面then不执行
}).then((state2)=>{
console.log(state2);
return p3;
}).then((state3)=>{
console.log(state3);
}).catch((failState)=>{
console.log(failState); // no2,捕抓到p2冒泡的reject
});
promise的并用
Promise.all()方法
all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。
// 延用上面p1,p2,p3的例子
Promise
.all([p1, p2, p3]) //这里传入的参数必须是以数组的形式
.then((results)=>{
console.log(results); //返回的是一个数组
}).catch((fail)=>{
console.log(fail); //返回的是失败的promise的reject()
});
只有当p1,p2,p3都成功执行完了,返回的都是resolve()后,才会进行到then();若是p1,p2,p3中有一个返回的是reject(),那么会直接进入catch();
Promise.race()方法
该方法就像他的名字一样,”race”竞速;仍然以p1,p2,p3为例子
Promise
.race([p1, p2, p3])
.then(function(results){
console.log(results); // yes1
}).catch((fail)=>{
console.log(fail); //返回的是失败的promise的reject()
});
p1,p2,p3当中只要有一个执行完成了,进入resolve()回调,就立马进入then()方法。剩下的两个不再执行。也就是“谁快就运行谁的回调”(race竞速)。