Promise
Promise
是一门新的技术(ES6规范),JS中进行异步编程的新解决方案。(旧的方案是使用回调函数,比如AJAX请求)。
从语法上来说Promise
是一个构造函数。
从功能上来说Promise
对象用来封装一个异步操作并可以获取其成功/失败的结果值。
Promise初体验
<script>
//普通实现异步方法setTimeout()
const btn = document.querySelector('#btn');
btn.addEventListener('click',()=>{
setTimeout(()=>{
alert('1秒后执行');
},1000);
});
document.querySelector('#btn1').addEventListener('click',()=>{
//使用Promise
//1. resolve 函数类型数据,异步执行成功回调
//2. reject 函数类型数据,异步执行失败回调
const promise = new Promise((resolve,reject)=>{
setTimeout(()=>{
//获取1-10的随机数
let n = Math.floor(Math.random() * (10 - 1 + 1)) + 1;
if(n <= 5){
resolve(n); //将promise对象状态设置为 成功
console.log('resolve');
}else{
reject(n);//将promise对象状态设置为 失败
console.log('resolve');
}
},1000);
});
//调用then方法获取异步函数执行状态,执行的是resolve/reject
//接受两个函数 resolve & reject
promise.then((val)=>{
alert('resolve ' + val);
},(val)=>{
alert('reject ' + val);
});
});
</script>
catch方法
const promise = new Promise((resolve,reject)=>{
//获取1-10的随机数
let n = Math.floor(Math.random() * (10 - 1 + 1)) + 1;
if(n<=5){
resolve(n);
}else{
reject(n);
}
}).then((val)=>{
console.log('success' + val);
}).catch((err)=>{
console.log('failure' + err);
});
使用Promise封装AJAX请求
const btn = document.querySelector('#btn');
btn.addEventListener('click',()=>{
const promise = sendAJAX('http://localhost/test');
//调用then方法
promise.then((val)=>{
//成功
console.log(val);
},(val)=>{
//失败
console.log(val);
});
});
function sendAJAX(url){
const promise = new Promise((resolve,reject)=>{
//1. AJAX请求 , 创建http客户端
const http = new XMLHttpRequest();
//2. 初始化
http.open('GET',url);
//3. 发送请求
http.send();
//4. 处理响应结果
http.onreadystatechange = function(){
if(http.readyState === 4){
if(http.status == 200){
//成功
resolve(http.response);
}else{
//失败
reject(http.status);
}
}
}
});
return promise;
}
Promise属性
PromiseState:Promise状态
- pending:等待,初始化默认值
- resolved / fullfilled:表示成功
- rejected:表示失败
PromiseResult:保存着对象的结果。成功/失败
- resolve():resolve方法会把状态改为成功,并且存成功的结果
- reject():reject方法会把状态改为失败,并且保存失败结果
Promise方法
- Promise.resolve()方法:如果传入的参数是非Promise类型的对象,则返回结果是成功的Promise对象,如果传入的参数为Promise对象,则参数的结果决定了resolve的结果
let promise = Promise.resolve(1); console.log(promise); promise = Promise.resolve(new Promise((resolve,reject)=>{ //resolve(); reject(); })); console.log(promise);
- Promise.reject()方法:快速的返回一个失败的Promise对象,无论传入什么,返回结果都是失败。
let promise = Promise.reject(1) console.log(promise);
- Promise.all()方法:传入Promise数组,只有所有的Promise对象都成功才成功,只要有一个失败就直接失败。成功的返回结果是全部的Promise对象。无论有多少个失败,都会执行完全部的Promise。
const p1 = new Promise((resolve,reject)=>{ resolve(); console.log(1) }) const p2 = new Promise((resolve,reject)=>{ reject(); console.log(2) }) const p3 = new Promise((resolve,reject)=>{ reject(); console.log(3) }) let promises = Promise.all([p1,p2,p3]) console.log(promises);
- Promise.race()方法:传入Promise数组,第一个完成的Promise的结果的状态就是最终的结果状态。结果也是第一个成功返回的结果。
const p1 = new Promise((resolve,reject)=>{ resolve(); console.log(1) }) const p2 = new Promise((resolve,reject)=>{ reject(); console.log(2) }) const p3 = new Promise((resolve,reject)=>{ reject(); console.log(3) }) let promises = Promise.race([p1,p2,p3]) console.log(promises);
Promise关键知识
- 如何改变Promise状态
const promise = new Promise((resolve,reject)=>{ //1. 调用resolve()方法,改为成功状态 resolve(); //2. 调用reject()方法,改为失败状态 reject(); //3. 抛出一个异常改为失败状态 throw throw 'has error'; })
- 可以为Promise指定多个then函数,都会被执行
const promise = new Promise((resolve,reject)=>{ resolve(); }).then(()=>{ console.log(1); }).then(()=>{ console.log(2); }).then(()=>{ console.log(3); });
- then和catch函数,是执行器里执行reslove()或者reject()方法才会执行
const promise = new Promise((resolve,reject)=>{ setTimeout(()=>{ console.log('setTimeout'); resolve(); },2000) }).then(()=>{ console.log(1); }).then(()=>{ console.log(2); }).then(()=>{ console.log(3); });
Promise链式调用
Promise的then方法可以返回Promise对象,当返回Promise对象时,后续的then方法接受到的参数是上一个then返回Promise返回的对象的返回值,如下。
也就是说,可以实现对异步操作的链式调用,只用上一个异步执行接受,有返回值的时候才会执行下一个then,不需要自己去判断线程的状态。
//三个异步方法,最后输出为 1 2 3
const promise = new Promise((resolve,reject)=>{
//1. 第一个异步方法
setTimeout(()=>{
resolve(1);
},2000)
}).then((val)=>{
console.log(val);
return new Promise((resolve,reject)=>{
//2. 第二个异步方法
setTimeout(()=>{
resolve(2);
},1000)
})
}).then((val)=>{
console.log(val);
return new Promise((resolve,reject)=>{
//3. 第三个异步方法
setTimeout(()=>{
resolve(3);
},1000)
})
}).then((val)=>{
console.log(val);
});
链式调用的异常穿透
链式调用过程中,只需要有一个catch,如果其中某一环节出错,抛出异常throw 'error msg'
,则会执行catch的函数,不会继续执行接下来的任务。
const promise = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(1);
},2000)
}).then((val)=>{
console.log(val);
return new Promise((resolve,reject)=>{
setTimeout(()=>{
//抛出异常直接执行catch,不会执行继续执行,因为没有执行到resolve()方法
throw 'error';
resolve(2);
},1000)
})
}).then((val)=>{
console.log(val);
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(3);
},1000)
})
}).then((val)=>{
console.log(val);
}).catch(err=>{
console.log(err);
});
中断链式调用
- 中断链式调用的方法是返回一个空函数的Promise对象
new Promise(()=>{})
这样就不会跳入下一个then里面 - 在某些业务场景中可以抛出异常来中断Promise,如上异常穿透也是终止了链式调用。这种直接调用了catch,也属于另类的终止
promise = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(1);
},2000)
}).then((val)=>{
console.log(val);
//终止链式调用
return new Promise(()=>{})
}).then((val)=>{
console.log(2);
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(3);
},1000)
})
}).then((val)=>{
console.log(val);
}).catch(err=>{
console.log(err);
});