回调地狱的终结者----promise

前言

promise是Es6新增的,本身是一个构造函数,promise对象用来封装异步代码,可以获取成功/失败的返回值。promise的引入也是为了解决在异步js中回调函数嵌套太多,进而形成回调地狱的问题。(回调地狱的特点-不便于阅读-不利于维护)

例子

比如现在你玩一个游戏,进行闯关,一共有5个关卡,每一关需要时间为1秒,如果成功就会进入下一关卡,如果某个关卡失败就结束游戏,当5个关卡全部通过,就是通关。

用我们原生的js来实现就是

//这里我们用Math.round(Math.random())表示在0-1之间四舍五入,来决定是否能通过某个关卡。
setTimeout(()=>{
      if(Math.round(Math.random())){
        console.log("通过第一关");
        setTimeout(()=>{
          if(Math.round(Math.random())){
            console.log("通过第二关");
            setTimeout(()=>{
              if(Math.round(Math.random())){
                console.log("通过第三关");
                setTimeout(()=>{
                  if(Math.round(Math.random())){
                    console.log("通过第四关");
                    setTimeout(()=>{
                      if(Math.round(Math.random())){
                        console.log("通过第五关");
                        console.log("恭喜你,通关啦。");
                      }else{
                        console.log("提示:就差最后一关没通过");
                      }
                    },1000)
                  }else{
                    console.log("提示:还剩两关没通过");
                  }
                },1000)
              }else{
                console.log("提示:还剩三关没通过");
              }
            },1000)
          }else{
            console.log("提示:就通过了前两关卡,实力有点不行啊");
          }
        },1000)
      }else{
        console.log("提示:太菜了第一关都没过");
      }
    },1000)
复制代码

乍眼一看,我们这个代码实在有些头秃,非常不便于我们去阅读和维护。那么这个例子我们可以用promise方法来实现么?

Promise

Promise状态

Promise对象 本质上代表的是一个未完成,但预计将要完成的操作。 有三种状态: pending:初始值 fulfilled:成功的状态 rejected:失败的状态

promise构造函数中需要传入一个回调函数,该函数有两个参数:resolve和reject。
resolve函数:会将promise对象的状态从pending变为fulfilled。
reject函数:会将promise对象的状态从pending变为rejected。
复制代码

Promise方法

resolve方法:他会返回一个成功状态的promise对象

  let eg1 = Promise.resolve("ok");//OK可更改,自己定义的
  console.log(eg1);
复制代码

image.png reject方法:他会返回一个失败状态的promise对象

let eg2 = Promise.reject("error");//error可更改,自己定义的
console.log(eg2);
复制代码

image.png all方法:接收一个包含多个promise对象的数组。 返回值:如果传入的promise对象都是成功的,返回一个成功的promise对象。只要有一个失败,则返回一个失败的promise对象。

let eg1 = Promise.resolve("ok1");
let eg2 = Promise.reject("error2");
let eg3 = Promise.resolve("ok3");
let eg4 = Promise.reject("error4");
let egall = Promise.all([eg1,eg3]);//结果1
 let egall = Promise.all([eg1, eg3,eg2]);//结果2

复制代码

结果1 image.png 结果2 image.png 了解了这些我们来看看用promise如何实现我们上边的例子

 // 封装一个方法
    function getAllow(data,err) {
      // 将promise对象return出去
      return new Promise((resolve,reject) => {
        setTimeout(() => {
          if (Math.round(Math.random())) {
            //成功
            resolve(data)
          } else {
            //失败
            reject(err)
          }
        }, 1000)
      })
      
    }
    //结果是一个promise对象
    getAllow("通过第一关","提示:太菜了第一关都没过").then((data)=>{
      console.log(data);
      return getAllow("通过第二关","提示:就通过了前两关卡,实力有点不行啊");
    }).then((data)=>{
      console.log(data);
      return getAllow("通过第三关","提示:还剩三关没通过");
    }).then((data)=>{
      console.log(data);
      return getAllow("通过第四关","提示:还剩两关没通过");
    }).then((data)=>{
      console.log(data);
      return getAllow("通过第五关","提示:就差最后一关没通过");
    }).then((data)=>{
      console.log(data);
      console.log("恭喜你,通关啦。");
    }).catch((err)=>{
      console.log(err);
    })
复制代码

看到这个代码我们可以明显感觉到,简洁工整了许多。。。别急,这还没有结束✈

asyncawait

async

async:异步,用来声明异步函数,该函数会返回一个promise对象。

    async function fn(){
      if (Math.round(Math.random())) {
        // 默认返回一个成功状态的promise对象。 该对象的结果由 return来决定。
        return "ok"
      }else{
        //抛出错误时,返回一个失败状态的promise对象
        throw new Error("失败了")
      }
    }
    let eg1 = fn();
    eg1.then((data)=>{
      //获取成功的值,在then的回调函数中定义一个形参接受。
      console.log(data);//ok
    }).catch((err)=>{
      //获取失败的信息,在catch的回调函数中定义一个形参接受。
      console.log(err);
    })
    console.log(eg1);
复制代码

await

await的用法:

  • await关键字必须写在async函数中。但是async函数可以没有await。
  • await右侧书写表达式,表达式一般返回值为promise对象。
  • await返回的是promise成功的结果。
  • await的promise失败了,就会抛出异常,可以通过tryCatch来处理异常。
    const eg1 = new Promise((resolve,reject)=>{
      if (Math.round(Math.random())) {
        resolve("成功了")
      } else {
        reject("失败了")
      }
      
    });
    async function fn(){
      try {
        // res的值就是promise成功的值。
        let res = await eg1;
        console.log(res);  //成功了
      } catch (error) {
        // error就是promise对象失败时,传入的数据。
        console.log(error); //失败了
      }
    }
    fn();
复制代码

await+async来实现上述案例

 function getAllow(data, err) {
      // return出去一个promise对象
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          if (Math.round(Math.random())) {
            //成功了
            resolve(data)
          } else {
            //失败了 
            reject(err)
          }
        }, 100)
      })
    }
    async function main() {
      try {
        //如果成功,first变量中的就是成功后的结果  18行的data
        let first = await getAllow("通过第一关", "提示:太菜了第一关都没过");
        console.log(first);
        let second = await getAllow("通过第二关", "提示:就通过了前两关卡,实力有点不行啊");
        console.log(second);
        let thired = await getAllow("通过第三关", "提示:还剩三关没通过");
        console.log(thired);
        let fourth = await getAllow("通过第四关", "提示:还剩两关没通过");
        console.log(fourth);
        let fifth = await getAllow("通过第五关", "提示:就差最后一关没通过");
        console.log(fifth);
        console.log("恭喜你,通关啦。");
      } catch (error) {
        console.log(error);
      }
    }
    main();
复制代码

猜你喜欢

转载自juejin.im/post/7041880083165872164