`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>
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值