JavaScript ES6语法学习笔记 04、Promise与Class(上)

举报
长路 发表于 2022/11/28 21:34:02 2022/11/28
【摘要】 文章目录前言一、Promise1.1、介绍Promise(认识异步)1.2、Promise的基本使用1.2.1、认识Promise的三个状态1.2.2、Promise中回调函数原理(参数为函数缘由)1.2.3、Promise的then()方法解决实际问题:回调地狱(解决过多函数回调相互嵌套问题)1.3、Promise对象的catch()方法1.3.1、替换then()中的第二个回调函数1.3.2、

@[toc]

前言

本篇博客是关于javascript的ES6中Promise以及Class,若文章中出现相关问题,请指出!

所有博客文件目录索引:博客目录索引(持续更新)

一、Promise

1.1、介绍Promise(认识异步)

Promise异步操作的解决方案。其也可以用来解决过多函数回调相互嵌套问题。

同步,即为等待结果的操作。
异步,即为不等待结果的操作。在js中的异步有:onXXX()事件,setInterval()(定时器、延时器)、ajax发送的请求、本章学习的Promise.then()方法还有一些回调函数都是异步的操作!

异步操作示例

<script>
    function fun() {
        //函数中设置一个延时器,需要传入一个回调函数,该函数就是一个异步方法
        setTimeout(() => {
            console.log("执行的异步方法!");
        }, 2000);
    }

    //测试异步回调方法与同步方法的区别!
    fun();
    console.log("执行的同步方法!");
</script>

image-20210623170543916

说明:从程序过程来看明明是先执行的fun()函数,结果却是先打印了11行的输出语句,而后延时器结束再进行输出的结果!



1.2、Promise的基本使用

1.2.1、认识Promise的三个状态

三个状态包含pending(未完成)、fulfilled(已成功)、rejected(已失败)。

三个状态的意义何在

  • 对于已成功或已失败状态肯定后面会跟着对应的执行方法来进行对应状态处理,这就与之后的then()方法有关系了!

示例:一切从Promise构造函数开始,默认状态就是pending(未完成),之后通过调用执行回调函数参数方法来进行改变状态。

<script>
    //使用构造函数,需要写一个回调函数,可获取到两个参数,其默认就是js传给你的两个方法你可以进行调用并执行
    //情况1:在回调函数中什么也不执行,默认就是未执行状态:pending
    let p = new Promise((resolve, reject) => {
    });
    console.log(p);//Promise { <state>: "pending" }

    //情况2:执行resolve(),改变状态为已完成
    p = new Promise((resolve, reject) => {
        resolve();//执行该方法改变状态为已完成
    });
    console.log(p);//Promise { <state>: "fulfilled", <value>: undefined }

    //情况3:执行reject(),改变状态为已失败
    //注意:此时若是执行已失败方法时,需要配合then()方法中的第二个回调函数或者catch()方法进行捕获操作,否则会报出异常,这里我们暂且忽略
    p = new Promise((resolve, reject) => {
        reject();//执行该方法改变状态为已失败
    });
    console.log(p);//Promise { <state>: "rejected", <reason>: undefined }
</script>

image-20210623172304064

  • fulfilled(已成功)、rejected(已失败)状态的Promise对象输出中,你可以很明显的看到有第二个参数值对于成功的是value(需要传递的值),对于失败的是reason(失败原因),这同样也与之后对应的回调函数相关。

注意点:对于resolve()reject()方法,一旦执行了其中的一个方法改变状态了,该回调函数中后面再调用改变状态的方法就无效了!



1.2.2、Promise中回调函数原理(参数为函数缘由)

在1.2.1中,我们在Promise的构造函数中添加一个回调函数并可以添加两个参数如下:

<script>
    new Promise((resolve, reject) => {
        //默认是两个函数
        console.log(resolve, reject);
    });
</script>

重点是这个回调函数中的两个参数都是函数实例,并且都是可以进行调用的!那么它究竟是怎么样定义,才能够让我们来写这个回调函数时能够接收参数并进行调用呢?

自定义一个普通的回调函数

