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 & rejectpromise.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. 抛出一个异常改为失败状态 throwthrow '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 3const 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);});