一个 Promise 对象代表一个在这个 promise 被创建出来时不一定已知值的代理。它让你能够把异步操作最终的成功返回值或者失败原因和相应的处理程序关联起来。这样使得异步方法可以像同步方法那样返回值:异步方法并不会立即返回最终的值,而是返回一个 promise,以便在未来某个时候把值交给使用者。
Promise对象有三种状态:
1.pending:刚刚创建一个Promise实例的时候,表示初始状态;
2.fulfilled:resolve方法调用的时候,表示操作成功;
3.rejected:reject方法调用的时候,表示操作失败;
状态只能从 初始化 -> 成功 或者 初始化 -> 失败,不能逆向转换,也不能在成功fulfilled 和失败rejected之间转换。
Promise对象是全局对象,你也可以理解为一个类,创建Promise实例的时候,要使用new关键字。参数是一个匿名函数,其中有两个参数:resolve(解决)和reject(拒绝),两个参数均为方法。resolve方法用于处理异步操作成功后业务;reject方法用于操作异步操作失败后的业务。
- let pro = new Promise(function(resolve,reject){
- // 异步操作
- // if(结果){
- // 成功操作
- // resolve('成功返回值')
- // }else{
- // 失败操作
- // resolve('失败返回值')
- // }
- })
- console.log(pro);
- //
- Promise {
} - // [[Prototype]]: Promise
- // [[PromiseState]]: "pending"
- // [[PromiseResult]]: undefined
-
- // 打印一个失败示例值
- Promise {
} - // [[Prototype]]: Promise
- // [[PromiseState]]: "rejected" // 状态
- // [[PromiseResult]]: 2 // 值
打印出来的值 就是上文提到的promise对象,那么我们想取到值就需要用到 Promise 的链式调用
.then() 和 .catch() 一般情况then接收成功,catch接收失败
他们都有一个回调函数作为参数,回调函数中的 参数 就是我们想要的值,并且在then中 return的值会是一个promise对象,供我们下一个then拿到,这样也就解决了‘回调地狱’的嵌套式请求,改成了链式的代码,维护性,易读性更强
写一个简单的定时器模拟请求案例:
- let pro2 = new Promise(function(res,rej){
- setTimeout(function(){
- res(1)
- },1000)
- // setTimeout(function(){
- // rej(500)
- // },1000)
- })
-
- pro2.then(res => {
- console.log('res',res)
- return res
- }).then(res => {
- let add = res+1
- console.log(res+1);
- return add
- }).catch(rej => {
- console.log('rej',rej);
- return rej+1
- }).then(res => {
- console.log(res);
- }).catch(rej => {
- console.log(rej);
- })
-
- pro2状态为成功,值为1
- 第一次打印 res 1
- 第二次打印 2
- 第三次打印 2
-
- pro2状态为失败,值为500
- 第一次打印 rej 500
- 第二次打印 501
两个定时器模拟请求,返回成功 1,失败 2(可以自己注释一下是失败,看看成功的状态)
catch如果return了值,会被下一个then接收,但是promise是封装请求,也不需要这样多层嵌套,一般情况是先 .then 一层或两层,然后在 .catch 进行收尾
简单封装一下ajax
- let api = function(url,type,data) {
- return new Promise(function(resolve,reject){
- $.ajax({
- url:url,
- type:type,
- data:data,
- success(res){
- resolve(res)
- },
- error(error){
- reject(error)
- }
- })
- })
- }
- let apiA = (data) => api('请求地址','请求方式',data)
-
- apiA({number:3}).then((res)=>{
- console.log(res);
- }).catch((error)=>{
- console.log(error);
- })
Promise.all()方法:接受一个数组作为参数,数组的元素是Promise实例对象 ,如果所有的 promise 都成功了,它会把一个包含 数组 里所有 promise 返回值的数组作为成功回调的返回值。顺序跟 数组参数的顺序保持一致。如果一个失败,会返回 失败的 值并停止,不会继续往下进行
Promise.race()方法:它的参数要求跟Promise.all()方法一样,不同的是,它参数中的promise实例,只要有一个状态发生变化(不管是成功fulfilled还是异常rejected),它就会有返回,其他实例中状态再发生变化,也不会再被捕获。
只例出promise.all:promise.race()使用语法一致
- let pro = new Promise(function(resolve,reject){
- resolve(1)
- // reject(2)
- })
- let pro2 = new Promise(function(resolve,reject){
- // resolve(3)
- reject(4)
- })
-
- Promise.all([pro,pro2]).then(res => {
- console.log('res',res);
- }).catch(err => {
- console.log('err',err);
- })
- // 打印: err 4
es7提供了两个新关键字:async和await关键字让我们可以用一种更简洁的方式写出基于Promise的异步行为,而无需刻意地链式调用Promise。而是用 await 处理promise,运行到 await 后,暂停 async 方法,等待await处理的promise的状态确定后,再恢复 async 方法继续执行
基础语法: async定义异步方法,await处理异步promise
- async function demo(){
- let num1 = await Promise.resolve(1)
- let num2 = await new Promise((resolve,reject)=>{
- setTimeout(()=>{
- console.log('定时器执行')
- resolve(2)
- // reject('出错啦')
- },2000)
- })
- console.log('两个异步结束了');
- return num1+num2
- }
- demo().then(res => {
- console.log('res',res);
- }).catch(err => {
- console.log('err',err);
- })
- // 成功一秒后 打印
- 定时器执行 两个异步结束了 res 3
- // 失败
- 定时器执行 两个异步结束了 rej 出错啦
使用 async 为前缀定义方法,方法中才会识别await,想要使用 await 处理promise,方法前必须有async。
await处理后我们直接 可以用变量接收 promise 的值,成功后return返回的值会是一个promise可以被then接收,但是注意如果 promise 状态为失败,和promise.all一样,该方法会返回一个失败状态的promise,值就是第一个错误的信息。
一个不含 await 表达式的 async 函数是会同步运行的。然而,如果函数体内有一个 await 表达式,async 函数就一定会异步执行。其实 async 函数异步执行,并且返回值还是一个promise,也意味着我们可以用 另一个 async 函数继续 操作它的返回值。