<script>
    //自定义回调函数实现
    function myFun(fn) {
        //模拟回调函数前的操作
        console.log("回调函数前执行的代码.......");
        fn = fn || function () { };
        fn();//执行回调函数
    }

    myFun(() => {
        console.log("我是回调函数!")
    });
</script>

image-20210623203743888


模拟Promise构造函数

对上面的普通回调函数稍作修改即可!如下:

<script>
    //模仿测试代码缩写
    // new Promise((resolve, reject) => {
    //     //默认是两个函数
    //     console.log(resolve, reject);
    // });

    //模拟Promise对象的两个改变状态方法
    function resolve() { };
    function reject() { };

    //自定义回调函数实现
    function myPromise(fn) {
        //执行回调函数,并传入指定的两个函数
        fn(resolve, reject);
    }

    //模拟new Promise构造器
    new myPromise((resolve, reject) => {
        console.log(resolve, reject);
    });
</script>

image-20210623204355775



1.2.3、Promise的then()方法

then()方法初次测试

通过构造函数获得的对象调用then()方法,需要你编写两个回调函数(回调函数根据你前面的状态来进行调用),每个回调函数你可以添加参数,对应的参数实际上就是前面我提到的valuereason两个值:

<script>
    let promise = new Promise((resolve, reject) => {
        // reject("失败原因:出现异常!");//状态为rejected,表示已失败
        resolve("成功的data(数据)");//状态为fulfilled,表示已成功
    });

    //根据promise的状态来执行指定函数
    //状态为pending(未完成):then后一个也不执行
    //状态为fulfilled(已成功):执行第一个回调函数,可接收执resolve()方法传入的参数
    //状态为rejected(已失败):执行第二个回调函数,可接收执reject()方法传入的参数
    promise.then((data) => {
        console.log("success", data);
    }, (data) => {
        console.log("error", data);
    });

    console.log(promise);
</script>

我们来测试一下上面的程序(测试两次,两种情况执行):

image-20210623173622643

image-20210623173643272


then()知识点说明

1、何时执行?只有当Promise对象的状态从未执行状态改变才会执行!

2、then()执行后的返回值:执行then()后的返回值是一个新的Promise对象。

<script>
    //第一个Promise对象:手动new实例
    let p1 = new Promise((resolve, reject) => {
        resolve("成功的data(数据)");//状态为fulfilled,表示已成功
    });

    //第二个Promise对象,执行了then()方法得到的实例
    let p2 = p1.then(() => { }, () => { });
    console.log(p1, p2, p1 == p2)
</script>

image-20210623174430800

3、then()执行后得到一个新的Promise对象p,此时如何决定之后使用p调用then()方法执行的对应回调函数呢?

答案:根据return "xxx"return new Promise((xxx,xxx)=>{xxx});来进行指定状态。

情况1:无任何返回值时

该对象没有调用then()时,状态为pending。

<script>
    let p1 = new Promise((resolve, reject) => {
        resolve("成功的data(数据)");//状态为fulfilled,表示已成功
    });

    //本部分来探讨此时通过then()获取到的promise实例如何决定之后再次调用then()中的执行回调函数
    //答案:通过return来确定,若是没有return操作默认就是pending(未执行)状态,但若p2调用了then()就会默认执行成功的回调函数!
    let p2 = p1.then(() => { }, () => { });
    console.log(p2);
</script>

image-20210623175613681

若是该对象调用了then(),状态也会自动改变为pending(已完成),执行第一个回调函数

<script>
    let p1 = new Promise((resolve, reject) => {
        resolve("成功的data(数据)");//状态为fulfilled,表示已成功
    });

    //本部分来探讨此时通过then()获取到的promise实例如何决定之后再次调用then()中的执行回调函数
    //答案:通过return来确定,若是没有return操作默认就是pending(未执行)状态,但若p2调用了then()就会默认执行成功的回调函数!
    let p2 = p1.then(() => { }, () => { });
    console.log(p2);
    p2.then(() => console.log("p2-success"), () => console.log("p2-reason"));
</script>

image-20210623175831110

