ES6学习笔记——Promise(2)

8.3 Promise的基本使用
const pro = new Promise((resolve, reject)=>{
    // 未决阶段的处理
    // 通过调用resolve函数将Promise推向已决阶段的resolved状态
    // 通过调用reject函数将Promise推向已决阶段的rejected状态
    // resolve和reject均可以传递最多一个参数,表示推向状态的数据
})

pro.then(data=>{
    //这是thenable函数,如果当前的Promise已经是resolved状态,该函数会立即执行
    //如果当前是未决阶段,则会加入到作业队列,等待到达resolved状态后执行
    //data为状态数据
}, err=>{
    //这是catchable函数,如果当前的Promise已经是rejected状态,该函数会立即执行
    //如果当前是未决阶段,则会加入到作业队列,等待到达rejected状态后执行
    //err为状态数据
})

在这里插入图片描述

细节:

  1. 未决阶段的处理函数是同步的,会立即执行
  2. thenable和catchable函数是异步的,就算是立即执行,也会加入到事件队列中等待执行,并且,加入的队列是微队列
  3. pro.then可以只添加thenable函数,pro.catch可以单独添加catchable函数
  4. 在未决阶段的处理函数中,如果发生未捕获的错误,会将状态推向rejected,并会被catchable捕获
  5. 一旦状态推向了已决阶段,无法再对状态做任何更改
  6. Promise并没有消除回调,只是让回调变得可控
function biaobai(god) {
        return new Promise(resolve => {
             console.log(`邓哥向${god}发出了表白短信`);
             setTimeout(() => {
                 if (Math.random() < 0.3) {
                     //女神同意拉
                     resolve(true)
                 } else {
                     //resolve
                     resolve(false);
                 }
             }, 3000);
         })
     }
     biaobai("女神1").then(result => {
         console.log(result);
     })
const pro = new Promise((resolve, reject) => {
            console.log("未决阶段")
            setTimeout(() => {
                if (Math.random() < 0.5) {
                    resolve(123)
                } else {
                    reject(new Error("asdfasdf"));
                }
            }, 3000);
        })
        pro.then(data => {
            console.log(data);
        }, err => {
            console.log(err)
        })
 const pro = new Promise((resolve, reject) => {
            console.log("a")
            resolve(1);
            setTimeout(() => {
                console.log("b")   //  宏队列
            }, 0);
        })
        //pro: resolved
        pro.then(data => {
            console.log(data)    //  微队列
        })
        pro.catch(err => {
            console.log(err)
        })
        console.log("c")            
        //  执行顺序是:a c 1 b
 const pro = new Promise((resolve, reject) => {
            throw new Error("123"); // pro: rejected
        })
        pro.then(data => {
            console.log(data)   // 不会执行
        })
        pro.catch(err => {
            console.log(err)   // Error: 123
        })
//  一旦状态推向了已决阶段,无法再对状态做任何更改
const pro = new Promise((resolve, reject) => {
            throw new Error("abc");
            resolve(1); //无效
            reject(2); //无效
            resolve(3); //无效
            reject(4); //无效
        })
        pro.then(data => {
            console.log(data)
        })
        pro.catch(err => {
            console.log(err)   // Error: abc
        })
8.4 Promise的串联

当后续的Promise需要用到之前的Promise的处理结果时,这时就需要Promise的串联。

Promise对象中,无论是then方法还是catch方法,它们都具有返回值,返回的是一个全新的Promise对象,它的状态满足下面的规则:

  1. 如果当前的Promise是未决的,得到的新的Promise是挂起状态
  2. 如果当前的Promise是已决的,会运行相应的后续处理函数,并将后续处理函数的结果(返回值)作为resolved状态数据,应用到新的Promise中;如果后续处理函数发生错误,则把返回值作为rejected状态数据,应用到新的Promise中。

后续的Promise一定会等到前面的Promise有了后续处理结果后,才会变成已决状态

then返回的Promise的对象一开始一定是挂起状态。

注意:
thenable和catchable函数是异步的,就算是立即执行,也会加入到事件队列中等待执行,并且,加入的队列是微队列。

const pro1 = new Promise((resolve, reject) => {
            resolve(1)
        })
        const pro2 = pro1.then(result => {
            return result * 2 
            });       
        //pro2类型:Promise对象
        //pro2的状态:
        pro2.then(result => console.log(result * 2), err => console.log(err * 3))
   //输出:4     
const pro1 = new Promise((resolve, reject) => {
            throw 1;
        })
        const pro2 = pro1.then(result => {
            return result * 2
        }, err => {
            return err * 3;
        });
        pro1.catch(err => {
            return err * 2;
        })
        //pro2类型:Promise对象
        //pro2的状态:
        pro2.then(result => console.log(result * 2), err => console.log(err * 3))
        //输出:6
