淘先锋技术网

首页 1 2 3 4 5 6 7

javascript中Promise深入理解

因为js是单线程的脚本语言,所以在执行代码时会先执行主程序中的代码,如果需要加载的程序,会先加载,待其加载完成后,将其丢到主程序中执行。
下面是一个简单的异步操作:

<!DOCTYPE html>
<html lang="cn">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    div{
      width: 200px;
      height: 200px;
      background: green;
      position: absolute;
      left:0px;
    }
  </style>
</head>
<body>
  <div></div>
  <script>
    function interval(callback,time){
      let id = setInterval(()=>{
        callback(id)
      },time)
    }
    interval((idC)=>{
      let div = document.querySelector("div");
      let left = parseInt(window.getComputedStyle(div).left);
      div.style.left = left+ 10+"px";
      if(left >=200){
        clearInterval(idC);
      }
    },100)
    console.log("2021");
    // 注意:在js的定时器中,定时器返回的值是定时器的编号。
    // 因为js是单线程的语言,所以在js中只会执行主程序,不断轮询主程序
  </script>
</body>
</html>

这里设置定时器,因为定时器需要等待,所以当该程序运行时,会将定时器模块丢到定时器模块加载,此时主程序会将主程序中的文件先执行,待定时器模块加载完毕后,会将其丢到主程序中等待执行。此时主程序会不断地进行轮询操作。
下面是图片加载操作:

<!DOCTYPE html>
<html lang="cn">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script>
    function imageLoad(src, resolve, reject) {
      let image = new Image();
      image.src = src;
      image.onload = resolve(image);
      image.onerror = reject;
    }
    setTimeout(() => {
      imageLoad('./img_1.jpg', function () {
        document.body.appendChild(arguments[0]);
        console.log("图片加载成功");
      }, () => {
        console.log("图片加载失败");
      })
    }, 1)
    console.log("图片加载的小demo");

    // 这里是异步处理,首先图片加载需要耗时,所以会在另一个内存空间内进行处理,当处理完成后,处理的结果会返回主程序
    // 此时javascript会优先处理主程序中的程序,并且会不断的轮询其他完成了的程序
  </script>
</body>

</html>

解析:这里是异步处理,首先图片加载需要耗时,所以会在另一个内存空间内进行处理,当处理完成后,处理的结果会返回主程序。此时javascript会优先处理主程序中的程序,并且会不断的轮询其他完成了的程序。
Promise简介:

<script>
    new Promise((resolve,reject)=>{
      resolve("解决")
    }).then((value)=>{
      console.log("成功1");
    },()=>{
      console.log("失败1");
    }).then((value)=>{
      console.log("成功2");
    },()=>{
      console.log("失败2");
    })
    console.log("这里是主程序");
</script>

解析:这里是Promise对象设置一个异步操作,传入两个参数表示状态,只有当状态改变的时候才能执行下面的then操作,不设置状态表现是pending状态。当设置状态是resolve时表示状态解决,当设置reject时表示失败状态。同时then中传入的两个参数是两个处理函数,分别是对成功和失败的情况下进行处理的操作。
②上面代码中的最后一个是主程序,上面的Promise是微程序,我们上面的代码中的图片加载以及定时器操作都是宏程序。主程序的处理次序要优先于微程序,微程序的处理次序要优先于宏程序。
各类程序的优先次序

<script>
setTimeout(function(){
      console.log("setTimeOut");
    },0);
    new Promise((resolve,reject)=>{
      resolve();
      console.log("Promise");
    }).then(()=>{
      console.log("成功");
    })
    console.log("主程序");
    // 上面几个顺序是:
    // Promise
    // 主程序
    // 成功
    // setTimeout

</script>

解析:上面程序中的定时器会先放到宏任务中进行加载,Promise中的console.log(“Promise”);会放到主程序中进行加载,然后通过状态改变开启一个微任务,由于主程序中的操作优先于微程序中的任务,优先于宏任务中的任务。所以上面便是最终的结果。