情况2:若是有返回值,直接return ""字符串形式就是表示改变状态为成功;若想指定为已失败,需要手动返回一个新的Promise对象如new Promise((resolve,reject)=>{reject(xxx);})

  • 本质:return ""实际上就本质就是return new Promise((resolve)=>{resolve();})
    说明:若是我们想直接执行then()后的已完成的回调函数,直接返回字符串就好(比较方便),对了这个字符串就是我们想要传的值。
    

测试then()后执行的是已完成的函数:使用的是简写形式

<script>
    let p1 = new Promise((resolve, reject) => {
        resolve("成功的data(数据)");//状态为fulfilled,表示已成功
    });

    //本部分来探讨此时通过then()获取到的promise实例如何决定之后再次调用then()中的执行回调函数
    let p2 = p1.then(() => {
        return "成功啦!";//实际上就等同于return new Promise((resolve)=>{resolve("成功啦!");})
    }, () => { });
    console.log(p2);
    p2.then((data) => console.log(data), (reason) => console.log(reason));
</script>

image-20210623180456071

测试then()后执行的是未完成的函数:使用的是完整形式

image-20210623184256384

image-20210623184305516

简而言之:若是你在then()方法中返回了一个值,可以再次编写调用then()方法来接收该返回值。使用该种方法可以进行解构,模块化处理指定的事情。

const p = new Promise(resolve=>{
    resolve("hello");
});
p.then(res=>{
    return res;
}).then(res=>{
    console.log(res);
});

image-20210803112723090



解决实际问题:回调地狱(解决过多函数回调相互嵌套问题)

需求:让一个盒子进行正方形移动,需要我们编写一个函数来进行移动。

GIF

解决方案1:通过多次回调执行,构成回调地狱(不利于代码删减)

<style>
    * {
        margin: 0;
        padding: 0;
    }

    div {
        height: 100px;
        width: 100px;
        border: 1px solid #000;
        background-color: red;
        /* 设置过渡 */
        transition: all linear .5s;
    }
</style>

<body>

    <!-- promise实际应用 -->
    <div id="box"></div>

    <script>
        let num = 1;
        //创建一个运动函数.参数1:指定的dom元素;参数2:x,y坐标存储在对象中;参数3:下一步要做的事情
        const move = (el, { x = 0, y = 0 } = {}, next = () => { }) => {
            el.style.transform = `translate3d(${x}px,${y}px,0)`;
            el.remove
            //添加一个监听器,监听过渡结束之后事件
            el.addEventListener('transitionend', () => {
                // console.log(num++);
                next();//执行下一个操作
            }, false);
        }

        //方式一:层层嵌套,形成回调地狱(不推荐)
        movBox.addEventListener('click', () => {
            move(movBox, { x: 150 }, () => {
                move(movBox, { x: 150, y: 150 }, () => {
                    move(movBox, { y: 150 }, () => {
                        move(movBox, {}, () => {

                        })
                    })
                })
            });
        }, false);

    </script>

</body>

问题描述:若是有大量的移动过程呢,就会产生大量的嵌套,若是有一些需求修改情况就会很麻烦,一旦出现下面层层嵌套情况:

image-20210623185940068

我们应当使用promise来进行解决!!!

方案2:通过使用promise对象来解决回调地狱

下面的代码替换掉之前的的方式一即可:此时我们看到不再是嵌套的情况,而是多个方法纵向执行

//方式二:借助promise来进行解决过多函数回调
//第一步:封装promise,需要传入一个el(dom对象)以及对象包含x,y的数字
const movePromise = (el, point) => {
    //返回一个封装好的promise对象
    return new Promise(reslove => {
        //其中move()方法的下一步操作(这里设置reslove())就是promise对象的then的第一个回调函数
        move(el, point, () => {
            reslove();
        })
    });
};

//第二步:开始写执行操作(通过then形成一个执行链条进行纵向执行,而不是进行嵌套回调)
movBox.addEventListener('click', () => {
    movePromise(movBox, { x: 150 })
    .then(() => {
        return movePromise(movBox, { x: 150, y: 150 });
    })
    .then(() => {
        return movePromise(movBox, { y: 150 });
    })
    .then(() => {
        return movePromise(movBox, {});
    });
}, false);