const pro1 = new Promise((resolve, reject) => {
            throw 1;
        })
        const pro2 = pro1.then(result => {
            return result * 2
        }, err => {
            throw err;
        });       
        //pro2类型:Promise对象
        //pro2的状态:
        pro2.then(result => console.log(result * 2), err => console.log(err * 3))
        //输出:3

如果前面的Promise的后续处理,返回的是一个Promise,则返回的新的Promise状态和后续处理返回的Promise状态保持一致。

 const pro1 = new Promise((resolve, reject) => {
            resolve(1);
        })
 const pro2 = new Promise((resolve, reject) => {
                resolve(2);
        })
  const pro3 = pro1.then(result =>{
				return pro2;
        })
   pro3.then(result => {
		console.log(result);
		})
	//  输出:2
const pro1 = new Promise((resolve, reject) => {
            resolve(1);
        })

        const pro2 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(2);
            }, 3000);
        })
        pro1.then(result => {
            console.log("结果出来了,得到的是一个Promise")
            return pro2;
        }).then(result => {
            console.log(result)   // 2 
        }).then(result => {
            console.log(result)   // undefined   上一次没有返回值,所以此处返回undefined
        })
        // 输出: 结果出来了,得到的是一个Promise
        // 		  2  (等两秒)
        //        undefined
		//获取李华所在班级的老师的信息  (数据在本地)
        //1. 获取李华的班级id   Promise
        //2. 根据班级id获取李华所在班级的老师id   Promise
        //3. 根据老师的id查询老师信息   Promise
        const pro = ajax({
            url: "./data/students.json"
        })
        pro.then(resp => {
            for (let i = 0; i < resp.length; i++) {
                if (resp[i].name === "李华") {
                    return resp[i].classId; //班级id
                }
            }
        }).then(cid => {
            return ajax({
                url: "./data/classes.json?cid=" + cid
            }).then(cls => {
                for (let i = 0; i < cls.length; i++) {
                    if (cls[i].id === cid) {
                        return cls[i].teacherId;
                    }
                }
            })
        }).then(tid => {
            return ajax({
                url: "./data/teachers.json"
            }).then(ts => {
                for (let i = 0; i < ts.length; i++) {
                    if (ts[i].id === tid) {
                        return ts[i];
                    }
                }
            })
        }).then(teacher => {
            console.log(teacher);
        })
function biaobai(god) {
            return new Promise(resolve => {
                console.log(`邓哥向${god}发出了表白短信`);
                setTimeout(() => {
                    if (Math.random() < 0.3) {
                        //女神同意拉
                        resolve(true)
                    } else {
                        //resolve
                        resolve(false);
                    }
                }, 500);
            })
        }
		/*
            邓哥心中有五个女神
            有一天,邓哥决定向第一个女神表白,如果女神拒绝,则向第二个女神表白,直到所有的女神都拒绝,或有一个女神同意为止
            用代码模拟上面的场景
        */
        const gods = ["女神1", "女神2", "女神3", "女神4", "女神5"];
        let pro;
        for (let i = 0; i < gods.length; i++) {
            if (i === 0) {
                pro = biaobai(gods[i]);
            }
            pro = pro.then(resp => {
                if (resp === undefined) {
                    return;
                } else if (resp) {
                    console.log(`${gods[i]}同意了`)
                    return;
                } else {
                    console.log(`${gods[i]}拒绝了`)
                    if (i < gods.length - 1) {
                        return biaobai(gods[i + 1]);
                    }
                }
            })
        }
8.5 Promise的其他api
原型成员 (实例成员)
  • then:注册一个后续处理函数,当Promise为resolved状态时运行该函数
  • catch:注册一个后续处理函数,当Promise为rejected状态时运行该函数
  • finally:[ES2018]注册一个后续处理函数(无参),当Promise为已决时运行该函数
// 无论是resolve还是reject的,  finally 都会执行,并且是无需传参的。
const pro = new Promise((resolve, reject) => {
            resolve(1);
        })
        pro.finally(() => console.log("finally1"))
        pro.then(resp => console.log("then2", resp * 2));
		pro.catch(resp => console.log("catch2", resp * 2));
		// finally1    then2  2
构造函数成员 (静态成员)
  • resolve(数据):该方法返回一个resolved状态的Promise,传递的数据作为状态数据
    - 特殊情况:如果传递的数据是Promise,则直接返回传递的Promise对象

  • reject(数据):该方法返回一个rejected状态的Promise,传递的数据作为状态数据

 const pro = new Promise((resolve, reject) => {
         resolve(1);
      })
        //等效于:
