美文网首页web基础学习之路
第八周第二天笔记

第八周第二天笔记

作者: 果木山 | 来源:发表于2018-09-08 23:52 被阅读0次

    ES6之Promise类

    1 Promise类基础知识解读

    • promise类的静态属性方法
      • 分类:resolve(),reject(),all(),race()
        • resolve():作为形参传入到实例对象中,在条件满足时,作为回调函数执行,可以传入实参;then中的第一个参数回调函数接收;
        • reject():作为形参传入到实例对象中,在条件不满足时,即失败时,作为回调函数执行,可以传入实参,then中第二个参数回调函数接收,或是catch中的回调函数接收;
        • all():提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调,即当最慢的一个没有执行完时,会执行完的异步操作传入的数据,以数组的形式储存,待最慢的一个执行完,以一个数组的形式,将数据传入到then;
        • race():多个异步操作同样是并行执行的,谁最快,数据进入then;其他的异步操作会继续执行,但是then不会再接受其他异步操作的数据;
      • 使用:Promise类名调用,即Promise.all;实例对象不能使用;
    • promise类原型上的属性方法
      • 分类:then(),catch()
        • then():接收第一个参数,是回调函数,并且会拿到异步操作成功后resolve传入的参数,第二个参数可有可无,如果添加,也是一个回调函数,里面拿到的是,异步操作失败后reject传入的参数;
        • catch():接受一个参数,是回调函数,第一个功能,是当异步操作失败后,接收reject传入的参数;第二个功能,是异步操作成功后,会进入then,但是在then中执行代码,报错了,然后,catch就接收到了报错的文本,然后不会终止JS,可以保证JS继续执行;
      • 使用:实例对象才能使用原型的属性方法;
    • 总结:实例创建中,当满足条件后,会执行resolve(),相当于then里面匿名函数调用;相当于回调函数,而resolve可以看做then里面匿名函数的函数名;异步操作其实就是实例对象自执行;
    • Promise详细解读文件

    2 Promise类实例

    • 实例1:图片请求超时
      • 知识点:将两个异步操作放入到race方法中,如果5秒之内图片请求成功了,那么便进入then方法,执行正常的流程。如果5秒钟图片还未成功返回,那么imgTimeout最快执行,则进入catch,报出“图片请求超时”的信息。当requestImg函数中图片地址出错,图片无法正常加载,onload事件不会执行,resolve不会执行,所以不会进入then;
         <script>
          function requestImg() {
              return new Promise(function (resolve) {
                  var oImg=new Image();
                  oImg.onload=function(){
                     resolve(this);
                  };
                  oImg.src="image1/01.png";
              })
          }
          function imgTimeout() {
              return new Promise(function (resolve, reject) {
                  setTimeout(function () {
                      reject("图片加载超时");
                  },5000)
              })
          }
          Promise.race([requestImg(),imgTimeout()])
              .then(function (data) {
                  document.body.appendChild(data);
              })
              .catch(function (reason) {
                  console.log(reason);
              });
         </script>
      
    • 实例2:小球运动实例
      • 知识点:多次执行异步操作,执行异步操作1后,当条件满足时,会执行异步操作1中resolve(),而在异步操作1点then的匿名函数中返回另一个异步操作2;然后执行异步操作2,实质为实例对象的自执行,然后满足条件时,执行异步操作2中的resolve(),然后再在异步操作2点then的匿名函数中返回异步操作3,反复异步操作,直到最后一个异步操作中条件满足后,执行resolve(),在其后面的then匿名函数中,添加运动结束代码;
       <!DOCTYPE html>
       <html lang="en">
       <head>
           <meta charset="UTF-8">
           <title>小球运动实例</title>
           <style>
               div{
                   width: 60px;
                   height: 60px;
                   border-radius: 50%;
                   margin-bottom: 10px;
               }
               .div1{
                   background-color: red;
               }
               .div2{
                   background-color: green;
               }
               .div3{
                   background-color: yellow;
               }
           </style>
       </head>
       <body>
       <div class="div1" style="margin-left:0"></div>
       <div class="div2" style="margin-left:0"></div>
       <div class="div3" style="margin-left:0"></div>
       <script>
           var oDiv1=document.getElementsByTagName("div")[0];
           var oDiv2=document.getElementsByTagName("div")[1];
           var oDiv3=document.getElementsByTagName("div")[2];
           //ele:操作的元素;target:元素运动到的目的地
           function promiseAnimate(ele,target) {//函数返回值为实例对象
               //resolve:成功之后想做什么,reject:失败之后想做什么
               return new Promise(function(resolve,reject){
                   function animate() {//去掉参数
                       setTimeout(function () {
                           var n=parseFloat(ele.style.marginLeft);
                           if(n===target){
                               resolve();//做回调函数要做的事情
                           }else{
                               if(n<target){
                                   n++;
                                   ele.style.marginLeft=n+"px";
                               }else{
                                   n--;
                                   ele.style.marginLeft=n+"px";
                               }
                               animate();
                           }
                       },10);
                   }
                   animate();//调用一次;
               })
           }
           promiseAnimate(oDiv1,100)
               .then(function () {
                   return promiseAnimate(oDiv2,200)
               })
               .then(function () {
                   return promiseAnimate(oDiv3,300)
               })
               .then(function () {
                   return promiseAnimate(oDiv3,150)
               })
               .then(function () {
                   return promiseAnimate(oDiv2,150)
               })
               .then(function () {
                   return promiseAnimate(oDiv1,150)
               })
               .then(function () {
                   alert("运动结束")
               })
       </script>
       </body>
       </html>
      

    运动库

    • 实例1:左右按钮点击运动
      • 知识点:
        • 边界值的判断:1)在cur累加累减之前,必须加减步长进行判断;2)在cur累加累减之后,不用加减步长进行判断,直接判断cur是否满足条件;
        • 边界值判断条件成立,执行的语句中,设置边界值,然后添加return,阻断程序执行;
        • 需注意:设置样式值,必须在边界值判断之后;;
         <script>
          //1 边界值判断,在cur累加累减之前,必须加减步长进行判断;
          if(cur>target){
              if(cur-5<=target){//提前加减步长进行比较,如果满足条件就设置目标值;
                  oDiv.style.left=target+"px";
                  return;
              }
              cur-=5;
          }else{
              if(cur+5>=target){
                  oDiv.style.left=target+"px";
                  return;
              }
              cur+=5;
          }
          oDiv.style.left=cur+"px";
         //2 边界值判断,在cur累加累减之后,不用加减步长进行判断,直接判断cur是否满足条件,但是需注意的一点是,设置必须在判断条件之后;
         if(cur>target){
             cur-=5;
             if(cur<=target){//在累加之后判断无需加减步长,如果满足条件就设置目标值;
               oDiv.style.left=target+"px";
               return;
              }
         }else{
             cur+=5;
             if(cur>=target){
               oDiv.style.left=target+"px";
               return;
              }
         }
         oDiv.style.left=cur+"px";
         </script>
        
        • 定时器的timer,设置在元素的自定义属性上,避免全局变量
        • 两个点击事件执行一个定时器时会出问题,所以需要在执行定时器之前,关闭定时器;
        • 优化思想:
          • 出现的问题:定时器中要添加函数的定义阶段,不加括号,但是针对带参数的函数,就无法只写函数名,可以新建一个匿名函数将函数调用放入匿名函数中;如:oDiv.timer=setTimeout(function(){ moveBat(target);},30),但是这样设置会出现问题,当定时器中的moveBat(target)执行值,会查找参数target,向匿名函数查找,查找不到再向上级作用域查找,而此时定时器中的匿名函数形成的私有作用域不会被释放,每执行一次定时器,都会新建一个私有作用域,所以内存会很大,不利于优化;
          • 解决措施:在moveBat(target)函数定义中,添加一个新的函数_move(),将所有代码放入其中,在定时器中添加_move,这样当定时器执行时,就会重复调用_move函数;不会再形成匿名函数;但是需注意的是,在添加_move定义阶段后,必须执行一次;
      • 代码:
       <!DOCTYPE html>
       <html lang="en">
       <head>
           <meta charset="UTF-8">
           <title>左右按钮点击运动</title>
           <style>
               *{
                   margin: 0;
                   padding: 0;
               }
               button{
                   margin: 5px;
                   width: 100px;
                   height: 30px;
                   line-height: 30px;
                   cursor: pointer;
               }
               #but{
                   width:230px;
                   height: 50px;
                   margin: 0 auto;
               }
               #div1{
                   width: 100px;
                   height: 100px;
                   line-height: 100px;
                   text-align: center;
                   font-size: 30px;
                   color: blue;
                   border-radius: 50%;
                   background-color: red;
                   position: absolute;
                   left: 500px;
                   top: 100px;
               }
               .div2{
                   width: 10px;
                   height: 500px;
                   position: absolute;
                   top: 50px;
                   background-color: blue;
               }
               #div2{
                   left: 240px;
               }
               #div3{
                   left: 1250px;
               }
           </style>
       </head>
       <body>
       <div id="but"><button>向左</button><button>向右</button></div>
       <div id="div1">太阳</div>
       <div class="div2" id="div2"></div>
       <div class="div2" id="div3"></div>
       <script>
           var oDiv=document.getElementById("div1");
           var aBtn=document.getElementsByTagName("button");
           aBtn[0].onclick=function () {
               moveBat(250);
           };
           aBtn[1].onclick=function () {
               moveBat(1150);
           };
           function moveBat(target) {
               _moveBat();//执行一次;
               function _moveBat(){//添加函数,利于优化
                   var cur=oDiv.offsetLeft;
                   if(cur>target){
                       if(cur-5<=target){//提前加减步长进行比较,如果满足条件就设置目标值;
                           oDiv.style.left=target+"px";
                           return;
                       }
                       cur-=5;
                   }else{
                       if(cur+5>=target){
                           oDiv.style.left=target+"px";
                           return;
                       }
                       cur+=5;
                   }
                   oDiv.style.left=cur+"px";
                   clearTimeout(oDiv.timer);//执行前先关闭定时器;
                   oDiv.timer=setTimeout(_moveBat,30);//将timer设置在元素的自定义属性上,避免全局变量;
               }
              /* oDiv.timer=setTimeout(function () {//设置匿名函数后,会重复新建私有作用域,不能释放,不利于优化
                   moveBat(target);
               },30);*/
           }
           //1 边界值的判断,预判是否到达边界值;
           //2 定时器的timer,设置在元素的自定义属性上,避免全局变量
           //3 两个点击事件执行一个定时器时会出问题,所以需要在执行定时器之前,关闭定时器;
           //4 定时器中新建匿名函数的优化问题;
       </script>
       </body>
       </html>
      
    • 运动库linear函数封装
      • 目的:获取运动元素的实时位置
      • 参数:
        • b:begin 运动起始位置
        • c:change 还要走多远
        • d:duration 走完剩下的路程需要的总时间
        • t:time 代表走了多少时间
      • 变量:time值为可变值,不断地累加,然后计算出实时位置;配合定时器使用;
      • 返回值:返回实时位置值;
       <script>
         function linear(c,d,t,b) {
             return c/d*t+b;
         }
       </script>
      
      • 实例
       <script>
           function linear(c,d,t,b) {
               return c/d*t+b;
           }
           var oDiv1=document.getElementById("div1");//运动元素
           var oDiv2=document.getElementById("div2");//目标位置元素
           //目标值target需要确定
           var target=oDiv2.offsetLeft-oDiv1.offsetWidth-oDiv2.offsetWidth;//减去运动元素的宽度和自身的宽度;
           var b=oDiv1.offsetLeft;
           var c=target-b;
           var d=1000;
           var t=0;
           oDiv1.timer=setInterval(function () {
               t+=10;//time为变量,不断累加;
               //边界点判断
               if(t>d){
                   oDiv1.style.left=target+"px";
                   clearInterval(oDiv1.timer);
               }
               var curLeft=linear(c,d,t,b);
               oDiv1.style.left=curLeft+"px";
           },10)
       </script>
      
    • 实例:一个物体的多运动
      • 目的:实现一个物体在x,y两个方向上的同时匀速运动;
      • 思路:
        • 分别求出物体运动在x,y方向上的起始位置,目标位置,算出各自方向上的总路程;
        • 设定总时间duration;
        • 起始时间为0,即time初始赋值为0;
        • 设置定时器:1)进行time变量的累加,最好跟定时器的执行时间相同;2)边界点判断(设置目标位置、停止定时器、阻断程序执行);3)利用linear方法获取x,y方向上的实时位置;4)设置实时位置;
       <!DOCTYPE html>
       <html lang="en">
       <head>
           <meta charset="UTF-8">
           <title>一个物体的多运动</title>
           <style>
               *{
                   margin: 0;
                   padding: 0;
               }
               #div1{
                   width: 100px;
                   height: 100px;
                   line-height: 100px;
                   text-align: center;
                   font-size: 30px;
                   color: blue;
                   border-radius: 50%;
                   background-color: red;
                   position: absolute;
                   left: 300px;
                   top: 30px;
               }
               .div2{
                   width: 10px;
                   height: 500px;
                   position: absolute;
                   top: 30px;
                   left: 1050px;
                   background-color: blue;
               }
           </style>
       </head>
       <body>
       <div id="div1">物体</div>
       <div class="div2" id="div2"></div>
       <script src="utils.js"></script>
       <script>
           function linear(c,d,t,b) {
               return c/d*t+b;
           }
           var oDiv1=document.getElementById("div1");
           var oDiv2=document.getElementById("div2");
           var targetLeft=oDiv2.offsetLeft-oDiv1.offsetWidth,targetTop=oDiv2.offsetHeight+oDiv2.offsetTop-oDiv1.offsetHeight;
           var beginLeft=oDiv1.offsetLeft,beginTop=oDiv1.offsetTop;
           var changLeft=targetLeft-beginLeft,changTop=targetTop-beginTop;
           var duration=1000;
           var time=0;
           var timer=setInterval(function () {
               //1 变量累加
               time+=10;
               //2 边界点判断
               if(time>=duration){
                   //设置目标值
                   utils.css(oDiv1,{
                       left:targetLeft,
                       top:targetTop
                   });
                   //停止定时器
                   clearInterval(timer);
                   //阻断程序执行
                   return ;
               }
               //3 获取当前位置
               var curLeft=linear(changLeft,duration,time,beginLeft);
               var curTop=linear(changTop,duration,time,beginTop);
               //4 设置当前位置
               utils.css(oDiv1,{
                   left:curLeft,
                   top:curTop
               });
           },10);
       </script>
       </body>
       </html>
      
    • 实例:封装方法,实现物体的多运动库
      • 参数: ele:元素,target:目标值,对象,duration:运动总时间
      • 注意点:
        • 工具库的引用,需要按照引用顺序调用;
        • 在工具库中利用自执行函数封装的方法,需要设置window,将其设置成全局变量,这样才能在全局引用;
      • 工具库代码:
       (function () {
           var gbEffect={
               Linear:function(c,d,t,b){
                   return c/d*t+b;
               }
           };
           function move(ele,target,duration){
               //ele:元素,target:目标值,对象,duration:时间
               duration=duration || 2000;
               var begin={},change={};
               for(var attr in target){
                   begin[attr]=utils.css(ele,attr);
                   change[attr]=target[attr]-begin[attr];
               }
               var time=0;
               //定时器
               var timer=setInterval(function () {
                   //变量累加
                   time+=10;
                   //边界点判断
                   if(time>=duration){
                       //设置边界值
                       console.log(1)
                       utils.css(ele,target);
                       //停止定时器
                       clearInterval(timer);
                       //阻断程序执行
                       return ;
                   }
                   //获取实时位置
                   for(var attr in change){
                       var linear=gbEffect.Linear(change[attr],duration,time,begin[attr]);
                       //设置实时位置
                       utils.css(ele,attr,linear);
                   }
               },10)
           }
           //自执行函数中与外界无联系,利用window设置为全局
           window.animate=move;
       })();
      
      • 执行代码:
       <body>
       <div id="div1">物体</div>
       <div id="div2"></div>
       <script src="utils.js"></script>
       <script src="move.js"></script>
       <script>
           var oDiv1=document.getElementById("div1");
           var oDiv2=document.getElementById("div2");
           animate(oDiv1,{
               left:oDiv2.offsetLeft-oDiv1.offsetWidth,
               top:oDiv2.offsetTop+oDiv2.offsetHeight-oDiv1.offsetHeight,
               opacity:0.8
           },2000)
       </script>
       </body>
      

    相关文章

      网友评论

        本文标题:第八周第二天笔记

        本文链接:https://www.haomeiwen.com/subject/guqrgftx.html