使用之后的效果与之前的一致,并且若是想要修改位置或者说是添加业务代码等都更加的方便了!



1.3、Promise对象的catch()方法

1.3.1、替换then()中的第二个回调函数

catch():是专门用来处理rejected(未完成)状态的!用来捕获失败的事件。

我们原本对于rejected状态通过是通过设置then()方法中的第二个回调函数来进行对应的,实际开发中对于未完成的我们都是通过使用catch()方法来进行处理的,而不是写在第二个参数的!

原始写法

说明:为了更方便分清成功与失败的回调函数,我们通常不写在then()的第二个参数上!下面是原始的写法:

<script>
    let p1 = new Promise((resolve, reject) => {
        reject("未加载到图片!");//表示状态为已失败!
    });

    //原始写法:对应已失败的情况,我们设置一个回调函数到then()的第二个参数中来进行处理!
    p1.then(() => { }, (reason) => {
        console.log(`失败的原因:${reason}`);
    });
</script>

image-20210623191035730

推荐写法:后面跟上catch(),添加一个回调函数

<script>
    let p1 = new Promise((resolve, reject) => {
        reject("未加载到图片!");//表示状态为已失败!
    });

    //已失败状态传来到then()中首先会看其中有没有对应的处理失败回调函数,没有的话继续向下抛出
    //合理写法:使用catch()来进行捕获失败状态,并且执行一些对应的操作
    p1.then().catch((reason) => {  //可设置参数来获取到传来的原因
        console.log(`失败的原因:${reason}`);
    });
</script>

image-20210623191348527



1.3.2、catch()捕捉到之后的then()状态

catch()捕捉好之后,若是下面依旧有then()会若无return或**直接return ‘字符串’**继续向下传递到success的回调函数中。若是想要从catch()那传到下面的错误回调函数中,就需要手动进行返回Promise()对象:new Promise((resolve,reject)=>{ reject();})

无返回值或返回值为字符串情况:传递到success回调函数

<script>
    let p1 = new Promise((resolve, reject) => {
        reject("未加载到图片!");//表示状态为已失败!
    });

    p1.catch((reason) => {
        console.log(`失败的原因:${reason}`);
        //若是无返回值的话,默认将undefined作为参数传递,相当于执行了return undefined;   
        //若是有返回字符串的,则将该字符串作为参数传递到下面then()的success回调函数中
    }).then((data) => {
        console.log(`catch之后的success函数,传递参数为:${data}`);
    });
</script>

image-20210623192400095


catch()想要传递到之后then()的对应错误回调函数(相当于出错情况)

<script>
    let p1 = new Promise((resolve, reject) => {
        reject("未加载到图片!");//表示状态为已失败!
    });

    p1.catch((reason) => {
        console.log(`失败的原因:${reason}`);
        //传递已失败状态对应的函数
        return new Promise((resolve, reject) => { reject(); })
    }).then(() => { }, (reason) => {
        console.log(`catch之后的错误函数,传递参数为:${reason}`);
    });
</script>

image-20210623193906221



1.3.3、捕捉异常另一种方式(推荐):throw+catch()

建议catch()可以捕获它前面的错误,一般总是建议在Promise对象后跟着catch()方法,这样可以处理Promise内部发生的错误!

  • catch()不仅仅能够捕捉自己抛出的异常,还能够捕捉到其他异常情况!

其实对于捕捉异常,最好的方式就是使用throw来抛出异常,接着使用catch()来进行捕捉异常最合适!

<script>
    let p1 = new Promise((resolve, reject) => {
        resolve("数据");//表示状态为已失败!
    });

    p1.then((data) => {
        console.log(data);
        //抛出异常,让下面的catch()进行处理
        throw new Error('失败原因xxxxx');
    }).catch((error) => {
        console.log(error);
    });
</script>

image-20210623194620348



1.4、Promise对象的finally()使用

执行时间:当Promise状态发生改变时,不论如何变化都会执行,不变化不执行!

应用场景:一般放置在最后,前端很少使用,在后端中经常用来处理一些资源流的关闭!

