javascript-Promise对象

状态

PromiseState

Pending Resolved(fulfilled) Rejected

状态变化:Pending->Resolved,Pending->Rejected

PromiseResult

保存着对象成功或失败的结果

resolve reject可以修改这个属性的结果

特点

  • 状态不受外界影响,只有异步操作的结果才能改变
  • 一旦状态改变,就不会在变。

流程

在这里插入图片描述

入门样例

<!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>
        var btn = document.querySelector("button");

        function createNumber() {
    
    
            return Math.floor(Math.random() * 100);
        }
        btn.addEventListener("click", () => {
    
    
            var p = new Promise((resolve, reject) => {
    
    
                var num = createNumber();
                setTimeout(() => {
    
    
                    if (num < 30) {
    
    
                        resolve(num);
                    } else {
    
    
                        reject(num);
                    }
                }, 1000);
            });
            p.then((value)=>{
    
    
                alert(`中奖了${
      
      value}`);
            }, (reason)=>{
    
    
                alert(`没mei${
      
      reason}`);
            });

        })
    </script>
</body>

</html>

操作文件

const fs = require("fs");

// fs.readFile('test.txt', (err, data)=>{
    
    
//     if(err) throw err;
//     console.log(data.toString());
// });
const p = new Promise((resole, reject)=>{
    
    
    fs.readFile('test.txt',(err, data)=>{
    
    
        if (err) reject(err);
        resole(data);
    });
})
p.then((value)=>{
    
    
    console.log(value.toString());
},(reason)=>{
    
    
    throw reason;
});

发送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>ajax请求</button>
    <script>
        let btn = document.querySelector("button");
        btn.addEventListener("click", function () {
    
    
            const p = new Promise((resolve, reject) => {
    
    
                const xhr = new XMLHttpRequest();
                xhr.open("get", "https://api.apiopen.top/getAllUrl");
                // method, url, async
                
                // 监听xhr.readyState属性值的变化,当这个属性值发生变化时,
                // 会执行这个回调函数
                xhr.onreadystatechange = function () {
    
    
                    if (xhr.readyState == 4){
    
     
                        // readyState有0,1,2,3,4五种状态,4 === XMLHttpRequest.DONE
                        // 表示下载操作以完成
                        if (xhr.status == 200){
    
    
                            resolve(xhr.response);
                        }else{
    
    
                            reject(xhr.status);
                        }
                    }
                };
                xhr.send();
            });
            p.then((value)=>{
    
    
                console.log(value);
            },(reason)=>{
    
    
                console.log(reason);
            });
        });
    </script>
</body>

</html>

封装读取文件内容的函数

/**
 * 封装函数读取文件内容
 * 参数:文件路径
 * 返回值:promise对象
 */

function readFile(path){
    
    
    return new Promise((resolve, reject)=>{
    
    
        require('fs').readFile(path, (err,data)=>{
    
    
            if (err) reject(err);
            resolve(data);
        });
    });
}
readFile('test.txt').then(value=>{
    
    
    console.log(value.toString());
},reason=>{
    
    
    console.log(reason);
});

引入node.js的util模块的promisfy方法,封装函数

const util = require('util');
const fs = require('fs');

// promisify参数是个err first类型的函数
let readFile = util.promisify(fs.readFile);

readFile('test.txt').then(value=>{
    
    
    console.log(value.toString());
},reason=>{
    
    
    console.log(reason);
});

Promise对象实例的api

  • 构造函数:注意Promise构造函数内部的代码是同步执行的
  • then():对成功和失败的回调函数,返回一个promise对象,这个Promise对象的状态由回调函数决定,如果回调函数 throw “error”,那么状态是reject;如果 return 非Promise对象,那么状态是resolve;如果 return Promise,那么状态由这个Promise对象决定。注意then()的两个参数,也就是回调函数是异步执行的,必须等同步代码执行后,在执行异步代码
  • catch():对失败的回调函数