<script>
new Promise((resolve)=>{
      console.log("哈哈哈哈");
      setTimeout(function(){
        resolve();
        console.log("setTimeOut");
      },0)
    }).then(()=>{
      console.log("成功");
    })
    console.log("主程序");
    // 打印的结果是
    // 哈哈哈哈
    // 主程序
    // setTimeout
    // 成功
</script>

解析:在promise中刚开始的哈哈哈哈语句是放到主程序中执行。并且其中存放了一个setTimeOut,所以会放到宏任务中。在宏任务中的内容开始到主程序执行的时候,此时setTimeOut语句就会在主程序中执行,但是resolve()这样一个微任务程序,会在微任务序列中等待执行,所以最后执行成功。

<script>
    let p1 = new Promise((resolve,reject)=>{
      // resolve("成功aaaa");
      reject("失败")
    });
    console.log(p1);
    let p2 = new Promise((resolve,reject)=>{
      resolve(p1);
    }).then((msg)=>{
      console.log(msg);
    },()=>{
      console.log('失败');
    });

</script>

解析:当一个Promise对象作为一个参数传入下一个Promise对象中.如果传入的promise对象为失败状态,则下一个Promise也是失败状态。第二:promise()对象状态一旦确定,就不可以更改
Promise中的then

<script>
 <script>
    new Promise((resolve,reject)=>{
      resolve("成功了");
      // reject("失败了")
    }).then(value=>{
      console.log(value);
    },reason=>{
      console.log(reason);
    })

    // 解析:只有当resolve或者reject执行的时候,才能将程序放置到微任务程序中
    // 如果仅仅想要讨论一种状态,另外一种状态可以省略,必要时可以使用null。
  </script>
</script>

解析:只有当resolve或者reject执行的时候,才能将程序放置到微任务程序中。如果仅仅想要讨论一种状态,另外一种状态可以省略,必要时可以使用null。
then的状态

<script>
  <script>
    let p1 = new Promise((resolve, reject) => {
      // resolve("成功");
      reject("失败1");
    })
    let p2 = p1.then((value) => {
      console.log("成功2");
    }, (reason) => {
      console.log("失败2");
    }).then((value)=>{
      console.log("成功3");
    },(reason)=>{
      console.log("");
    })
   //失败2
   //成功3
</script>

这里打印的结果是失败2,成功3,p1的then接收的一个reject的结果,但是第二的then当没有设置状态改变的时候,默认的状态是成功的状态。
对then返回的处理

<script>
//一、这里的then直接打印出结果
new Promise((resolve,reject)=>{
      resolve("成功了");
    }).then(value=>{
      console.log(value);
    },reason=>{
      console.log(reason);
    })
//二、then默认是成功状态
    new Promise((resolve,reject)=>{
      resolve("成功了");
    }).then(value=>{
      return "我是dl"
    },reason=>{
      console.log(reason);
    }).then(value=>{
      console.log(value);
    })
//三、一个Promise对象对应一个then函数 当Promise处于pedding状态,下面的then就会进行等待
    new Promise((resolve, reject) => {
      resolve("成功了")
    }).then(value => {
      return new Promise((resolve, reject) => {
        // resolve("我是dl");
        reject("失败了不是")
      })
    }, reason => {
      console.log(reason);
    }).then(value => {
      console.log(value);
    }, reason => {
      console.log(reason);
    })
   //四、 当设置定时器的时候,后面的then必须设置到等到状态才可以执行
       new Promise((resolve, reject) => {
      resolve("成功了")
    }).then(value => {
      return new Promise((resolve, reject) => {
        // resolve("我是dl");
        setTimeout(function () {
          reject("失败了不是")
        }, 3000)
      })
    }, reason => {
      console.log(reason);
    }).then(value => {
      console.log(value);
    }, reason => {
      console.log(reason);
    })
    //五、 一个Promse对应着一个then,后面的then(),就是对Promise的处理
    new Promise((resolve, reject) => {
      resolve("成功了")
    }).then(value => {
      return new Promise((resolve, reject) => {
        reject("失败了不是")
      }).then(null, r => {
        return new Promise((resolve, reject) => {
          resolve("hhhhhh")
        })
      });
    }, reason => {
      console.log(reason);
    }).then(value => {
      console.log(value);
    }, reason => {
      console.log(reason);
    })