<script>
    let p1 = new Promise((resolve, reject) => {
        //状态发生改变才会执行finally(),否则不执行
        resolve(12);
    });

    //参数为undefined,几乎不怎么使用
    p1.finally((data) => {
        console.log(data);
    });
</script>

image-20210623195326480

本质

finally()的本质实际上就是由then()方法构成,如下:无论是成功还是失败都会执行

<script>
    let p1 = new Promise((resolve, reject) => {
        //状态发生改变才会执行finally(),否则不执行
        resolve(12);
    });

    //参数为undefined,几乎不怎么使用
    // p1.finally((data) => {
    //     console.log(data);
    // });

    //模拟finally()操作
    p1.then(() => {
        console.log("模拟finally()操作....");
    }, () => {
        console.log("模拟finally()操作....");
    });
</script>

image-20210623195730068



1.5、Promise.resolve()与Promise.reject()

1.5.1、介绍两种方法以及Promise实例作为参数的情况(两种)

介绍两种方法

Promise.resolve()Promise.reject():是成功与失败状态的获取Promise()对象的一种简写方式。

示例

<script>
    //两个构造函数方法的本质都是返回一个Promise对象,简化了原本使用new Promise((res,rej)=>{res();})的方式
    //Promise.resolve():改变为成功状态
    console.log(Promise.resolve("成功传输数据"));;
    //Promise.reject():改变为失败状态
    console.log(Promise.reject("失败原因xxx").catch((data) => console.log(data)));;
</script>

image-20210623200806444


注意点说明:Promise对象作为参数时不同情况

Promise对象作为resolve()以及reject()参数时是否会将Promise对象作为参数传递呢?

结论

  • 作为resolve()的参数:间接直接执行该promise对象后传递指定的参数,不是传递该实例!
  • 作为reject()的参数:并不会执行该promise对象,而是直接将该实例进行传递!

结论一测试:

let p = Promise.resolve("成功传输数据");
new Promise((resolve, reject) => {
    resolve(p);//作为resolve()方法的参数,会直接间接执行该promise对象之后
}).then((data) => {
    console.log(data);
})

image-20210623202134342

结论二测试:

let p = Promise.resolve("成功传输数据");
new Promise((resolve, reject) => {
    reject(p);//作为reject()方法的参数,会直接间接执行该promise对象之后
}).then((data) => {
    console.log(data);
}, (reason) => {
    console.log(reason);
})

image-20210623202049163



1.5.2、在两个方法中传入具有then()方法的对象

说明:定义一个对象并添加一个then()函数,接着将该对象传入到resolve()方法中,即可与new Promise()构造函数中写回调函数方式一致,如下示例:

<script>
    var hasThenObj = {
        //添加一个then方法,其中执行指定改变状态方法(与new Promise()中的回调函数使用方法一致)
        then(resolve, reject) {
            // resolve("成功执行的传递数据!");
            reject("失败的原因xxx");
        }
    };

    //将具有then()方法的对象传入依旧可进行使用!
    Promise.resolve(hasThenObj).then((data) => {
        console.log(data);
    }, (data) => {
        console.log(data);
    })
</script>

image-20210623220546095

image-20210623220607580



1.6、Promise.all():与传入的对象状态相关

Promise.all()的状态变化与所有传入的Promise实例对象状态有关!

  1. 都不改变状态情况(无任何返回值),默认将undefined作为传递值改变状态为成功。
  2. 所有的状态都变成resolved,最终的状态才会变成resolved,才会去调用生成的Promise实例的成功回调函数!
  3. 只要有一个Promise实例变成rejected,最终的状态就会变成rejected!(另一个Promise实例会继续执行,而并不是说最终状态得到了就不执行了)

实际用途:应用与前端向后端发送ajax,如同时获取多个数据,只有同时都获取到了才将数据显示出来,如果没有获取到呢就再进行处理。

示例