Promise对象的api

  • Promise.resolve():返回一个成功或失败的Promise对象

    参数:非Promise对象的值,返回一个成功的Promise对象

    ​ 传入一个Promise对象,则返回的Promise对象的状态与传入参数的Promise对象相同

    <!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>
        <script>
            let p1 = Promise.resolve(11);
            /**
             * Promise
    ·········· __proto__: Promise
    ·········· [[PromiseState]]: "fulfilled"
               [[PromiseResult]]: 11
             */
            console.log(p1);
            let p2 = Promise.resolve(new Promise((resolve, reject)=>{
          
          
                resolve("hahha");
            }))
            /**
             *  Promise {<fulfilled>: "hahha"}
                __proto__: Promise
                [[PromiseState]]: "fulfilled"
                [[PromiseResult]]: "hahha"
             */
            console.log(p2);
    
            let p3 = Promise.resolve(new Promise((resolve,reject)=>{
          
          
                reject('error');
            }));
            // Promise {<rejected>: "error"}
            // __proto__: Promise
            // [[PromiseState]]: "rejected"
            // [[PromiseResult]]: "error"
            p3.catch(reason=>{
          
          
                console.log(reason); // error
            });
            console.log(p3);
        </script>
    </body>
    </html>
    
  • Promise.reject():返回一个失败的Promise对象

    let p4 = Promise.reject(11);
    /**
    __proto__: Promise
    [[PromiseState]]: "rejected"
    [[PromiseResult]]: 11
    */
    let p5 = Promise.reject(new Promise((resolve, reject)=>{
          
          
        reject('ok');
        // resolve('ok');
    }))
    /**
    __proto__: Promise
    [[PromiseState]]: "rejected"
    [[PromiseResult]]: Promise
    */
    console.log(p5);
    
  • Promise.all():参数promise的数组,只有数组的promise状态全部为成功,结果才为成功,PromiseResult的值就是一个数组;如果数组中的promise只要有一个是失败的话,则返回失败的Promise,且PromiseResult的值是参数数组中第一个失败的Promise的PromiseResult

    let p6 = new Promise((resolve, reject) => {
          
          
                resolve('ok');
            });
    
    let p8 = Promise.resolve("hhaha");
    let p7 = Promise.resolve(1233);
    let pall = Promise.all([p6, p8, p7]);
    console.log(pall);
    /*
    __proto__: Promise
    [[PromiseState]]: "fulfilled"
    [[PromiseResult]]: Array(3)
    0: "ok"
    1: 1233
    2: "hhaha"
    */
    
    let p6 = new Promise((resolve, reject) => {
          
          
                resolve('ok');
            });
    
    let p8 = Promise.reject("hhaha");
    let p7 = Promise.reject(1233);
    let pall = Promise.all([p6, p8, p7]);
    console.log(pall);
    
    // __proto__: Promise
    // [[PromiseState]]: "rejected"
    // [[PromiseResult]]: "hhaha"
    
  • Promise.race():参数:promise数组,返回一个新的Promise,状态由参数数组中第一个完成的Promise的状态决定

    let p6 = new Promise((resolve, reject) => {
          
          
                resolve('ok');
            });
    let p8 = Promise.reject("hhaha");
    let p7 = Promise.reject(1233);
    let p_race = Promise.race([p6, p7,p8]); // 根据数组的顺序判断
    console.log(p_race);
    /*
    __proto__: Promise
    [[PromiseState]]: "fulfilled"
    [[PromiseResult]]: "ok"
    */
    

改变Promise状态的3种方式

  • resolve
  • reject
  • throw:pedding->reject

当用then对Promise指定多个成功或失败的回调函数时,当Promise状态改变时对应成功的回调函数都会执行在这里插入图片描述

Promise的链式调用

原因就是then()函数返回的是一个Promise对象