</script>

其他类型的Promise封装

<script>
//一、正常的使用Promise对象
    new Promise((resolve,reject)=>{
      resolve("成功了");
    }).then(value=>{
      return new Promise((resolve,reject)=>{
        resolve("成功哈哈哈")
      })
    },reason=>{
      console.log(reason);
    }).then(value=>{
      console.log(value);
    })
 //二、使用对象字面量来封装
     new Promise((resolve,reject)=>{
      resolve("成功");
    }).then(value=>{
      return { //这里使用return返回一个Promise对象
        then(resolve,reject){
          resolve("哈哈哈")
        }
      }
    },reason=>{
      console.log(reason);
    }).then(value=>{
      console.log(value);
    })
//三、使用对象字面量来封装
    new Promise((resolve,reject)=>{
      resolve("成了")
    }).then(value=>{
      class dh{
        then(resolve,reject){
          reject("拒绝")
        } 
      }
      return new dh;
    },reason=>{
      console.log(reason);
    }).then(value=>{
      console.log(value);
    },reason=>{
      console.log(reason);
    })
   //四、使用静态方法进行封装
    new Promise((resolve,reject)=>{
      resolve("成了");
    }).then(value=>{
      class hd{
        static then(resolve,reject){
          resolve("哈哈哈哈");
        }
      }
      return hd;
    },reason=>{
      console.log(reason);
    }).then(value=>{
      console.log(value);
    },reason=>{
      console.log(reason);
    })
</script>

对ajax异步操作进行处理

<script>
<!DOCTYPE html>
<html lang="cn">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    function ajax(url){
      return new Promise((resolve,reject)=>{
        let xhr = new XMLHttpRequest();
        xhr.open("GET",url);
        xhr.send();
        xhr.onload = function(){
          if(this.status == 200){
            resolve(this.response);
          }else{
            reject("加载错误")
          }
        }
        xhr.onerror = function(){
          reject(this);
        }
      })
    }
    ajax('http://127.0.0.1:5000/user/dl').then(value=>{
      // value = eval('(' + value + ')');
      return ajax("http://127.0.0.1:5000/id/201902091").then(value=>{
        console.log(value);
      },reason=>{
        console.log(reason);
      });
      console.log("http://127.0.0.1:5000/id/"+value['id']);
    },reason=>{
      console.log(reason);
    })
  </script>
</body>
</html>
</script>

这里的程序,只有等到上一级的操作完成后 ,才能进行下一次操作。
对Promise中失败的处理

<script>
//一、这里是直接通过使用reject进行错误返回
    new Promise((resolve,reject)=>{
      reject("失败")
    }).then(value=>{
      console.log(value);
    },reason=>{
      console.log(reason);
    })
  //二、当一些语法错误之类的,js会直接返回reject对象.
      new Promise((resolve, reject) => {
      hs+10;
    }).then(value => {
      console.log(value);
    }, reason => {
      console.log(reason.message);
    })
   //三、可以自己去抛出错误,这样也会返回reject
     new Promise((resolve, reject) => {
      throw new Error("shibai")
    }).then(value => {
      console.log(value);
    }, reason => {
      console.log(reason.message);
    })
   //四、
       new Promise((resolve, reject) => {
      try{
        hs+10;
      }catch{
        console.log("这里出现错误");
      }
    }).then(value => {
      console.log(value);
    }, reason => {
      console.log(reason);
    })
//五、
 new Promise((resolve,reject)=>{
      reject("失败")
    }).then(value=>{
      return new Promise((resolve,reject)=>{
        resolve("chengg")
      })
    },reason=>{
      console.log(reason);
    }).catch(error=>{
      console.log(error);
    })
//catch可以解决reject出现的错误,可以解决前面所有出现的错误,但是不能解决.其后面出现的错误,如果是前面出现错误被自身的reject()回调函数解决,则后面则不接收错误

</script>