<script>
    //自定义封装Promise
    const delay = ms => {
        return new Promise(resolve => {
            setTimeout(() => {
                resolve();
            }, ms);
        });
    };

    //设置两个p2
    const p1 = delay(1000).then(() => {
        console.log("p1-success!");
        // return "p11";
        // return Promise.reject("p11");
    });

    const p2 = delay(2000).then(() => {
        console.log("p2-success!");
        // return "p22";
    });

    //执行Promise.all()
    //情况1:两个Promise实例都已成功后,将两个传递参数封装到数组中作为p实例调用then()第一个回调函数的参数
    //情况2:只要一个Promise实例为rejected,就会立刻执行p中的then()方法,即第二个回调函数
    //情况3:若是两个实例都没有返回值或改变状态方法,默认会调用p实例中的第一个回调函数,传值为两个undefined
    const p = Promise.all([p1, p2]);
    p.then((data) => {
        console.log(data);
    }, (error) => {
        console.log(error);
    })
</script>

image-20210623235702904



1.7、Promise.race()和Promise.allSettled()

Promise.race()

Promise.race():其状态取决于第一个完成的Promise实例对象,如果第一个完成的成功了,那最终就是成功(得到第一个成功返回的参数);如果第一个完成的失败了,那么最终就是失败!(得到的参数也是取决于第一个完成的)

示例

<script>
    //自定义封装Promise
    const delay = ms => {
        return new Promise(resolve => {
            setTimeout(() => {
                resolve();
            }, ms);
        });
    };

    //设置两个p2
    const p1 = delay(1000).then(() => {
        // return "p11-success";
        return Promise.reject("p11-error");
    });

    const p2 = delay(2000).then(() => {
        console.log("p2-success!");
        // return "p22";
    });

    //执行Promise.race():
    const p = Promise.race([p1, p2]);
    p.then((data) => {
        console.log(data);
    }, (error) => {
        console.log(error);
    })
</script>

image-20210624000507041


Promise.allSettled()

Promise.allSetted():该方法的状态与传入的Promise状态无关,它们永远都是成功的,并且会记录下各个Promise的表现,以对象键值对形式存放在一个数组中。也就是说它不可能会有失败情况!

示例

<script>
    //自定义封装Promise
    const delay = ms => {
        return new Promise(resolve => {
            setTimeout(() => {
                resolve();
            }, ms);
        });
    };

    //设置两个p2
    const p1 = delay(1000).then(() => {
        return Promise.reject("p11-error");
    });

    const p2 = delay(2000).then(() => {
        return "p22-succes";
    });

    //执行Promise.allSettled():获取所有传入的promise实例的最终状态(存储的是Promise实例到数组中)
    const p = Promise.allSettled([p1, p2]);
    p.then((data) => {
        console.log(data);
    }, (error) => {
        console.log(error);
    })
</script>

image-20210624000838723



1.8、Promise的注意事项

1、resolve()与reject()后的代码也会执行。

<script>
    new Promise((resolve, reject) => {
        resolve("传递数据xxx");
        //改变状态的方法下面代码依旧会执行
        console.log(111111);
    }).then((data) => console.log(data));
</script>

image-20210624001322085

2、Promise.all()race()allSettled()的参数如果不是Promise数组,会将不是Promise的数组转为成Promise对象!

  • 不只是数组,任何可遍历的都可以作为参数如数组、字符串、Set、Map、NodeList、arguments…

下面第2行就是传入非Promise数组,实质你可以看下下面就是自动帮你封装为Promise.resolve()

<script>
    Promise.all([1, 2, 3]).then((data) => console.log(data));
    //上面传入的是非Promise实例,实质可以转为如下:内部自动会帮你进行封装执行改变为已成功!
    Promise.all([
        Promise.resolve(1),
        Promise.resolve(2),
        Promise.resolve(3)
    ]).then((data) => console.log(data))
</script>

image-20210624001925612

3、Promise.all()race()allSettled()的错误处理:既可以单独处理也可以统一处理!

针对于all如何进行批量处理错误?

  1. 直接在对应的某个promise上添加catch处理。自己将错误进行处理。
  2. 直接在all返回的promise上进行处理,达到统一处理的效果。

单独处理形式:直接让对应的Promise实例自己处理,处理好之后不会再向下传

