第八周第二天笔记

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>
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容

  • "use strict";function _classCallCheck(e,t){if(!(e instanc...
    久些阅读 2,027评论 0 2
  • Promise 对象 Promise 的含义 Promise 是异步编程的一种解决方案,比传统的解决方案——回调函...
    neromous阅读 8,698评论 1 56
  • 1.何小桃南行所悟 终于回到了北京。 近一个月以来,何小桃一直在南方的大小城市来回穿梭,似乎想从南方炙热的空气中找...
    叫我正小健阅读 380评论 1 3
  • 我们在雨中别离 说不定又风中相遇 白云说邂逅是一种伤心的美丽 就像那躲进河流的雨滴 …… 岁月说签名和留影都会都遗...
    存孝羽阅读 173评论 0 0
  • 先人常言、少时好读书,壮时好行路,若伪少时苦,壮时知苦味。
    亚里虫子阅读 369评论 0 0