<!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>
    <script>
        let p1 = new Promise((resolve, reject) => {
     
     
            setTimeout(() => {
     
     
                resolve("ok");
            }, 1000);
        });
        p1.then(value => {
     
     
            console.log(value);
            return new Promise((resolve, reject) => {
     
     
                resolve("success");
            });
        }).then(value => {
     
     
            console.log(value);
        }).then(value => {
     
     
            console.log(value);
        });
        // ok
        // success
        // undefined
    </script>
</body>

</html>

Promise的异常穿透

使用then链式调用,可以在最后指定失败的回调

<!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>
    <script>
        let p1 = new Promise((resolve, reject) => {
    
    
            setTimeout(() => {
    
    
                resolve("ok");
            }, 1000);
        });
        p1.then(value => {
    
    
            console.log(value);
            return new Promise((resolve, reject) => {
    
    
                resolve("success");
            });
        }).then(value => {
    
    
            console.log(value);
        }).then(value => {
    
    
            console.log(111);
            throw "失败;了";
        }).catch(value=>{
    
    
            console.log(value);
        });
        // ok
        // success
        // 111
        // 失败;了
    </script>
</body>

</html>

中断Promise链

返回一个Promise状态为pedding即可

<!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>
    <script>
        let p1 = new Promise((resolve, reject) => {
    
    
            setTimeout(() => {
    
    
                resolve("ok");
            }, 1000);
        });
        p1.then(value => {
    
    
            console.log(value);
            return new Promise((resolve, reject) => {
    
    
                resolve("success");
            });
        }).then(value => {
    
    
            console.log(11);
            return new Promise(()=>{
    
    });
        }).then(value => {
    
    
            console.log(22);

        }).then(value => {
    
    
            console.log(33);
        }).catch(value => {
    
    
            console.log(value);
        });
        // ok
        // 11
    </script>
</body>

</html>

自定义Promise,并封装成类

class Promise {
    
    
    constructor(executor) {
    
    
        this.PromiseState = "pending";
        this.PromiseResult = null;
        this.callbacks = [];
        const self = this;

        function resolve(data) {
    
    
            if (self.PromiseState !== "pending") return;
            self.PromiseState = "resolve";
            self.PromiseResult = data;
            // 状态改变,执行回调
            setTimeout(() => {
    
    
                self.callbacks.forEach(item => {
    
    
                    item.onresolve(data);
                });
            });
        }

        function reject(data) {
    
    
            if (self.PromiseState !== "pending") return; // 保证状态只能改变一次
            self.PromiseState = "reject";
            self.PromiseResult = data;
            // 状态改变,执行回调
            setTimeout(() => {
    
    
                self.callbacks.forEach(item => {
    
    
                    item.onreject(data);
                });
            });
        }
        try {
    
    
            // 构造函数内的代码要同步执行
            executor(resolve, reject);
        } catch (error) {
    
    
            reject(error);
        }
    }
    then(onresolve, onreject) {
    
    
        const self = this;
        // 设置异常穿透
        if (typeof onreject !== "function") {
    
    
            onreject = reason => {
    
    
                throw reason;
            }
        }
        if (typeof onresolve !== "function") {
    
    
            onresolve = value => value;
            // onresolve = value = { return value};
        }
        return new Promise((resolve, reject) => {
    
    
            function callback(type) {
    
    
                try {
    
    
                    let result = type(self.PromiseResult);
                    if (result instanceof Promise) {
    
    
                        result.then(v => {
    
    
                            resolve(v);
                        }, r => {
    
    
                            reject(r);
                        });
                    } else {
    
    
                        resolve(result);
                    }
                } catch (error) {
    
    
                    reject(error);
                }
            }
            // 调用回调函数
            if (this.PromiseState === "resolve") {
    
    
                setTimeout(() => {
    
    
                    callback(onresolve);
                });

            }
            if (this.PromiseState === "reject") {
    
    
                setTimeout(() => {
    
    
                    callback(onreject);
                });
            }
            // 改变状态执行回调
            if (this.PromiseState === "pending") {
    
    
                this.callbacks.push({
    
    
                    onresolve: function () {
    
    
                        callback(onresolve);
                    },
                    onreject: function () {
    
    
                        callback(onreject);
                    }
                });
            }
        });

    }
    catch (onreject) {
    
    
        this.then(undefined, onreject);
    }