const pro = Promise.resolve(1);

const pro = new Promise((resolve, reject) => {
         reject(1);
     })
  //等效于:
 const pro = Promise.reject(1);

resolve的特殊情况:如果传递的数据是Promise,则直接返回传递的Promise对象

const p = new Promise((resolve, reject) => {
            resolve(3);
        })
        // const pro = Promise.resolve(p);
        //等效于
        const pro = p;
        console.log(pro === p)   // true
  • all(iterable):这个方法返回一个新的promise对象,该promise对象在iterable参数对象里所有的promise对象都成功的时候才会触发成功,一旦有任何一个iterable里面的promise对象失败则立即触发该promise对象的失败。这个新的promise对象在触发成功状态以后,会把一个包含iterable里所有promise返回值的数组作为成功回调的返回值,顺序跟iterable的顺序保持一致;如果这个新的promise对象触发了失败状态,它会把iterable里第一个触发失败的promise对象的错误信息作为它的失败错误信息。Promise.all方法常被用于处理多个promise对象的状态集合。
function getRandom(min, max) {
            return Math.floor(Math.random() * (max - min)) + min;
        }
        const proms = [];
        for (let i = 0; i < 10; i++) {
            proms.push(new Promise((resolve, reject) => {
                setTimeout(() => {
                    if (Math.random() < 0.5) {
                        console.log(i, "完成");
                        resolve(i);
                    } else {
                        console.log(i, "失败")
                        reject(i);
                    }
                }, getRandom(1000, 5000));
            }))
        }
        //等到所有的promise变成resolved状态后输出: 全部完成
        const pro = Promise.all(proms)
        pro.then(datas => {
            console.log("全部完成", datas); // 只有当全部完成才会执行
        })
        pro.catch(err => {
            console.log("有失败的", err);  // 有失败的会立即执行这里,
        })
        console.log(proms);
  • race(iterable):当iterable参数里的任意一个子promise被成功或失败后,父promise马上也会用子promise的成功返回值或失败详情作为参数调用父promise绑定的相应句柄,并返回该promise对象
 function getRandom(min, max) {
            return Math.floor(Math.random() * (max - min)) + min;
        }
        const proms = [];
        for (let i = 0; i < 10; i++) {
            proms.push(new Promise((resolve, reject) => {
                setTimeout(() => {
                    if (Math.random() < 0.5) {
                        console.log(i, "完成");
                        resolve(i);
                    } else {
                        console.log(i, "失败")
                        reject(i);
                    }
                }, getRandom(1000, 5000));
            }))
        }
        //等到所有的promise变成resolved状态后输出: 全部完成
        const pro = Promise.race(proms)
        pro.then(data => {
            console.log("有人完成了", data);  // 只要有人完成就执行。
        })
        pro.catch(err => {
            console.log("有人失败了", err);   // 只要有人失败就执行。
        })
        console.log(proms);
  /*
	  邓哥心中有二十个女神,他决定用更加高效的办法
	   他同时给二十个女神表白,如果有女神同意,就拒绝其他的女神
	   并且,当所有的女神回复完成后,他要把所有的回复都记录到日志进行分析
	   用代码模拟上面的场景
  */
      function biaobai(god) {
          return new Promise((resolve, reject) => {
              console.log(`邓哥向女神【${god}】发出了表白短信`);
              setTimeout(() => {
                  if (Math.random() < 0.05) {
                      //女神同意拉
                      console.log(god, "同意")
                      resolve(true);
                  } else {
                      console.log(god, "拒绝")
                      resolve(false);
                  }
              }, Math.floor(Math.random() * (3000 - 1000) + 1000));
          })
      }
      const proms = [];
      let hasAgree = false; //是否有女神同意
      for (let i = 1; i <= 20; i++) {
          const pro = biaobai(`女神${i}`).then(resp => {
              if (resp) {
                  if (hasAgree) {
                      console.log("发错了短信,邓哥很机智的拒绝了")
                  } else {
                      hasAgree = true;
                      console.log("邓哥很开心,终于成功了!");
                  }
              }
              return resp;
          })
          proms.push(pro);
      }
      Promise.all(proms).then(results => {
          console.log("日志记录", results);
      })
async和await

asyncawait是 ES2016 新增两个关键字,它们借鉴了 ES2015 中生成器在实际开发中的应用,目的是简化 Promise api 的使用,并非是替代 Promise。

async

目的是简化在函数的返回值中对Promise的创建

