• `Promise`全面解析


    Promise入门

    1.Promise介绍

    1.1 理解

    1.抽象表达

    1. Promise是一门新的技术(ES6规范)

    2. PromiseJS中进行异常编程的新解决方案

      备注:旧方案是单纯使用回调函数【】

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IPJMRoCA-1663649049909)(D:\typora笔记\promise\img\1663399313648.png)]

    2.具体表达

    1. 从语法上来说:Promise是一个构造函数
    2. 从功能上来说:Promise对象用来封装一个异步操作并可以获取其成功/失败的结果值
    1.2 promise的状态改变

    由于Promise实例中有一个属性:PromiseState有三种状态

    pending	未决定的,初化状态
    resolved / fullfilled 成功,如果成功后,则将状态修改成该状态
    rejected 失败  如果失败后,则将状态修改成该状态
    
    1. pending变为resolved
    2. pending变为rejected

    说明:只有这2种,且一个promise对象只能改变一次,无论变为成功还失败,都会有一个结果数据,成功的结果数据一般称为了 value,失败的结果数据一般称为reason

    1.3Promise对象值

    实例对象量的另一个属性PromiseResutl,保存着是异步任务【成功/失败】的结果,这个状态只能使用resolvereject两个对象进行修改

    • resolve
    • reject

    在这里插入图片描述

    1.4 promise的执行流程

    在这里插入图片描述

    2.Promise快速入门

    案例:

            /**
                点击按钮,  1s 后显示是否中奖(30%概率中奖)
                    若中奖弹出    恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券
                    若未中奖弹出  再接再厉
            */
    

    传统方式一:

    <body>
        <div class="container">
            <h2 class="page-header">Promise 初体验</h2>
            <button class="btn btn-primary" id="btn">点击抽奖</button>
        </div>
        <script>
            //生成随机数
            function rand(m,n){
                return Math.ceil(Math.random() * (n-m+1)) + m-1;
            }
            /**
                点击按钮,  1s 后显示是否中奖(30%概率中奖)
                    若中奖弹出    恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券
                    若未中奖弹出  再接再厉
            */
             // 方式一:使用传统方式
            //获取元素对象
            let bnt = document.getElementById("btn");
            
    
            // 使用传统方式一;
           // 绑定单击事件
            bnt.onclick = ()=>{
                let result = rand(1,100);
                // 使用定时器 1s 后开奖
                setTimeout(()=>{
                    if(result<=30){
                        alert("恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券");
                    }else{
                        alert("再接再厉");
                    }
                },1000);
            };
    
        </script>    
    </body>
    

    Promise方式二:

            // 使用Promise方式二;
           // 绑定单击事件
            bnt.onclick = ()=>{
                // 由于Promise是构造函数,所以可以直接new对象
                // 在Promise需要接收一个函数
                // 在这个函数中需要两个参数:resolve 和 reject 这个参数都是 `函数类型的数据`
                // 
                let p = new Promise((resolve,reject)=>{
                    setTimeout(() => {
                        //30%  1-100  1 2 30
                        //获取从1 - 100的一个随机数
                        let n = rand(1, 100);
                        //判断
                        if(n <= 30){
                            resolve(); // 将 promise 对象的状态设置为 『成功』
                        }else{
                            reject(); // 将 promise 对象的状态设置为 『失败』
                        }
                    }, 1000);
                });
    
                // 对回调的结果进行处理
                // then需要接收两个回调函数
                // 第一个参数:成功后调用
                // 第二个参数:失败后调用
                p.then(()=>{
                    alert("恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券");
                },
                ()=>{
                    alert("再接再厉");
                });
    
    <body>
        <div class="container">
            <h2 class="page-header">Promise 初体验</h2>
            <button class="btn btn-primary" id="btn">点击抽奖</button>
        </div>
        <script>
            //生成随机数
            function rand(m,n){
                return Math.ceil(Math.random() * (n-m+1)) + m-1;
            }
            /**
                点击按钮,  1s 后显示是否中奖(30%概率中奖)
                    若中奖弹出    恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券
                    若未中奖弹出  再接再厉
            */
             // 方式一:使用传统方式
            //获取元素对象
            let bnt = document.getElementById("btn");
           
    
            // 使用Promise方式二;
           // 绑定单击事件
            bnt.onclick = ()=>{
                // 由于Promise是构造函数,所以可以直接new对象
                // 在Promise需要接收一个函数
                // 在这个函数中需要两个参数:resolve 和 reject 这个参数都是 `函数类型的数据`
                // 
                let p = new Promise((resolve,reject)=>{
                    setTimeout(() => {
                        //30%  1-100  1 2 30
                        //获取从1 - 100的一个随机数
                        let n = rand(1, 100);
                        //判断
                        if(n <= 30){
                            resolve(n); // 将 promise 对象的状态设置为 『成功』
                        }else{
                            reject(n); // 将 promise 对象的状态设置为 『失败』
                        }
                    }, 1000);
                });
    
                // 对回调的结果进行处理
                // then需要接收两个回调函数
                // 第一个参数:成功后调用
                // 第二个参数:失败后调用
                p.then((value)=>{
                    alert("恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券,您的中奖数字为"+value);
                },
                (reason)=>{
                    alert("再接再厉,您的号码为"+reason);
                });
            };
    
        </script>    
    </body>
    

    3.fs读取文件

    使用传统回调函数方式:

    // 回调用函数形式
    const fs = require('fs');
    fs.readFile('./resource/content.txt',(err,data)=>{
        // 如果出现异常,抛出
        if(err){
            throw err;
        }
        // 没有异常则打印
        console.log(data.toString);
    });
    

    使用Promise方式:

    // 第一步:创建 Promise对象
    const p = new Promise((resolve,reject)=>{
        // 第二步:读取文件
        fs.readFile('./resource/content.txt',(error,data)=>{
            if(data){
                resolve(data);
            }
            if(error){
                reject(error);
            }
        });
    });
    
    p.then(
        (data)=>{
            console.log(data.toString);
        },
        (err)=>{
            throw err;
        }
    );
    

    4.Promise实践练习AJAX请求

    传统方式:

    <body>
        <div class="container">
            <h2 class="page-header">Promise 封装 AJAX 操作</h2>
            <button class="btn btn-primary" id="btn">点击发送 AJAX</button>
        </div>
        <script>
            //接口地址 https://fanyi.baidu.com/
            //获取元素对象
            const btn = document.querySelector('#btn');
    
            // btn绑定单击事件
            btn.onclick = ()=>{
                // 创建对象
                let xhr = new XMLHttpRequest();
                // 初化url
                xhr.open("get","https://fanyi.baidu.com/");
                // 发送
                xhr.send();
                // 对响应结果处理
                xhr.onreadystatechange = ()=>{
                    // 判断是否完成响应
                    if(xhr.readyState === 4){
                        if(xhr.status>=200&&xhr.status<300){
                            alert(xhr.response);
                            console.log(xhr.response);
                        }else{
                            alert(xhr.status);
                        }
                    }
                };
            }
    
        </script>    
    </body>
    
    

    Promise方式

    <body>
        <div class="container">
            <h2 class="page-header">Promise 封装 AJAX 操作</h2>
            <button class="btn btn-primary" id="btn">点击发送 AJAX</button>
        </div>
        <script>
            //接口地址 https://fanyi.baidu.com/
            //获取元素对象
            const btn = document.querySelector('#btn');
    
            btn.onclick = ()=>{
                // 创建对象
    
                let p = new Promise((resolve,reject)=>{
                    let xhr = new XMLHttpRequest();
                    // 初化url
                    xhr.open("get","https://api.apiopen.top/getJoke");
                    // 发送
                    xhr.send();
    
                    // 判断是否成功响应
                    xhr.onreadystatechange = ()=>{
                        if(xhr.readyState===4){
                            if(xhr.status>=200&&xhr.status<300){
                                resolve(xhr.response);
                            }else{
                                reject(xhr.status);
                            }
                        }
                    }
                });
    
    
                // 处理promise的结果
                p.then(
                    (value)=>{
                        console.log(value);
                    },
                    (reason)=>{
                        console.log(reason);
                    });
            };
    
        </script>     
    </body>
    
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Promise 封装 AJAX</title>
        <link crossorigin='anonymous' href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    </head>
    <body>
        <div class="container">
            <h2 class="page-header">Promise 封装 AJAX 操作</h2>
            <button class="btn btn-primary" id="btn">点击发送 AJAX</button>
        </div>
        <script>
            //接口地址 https://api.apiopen.top/getJoke
            //获取元素对象
            const btn = document.querySelector('#btn');
    
            btn.addEventListener('click', function(){
                //创建 Promise
                const p = new Promise((resolve, reject) => {
                    //1.创建对象
                    const xhr = new XMLHttpRequest();
                    //2. 初始化
                    xhr.open('GET', 'https://api.apiopen.top/getJoke');
                    //3. 发送
                    xhr.send();
                    //4. 处理响应结果
                    xhr.onreadystatechange = function(){
                        if(xhr.readyState === 4){
                            //判断响应状态码 2xx   
                            if(xhr.status >= 200 && xhr.status < 300){
                                //控制台输出响应体
                                resolve(xhr.response);
                            }else{
                                //控制台输出响应状态码
                                reject(xhr.status);
                            }
                        }
                    }
                });
                //调用then方法
                p.then(value=>{
                    console.log(value);
                }, reason=>{
                    console.warn(reason);
                });
            });
        </script>
    </body>
    </html>
    
    

    5.Promise封装练习-fs模块

    案例:

    /**
     * 封装一个函数 mineReadFile 读取文件内容
     * 参数:  path  文件路径
     * 返回:  promise 对象,如果成功resovle,失败返回reject
     */
    
    
    /**
     * 封装一个函数 mineReadFile 读取文件内容
     * 参数:  path  文件路径
     * 返回:  promise 对象,如果成功resovle,失败返回reject
     */
    
    // 引入fs对象
    const fs = require('fs');
    
    // 封装函数 mineReadFile
    function mineReadFile(path){
        return new Promise((resovle,reject)=>{
            fs.readFile(path,(error,data)=>{
                if(error){
                    reject(error);
                }
                resovle(data);
            })
        });
    };
    
    
    // 调用函数测试
    mineReadFile("./resource/content.txt")
        .then(
            (data)=>{
                console.log(data);
            },
            (error)=>{
                console.log(error);
            });
    
    

    6.util.promisify方法

    /**
     * util.promisify 方法
     */
    
    // 引入模块
    const util = require("util");
    const fs = require("fs");
    
    // 返回一个新的函数对象
    let mineReadFile = util.promisify(fs.readFile);
    
    // 调用函数测试
    mineReadFile("./resource/content.txt")
        .then(
            (data)=>{
                console.log(data.toString());
            },
            (error)=>{
                console.log(error);
            });
    
    

    7.Promise封装AJAX请求

            /**
             * 封装一个函数 sendAJAX 发送 GET AJAX 请求
             * 参数   URL
             * 返回结果 Promise 对象
             */
    
    
    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Promise封装AJAX操作title>
    head>
    <body>
        <script>
            /**
             * 封装一个函数 sendAJAX 发送 GET AJAX 请求
             * 参数   URL
             * 返回结果 Promise 对象
             */
            function sendAJAX(url){
                return new Promise((resolve, reject) => {
                    const xhr = new XMLHttpRequest();
                    xhr.responseType = 'json';
                    xhr.open("GET", url);
                    xhr.send();
                    //处理结果
                    xhr.onreadystatechange = function(){
                        if(xhr.readyState === 4){
                            //判断成功
                            if(xhr.status >= 200 && xhr.status < 300){
                                //成功的结果
                                resolve(xhr.response);
                            }else{
                                reject(xhr.status);
                            }
                        }
                    }
                });
            }
        
            sendAJAX('https://api.apiopen.top/getJok')
            .then(value => {
                console.log(value);
            }, reason => {
                console.warn(reason);
            });
        script>
    body>
    html>
    
    

    PromiseAPI

    1.Promise构造函数:Promise(excutor){}
    1. executor函数:执行器(resolve,reject)=>{}
    2. resolve函数:内部定义成功时我们调用的函数value=>{}
    3. reject函数:内部定义失败时我们调用的函数reason=>{}

    说明:executor会在Promise内部立即同步调用,异常操作在执行器中执行【就是说:传入的箭头函数是立即执行的】

    2.Promise.prototype.then方法:(onResolved,onRejected)=>{}
    1. onResolved函数:成功的回调函数 (value)=>{}
    2. onReject函数:失败的回调函数 (reason)=>{}

    说明:指定用于得到成功value的成功回调和用于得到失败reason的失败回调返回一个新的promise对象

    3.Promise.prototype.catch方法:(onRejected)=>{}
    1. onRejected函数:失败的回调函数 (reason)=>{}
    2. then()语法糖,相当于then(undefiend,onRejected);

    说明:注意是:catch方法只能在失败时调用

    注意是:thencatch方法都在Promise对象调用的【也就是通过Promise构造函数创建的对象,对象名调用】,不能直接通过Promise.的形式调用

        <script>
            let p = new Promise((resovle,reject)=>{
                /**
                 * 我们可以通过rsovle或reject对象来修改是否成功或失败
                 */ 
                // resovle("海康");//设置成功
                reject("error");//设置失败
            });
    
            // 对p结果处理
            // p.then(
            //     (data)=>{
            //         console.log(data);
            //     },
            //     (error)=>{
            //         console.log(error);
            //     }
            // )
    
            // 注意是:catch方法只能处理失败后的结果 
            p.catch((error)=>{
                console.log(error);
            });
        </script>
    
    4. Promise.resolve方法:(value)=>{}
    1. value:成功的数据或promise对象

    说明:返回一个成功/失败的promise对象

    注意是:resolve方法是可以直接通过Promise.resolve("参数")调用的,并且可以传入参数,如果传入参数是非Promise对象返回就是成功,如果传入参数是Promise对象,传入的Promise对象返回成功就是成功,返回失败就是失败

        <script>
            // Promise.resolve("参数")方法
            /**
             * 1.如果传入的参数为 非Promise类型的对象,则返回结果为成功的Promise对象。例如:传入 数值 布尔 等【除了Promse对象】
             * 
             * 2.如果传入的参数为 Promise类型的对象,则返回结果由传入的Promise对象决定,如果传入的Promise返回的结果是成功,则成功,如果传入的Promise返回结果是失败,返回的结果就是失败
             */ 
    
             let p = Promise.resolve("海康");// 返回结果为:成功
    
             let p2 = Promise.resolve(new Promise((resovle,reject)=>{
                /**
                 * 可以使用 resovle和reject函数对象修改是否成功或失败
                 */
                // resovle("湛江");
                reject("error");
             }));
    
             // 对象p2结果进行处理
             p2.then(
                (data)=>{
                    console.log(data);
                },
                (error)=>{
                    console.log(error);
                });
        </script>
    
    5.Promise.reject方法:(reason)=>{}
    1. reason:失败的原因

    说明:返回一个失败的promise对象,不管传入的参数是什么永远返回的Promise结果都是失败的

        <script>
            // 在reject函数中不管传入什么参数,返回的结果永远都失败的
            let p = Promise.reject("永远都是失败的reject函数");
    
            p.catch((error)=>{
                console.log(error);
            });
        </script>
    
    6.Promise.all方法:(promise)=>{}
    1. promise:包含npromise的数组

    说明:返回一个新的promise,只有所有的promise都成功才成功,只要有一个失败了就直接失败,注意是:返回所有成功promise对象组成的数组,失败就是直接返回失败的那个promise对象

    <script>
            // 定义几个Promise对象
            let p1 = new Promise((resolve,reject)=>{
                resolve("湛江");
            });
            let p2 =  Promise.resolve("海康");
            let p3 =  Promise.resolve("南宁");
    
            /**
             * 1.由于三个返回的结果都是成功,所以三者组成的数组返回,总结:成功组成数组全部返回
             * 2.如果其中的 p2 返回的结果是失败,则直接返回 p2 的结果
             */ 
            let result = Promise.all([p1,p2,p3]);
    </script>
    
    7.Promise.race方法:(promise)=>{}
    1. promise:包含npromise的数组

    说明:返回一个新的promse,第一个完成的promise的结果状态就是最终的结果状态

    Promise.reace方法中的那个promise对象状态先改变,返回结果就是那个对象的状态,如果那个对象返回成功,则成功,返回失败,则失败

    <script>
            // 定义几个Promise对象
            let p1 = new Promise((resolve,reject)=>{
               setTimeout(()=>{
                    resolve("湛江");
               },1000);
            });
            let p2 =  Promise.resolve("海康");
            let p3 =  Promise.resolve("南宁");
    
            /**
             * race返回的结果就是由于那个一个最先改状态的那个Promise对象,
             * 如果在这个案例中,是第二个先修改状态,所以返回就是第二个,由于返回成功,则成功,如果返回失败,则失败
             */ 
            let result = Promise.race([p1,p2,p3]);
    </script>
    

    注意是:resolve() reject() all() race()这四个方法都可以通过Promise.的方式来调用的

    asyncawait

    1.asyn函数

    1. 函数的返回值为promise对象
    2. promise对象的结果由async函数执行的返回值决定
      1. 如果返回值是非Promise对象,则返回就会成功的Promise对象
      2. 如果返回值是Promise对象,则Promise返回成功还是失败,由该Promise成功还是失败决定
      3. 如果抛出异常,则直接返回失败的Promise对象

    asynthenPromise.resolve()函数返回值一样的规则

        <script>
            // async函数
            async function main(){
                // 1.如果直接返回一个 非Promise对象【如布尔 数值 字符串 null undefiend】,则async函数返回值就是一个成功的promise对象
                return "海康"; // 返回是成功的
    
                // 2.如果返回值是:Promise对象,成功还是失败,由该Promise对象决定
                return new Promise((resolve,reject)=>{
                    // 返回失败,则失败
                    // reject("error");
                    // 返回成功,则成功
                    resolve("success");
                });
    
                // 3.抛出异常,返回Promise对象是失败的
                throw "失败的Promise";
            }
    
            let result = main();
            alert(result);
        </script>
    

    2. await表达式

    1. await右侧的表达式一般为promise对象,但也可以是其它的值
    2. 如果表达式是promise对象,并且promise是成功,await返回的是promise成功的值【是获取成功后传入的参数值,如果传入是success,则返回就是success
    3. 如果表达式是promise对象,并且promise是失败,我们需要使用try-catch来捕获await语句
    4. 如果表达式是其它值,直接将此值作为await的返回值

    注意:

    1. await必须写在async函数中,但async函数中可以没有await
    2. 如果awaitpromise失败了,就会抛出异常,需要通过try-catch捕获处理
        <script>
            // 注意是:await必须在async
            async function main(){
                // 1.await右侧是 非Promies对象,await会将该值当返回值返回
                let res1 = await "海康";
    
                console.log(res1);
    
                // 2.await右侧是 Promise对象,如果 Promise对象是成功的,则返回成功的值
    
                let p = new Promise((resolve,reject)=>{
                    resolve("success");
                });
    
                let res2 = await p;
    
                console.log(res2);
                console.log(typeof res2);
    
                // 3.await右侧是 Promise对象,如果 Promise对象是失败的,则需要`try-catch`来对`await`语句进行捕获
                let p2 = new Promise((resolve,reject)=>{
                    reject("error");
                });
    
                try{
                    let res3 = await p2;
                }catch(e){
                    console.log(e);
                }
    
            }
    
            main();
        </script>
    

    3.asyn函数与await表达式

    注意是:util中的promisify(参数)是可以将一些API转换成promise对象,如:util.promisify(fs.readFile);

    使用asyn函数与await表达式读取三个文件中的内容,并且拼接在一定输出

    const fs = require("fs");
    const util = require("util");
    const mineReadFile = util.promisify(fs.readFile);
    
    async function main(){
        let data1 = await mineReadFile("./resource/1.html")
        let data2 = await mineReadFile("./resource/2.html")
        let data3 = await mineReadFile("./resource/3.html")
    
        console.log(data1+data2+data3);
    }
    
    main();
    

    4.asyncawait结合发送AJAX请求

    <!DOCTYPE html>
    <html lang="en">
    <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>
        <button>获取段子了...</button>
        <script>
            // 封装 ajax 
            function sendAJAX(url){
                return new Promise((resovle,reject)=>{
                    // 创建XMLHttpRequest
                    let xhr = new XMLHttpRequest();
                    xhr.open('get',url);
                    xhr.send();
                    xhr.onreadystatechange = ()=>{
                        if(xhr.readyState===4){
                            if(xhr.status>=200&&xhr.status<300){
                                resovle(xhr.response);
                            }else{
                                reject(xhr.status);
                            }
                        }
                    }
                });
            }
    
    
            // 使用async与await结合发送ajax请求
            // 获取button对象
            let bnt = document.getElementsByTagName("button")[0];
            // 绑定单击事件
            //段子接口地址 https://api.apiopen.top/getJoke
            bnt.onclick = async function(){
                alert("fdsfs");
                let result = await sendAJAX("https://api.apiopen.top/getJoke");
                console.log(result);
            }
        </script>
    </body>
    </html>
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>asyncawait结合发送AJAX</title>
    </head>
    <body>
        <button id="btn">点击获取段子</button>
        <script>
            //axios
            function sendAJAX(url){
                return new Promise((resolve, reject) => {
                    const xhr = new XMLHttpRequest();
                    xhr.responseType = 'json';
                    xhr.open("GET", url);
                    xhr.send();
                    //处理结果
                    xhr.onreadystatechange = function(){
                        if(xhr.readyState === 4){
                            //判断成功
                            if(xhr.status >= 200 && xhr.status < 300){
                                //成功的结果
                                resolve(xhr.response);
                            }else{
                                reject(xhr.status);
                            }
                        }
                    }
                });
            }
    
            //段子接口地址 https://api.apiopen.top/getJoke
            let btn = document.querySelector('#btn');
    
            btn.addEventListener('click',async function(){
                //获取段子信息
                let duanzi = await sendAJAX('https://api.apiopen.top/getJoke');
                console.log(duanzi);
            });
        </script>
    </body>
    </html>
    
  • 相关阅读:
    Windows学习总结(24)—— 升级到 Windows 11 版本的九个理由
    2022年8月9日:使用 ASP.NET Core 为初学者构建 Web 应用程序--使用 HTML、CSS 和 Javascript 构建简单的网站
    如何使用postman调用若依系统接口(报错401,认证失败,无法访问系统资源)
    SpringMVC面试题
    新一代L3虚拟网络接入解决方案(畅想)
    Postgresql查询执行模块README笔记
    【SpringBoot整合MQ】-----SpringBoot整合Kafka
    新版C语言面试题面试题库(含答案)
    (硬件设计)老工程师的经验之道
    Enscape 4.1.0 软件安装教程+离线资源库
  • 原文地址:https://blog.csdn.net/weixin_47267628/article/details/126950917