<script>
    //自定义封装Promise
    const delay = ms => {
        return new Promise(resolve => {
            setTimeout(() => {
                resolve();
            }, ms);
        });
    };

    //情况1:两个Promise实例自定义异常处理!!!
    const p1 = delay(1000).then(() => {
        // return "p11";
        return Promise.reject("p11的错误原因!");
    }).catch((error) => {
        console.log(`p1自己处理:${error}`);
    });

    const p2 = delay(2000).then(() => {
        return Promise.reject("p22的错误原因!");
    }).catch((error) => {
        console.log(`p2自己处理:${error}`);
    });;

    const p = Promise.all([p1, p2]);
    p.then((data) => {
        console.log(data);
    }, (error) => {
        console.log(error);
    }).catch(error => {
        console.log("统一处理错误....")
    });
</script>

image-20210624002545688

统一处理:统一交由all()或其他返回的Promise对象来处理

<script>
    //自定义封装Promise
    const delay = ms => {
        return new Promise(resolve => {
            setTimeout(() => {
                resolve();
            }, ms);
        });
    };

    //情况1:两个Promise实例自定义异常处理!!!
    const p1 = delay(1000).then(() => {
        // return "p11";
        return Promise.reject("p11的错误原因!");
    });

    const p2 = delay(2000).then(() => {
        return Promise.reject("p22的错误原因!");
    });

    const p = Promise.all([p1, p2]);
    p.then((data) => {
        console.log(data);
    }).catch(error => {
        console.log("统一处理错误....")
    });
</script>

image-20210624002745658



实际应用:异步加载图片

Promise应用:进行异步加载,当停留在当前页面时,利用这个空隙即浏览的时间,将其他的资源提前加载!之后访问指定的资源就减少时间,体验更好!

知识说明

当我们new Imgae时就相当于创建了一个图片Dom元素,在构造函数中你可以设置widthheight,重要的来的就是当你对该实例的src添加请求路径时,浏览器就会发送一个请求得到资源!

<script>
    const img = new Image(300, 100);
    img.src = 'https://img0.baidu.com/it/u=2151136234,3513236673&fm=26&fmt=auto&gp=0.jpg';
    console.log(img);
</script>

image-20210624162116871

image-20210624162126343


实现异步加载图片

想要实现异步加载图片,那么我们就需要使用到Promise了,其就是异步方法,我们将Image实例化以及设置src属性的操作放置在构造函数的回调函数里进行!

在加载页面的过程中,实际上就已经将对应的图片资源请求到了,当我们点击页面中的图片时,就能够实现快速响应的效果!!!

GIF

<style>
    * {
        margin: 0;
        padding: 0;
    }

    img {
        width: 300px;
        height: auto;
        margin: 10px;
    }
</style>

<body>

    <img id="myimg" src="./css/images/01_1.jpg" alt="">
    <script>

        //异步加载图片
        const loadImgAsync = url => {
            return new Promise((resolve, reject) => {
                //实例化一个图片
                const img = new Image();

                //绑定加载完毕事件(在设置src路径得到响应码之后来决定是否加载成功或失败)
                img.onload = () => {
                    resolve(img);
                };

                //出现错误
                img.onerror = () => {
                    reject(new Error(`Could not load image at ${url}`));
                }

                //设置url,资源路径(设置的同时发出请求进行响应)
                img.src = url;

            })
        };

        //修改页面中图片的标签
        const modifyPic = (img_dom, targetUrl) => {
            img_dom.src = targetUrl;
        }

        //获取到原本图片的Dom元素
        var m_img = document.getElementById("myimg");
        //加载好图片之后(自动做的异步操作),点击原本图片进行切换
        loadImgAsync('https://img0.baidu.com/it/u=2151136234,3513236673&fm=26&fmt=auto&gp=0.jpg')
            .then((img) => {
            console.log(img);
            //绑定点击事件,点击进行修改操作
            m_img.onclick = () => modifyPic(m_img, img.src);
        }).catch((error) => {
            console.log("处理失败原因!", error);
        });
    </script>
</body>

对于若是加载失败情况:若是没有加载到的可能会再加载一遍或者说是从别的地址重新进行加载,根据项目组规定来进行实施!

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。