async 用于修饰函数(无论是函数字面量还是函数表达式),放置在函数最开始的位置,被修饰函数的返回结果一定是 Promise 对象。

async function test(){
    console.log(1);
    return 2;
}
//等效于
function test(){
    return new Promise((resolve, reject)=>{
        console.log(1);
        resolve(2);
    })
}
await

await关键字必须出现在async函数中!!!!

await用在某个表达式之前,如果表达式是一个Promise,则得到的是thenable中的状态数据。

async function test1(){
    console.log(1);
    return 2;
}
async function test2(){
    const result = await test1();
    console.log(result);
}
test2();

//等效于
function test1(){
    return new Promise((resolve, reject)=>{
        console.log(1);
        resolve(2);
    })
}

function test2(){
    return new Promise((resolve, reject)=>{
        test1().then(data => {
            const result = data;
            console.log(result);
            resolve();
        })
    })
}
test2();

举栗子:

async function test1() {
            console.log(1);
            return 2;
        }
        async function test2() {
            const result = await test1();
            console.log(result);
        }

        test2();  
        //  输出  1  2
		//还是获取李华所在班级的老师的信息     
        //1. 获取李华的班级id   Promise
        //2. 根据班级id获取李华所在班级的老师id   Promise
        //3. 根据老师的id查询老师信息   Promise
        async function getTeacher() {
            const stus = await ajax({
                url: "./data/students.json"
            })
            let cid;
            for (let i = 0; i < stus.length; i++) {
                if (stus[i].name === "李华") {
                    cid = stus[i].classId;
                }
            }
            const cls = await ajax({
                url: "./data/classes.json"
            })
            let tid;
            for (let i = 0; i < cls.length; i++) {
                if (cls[i].id === cid) {
                    tid = cls[i].teacherId;
                }
            }
            const ts = await ajax({
                url: "./data/teachers.json"
            })
            for (let i = 0; i < ts.length; i++) {
                const element = ts[i];
                if (element.id === tid) {
                    console.log(element);
                }
            }
        }
        getTeacher();   
        //  这样子书写就看着很舒服了!!!!
		function biaobai(god) {
		     return new Promise(resolve => {
		           console.log(`邓哥向${god}发出了表白短信`);
		           setTimeout(() => {
		               if (Math.random() < 0.3) {
		                   //女神同意拉
		                   resolve(true)
		               } else {
		                   //resolve
		                   resolve(false);
		               }
		           }, 500);
		       })
		       }
        /*
            邓哥心中有三个女神
            有一天,邓哥决定向第一个女神表白,如果女神拒绝,则向第二个女神表白,直到所有的女神都拒绝,或有一个女神同意为止
            用代码模拟上面的场景
        */
        (async () => {
            const gods = ["女神1", "女神2", "女神3", "女神4", "女神5"];
            for (let i = 0; i < gods.length; i++) {
                const g = gods[i];
                // 当前循环等待的Promise没有resolve,下一次循环不运行
                const result = await biaobai(g);
                if (result) {
                    console.log(`${g}同意了,不用再表白了!!!`);
                    break;
                } else {
                    console.log(`${g}没有同意`)
                }
            }
        })()
// 通过改造计时器函数,从而方便使用async
function delay(duration) {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    resolve();
                }, duration);
            })
        }
        async function biaobai(god) {
            console.log(`邓哥向${god}发出了表白短信`);
            await delay(500);
            return Math.random() < 0.3;
        }
  (async () => {
            const gods = ["女神1", "女神2", "女神3", "女神4", "女神5"];
            for (let i = 0; i < gods.length; i++) {
                const g = gods[i];
                // 当前循环等待的Promise没有resolve,下一次循环不运行
                const result = await biaobai(g);
                if (result) {
                    console.log(`${g}同意了,不用再表白了!!!`);
                    break;
                } else {
                    console.log(`${g}没有同意`)
                }
            }
        })()

如果await的表达式不是Promise,则会将其使用Promise.resolve包装后按照规则运行。

async function test() {
	  const result = await 1;
	  console.log(result)
	}
// 相当于这种写法:
//function test(){
//	return new Promise((resolve,reject) =>{
//		Promise.resolve(1).then(data =>{
//			const result = data;
//			console.log(result);
//			resolve();
//		})
//	})
//}
	test();
	console.log(123);  // 先输出123  在输出1

若需要拿到错误状态,可以利用try catch进行处理。

async function getPromise() {
            if (Math.random() < 0.5) {
                return 1;
            } else {
                throw 2;
            }
        }
        async function test() {
            try {   
                const result = await getPromise();
                console.log("正常状态", result)
            } catch (err) {  
                console.log("错误状态", err);
            }
        }
        test();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值