    static resolve(value) {
    
    
        return new Promise((resolve, reject) => {
    
    
            if (value instanceof Promise) {
    
    
                value.then(v => {
    
    
                    resolve(v);
                }, r => {
    
    
                    reject(r);
                });
            } else {
    
    
                resolve(value);
            }
        });
    }

    static reject(reason) {
    
    
        return new Promise((resolve, reject) => {
    
    
            reject(reason);
        });
    }

    static all(promises) {
    
    
        return new Promise((resolve, reject) => {
    
    
            let count = 0;
            let arr = [];
            for (let i = 0; i < promises.length; i++) {
    
    
                promises[i].then(v => {
    
    
                    // 对象状态成功
                    count++;
                    arr[i] = v;
                    if (count === promises.length) {
    
    
                        resolve(arr);
                    }
                }, r => {
    
    
                    reject(r);
                });
            }
        });
    }

    static race(promises) {
    
    
        return new Promise((resolve, reject) => {
    
    
            for (let i = 0; i < promises.length; i++) {
    
    
                promises[i].then(v => {
    
    
                    resolve(v);
                }, r => {
    
    
                    reject(r);
                })
            }
        });
    }
}

async函数

  • 函数的返回值是一个Promise对象,且该Promise对象的状态由async函数的返回值决定,规则与then()一致

await

在这里插入图片描述

  • 必须放在async函数内,但是async函数不一定需要await

  • await右边是Promise对象,那么返回Promise成功的状态;如果不是Promise对象,则直接返回原来的数;

  • 如果await右边的Promise对象状态是reject(reject()或throw)的,那么需要通过try()catch()捕获reason

    <!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>
        <!-- <script src="自定义.js"></script> -->
    </head>
    <body>
        <script>
            async function test(){
          
          
                let p = new Promise((resolve, reject)=>{
          
          
                    // resolve("ok");
                    // reject("error");
                    throw "error";
                });
                // let res = await p; // ok
                let res1 = await 1233; // 1233
                try{
          
          
                    let res = await p; // 不能省略
                }catch(e){
          
          
                    console.log(e) // error
                }
                // console.log(res);
            }
            test();
        </script>
    </body>
    </html>
    

    async与await配合使用

    const util = require('util');
    const fs = require('fs');
    const readFile = util.promisify(fs.readFile); // 返回一个Promise对象
    
    async function main(){
          
          
        let data1 = await readFile("1.txt");
        let data2 = await readFile("2.txt");
        let data3 = await readFile("3.txt");
        console.log(data1+data2+data3);
    }
    // 看不见回调函数,但是代码却是异步操作的
    
    main();
    

    async与await发送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>发送ajax</button>
        <script>
            function sendAjax(url) {
           
           
                return new Promise((resolve, reject) => {
           
           
                    const xhr = new XMLHttpRequest();
                    xhr.open("get", url);
                    xhr.onreadystatechange = function () {
           
           
                        if (xhr.readyState == 4) {
           
           
                            if (xhr.status == 200) {
           
           
                                resolve(xhr.response);
                            } else {
           
           
                                reject(xhr.status);
                            }
                        }
                    };
                    xhr.send();
                });
            }
            let btn = document.querySelector("button");
            btn.addEventListener("click", async function(){
           
           
                let url = "https://api.apiopen.top/getAllUrl";
                let res = await sendAjax(url);
                console.log(res);
            });
        </script>
    </body>
    
    </html>
    

猜你喜欢

转载自blog.csdn.net/weixin_42100456/article/details/114907274