异步编程的实现 —— Promise

需要明白

JavaScript是一门单线程语言,不支持多线程,是从上往下一行一行执行的同步任务,这就意味着没法使用多线程来同时处理多个任务,但是js中存在任务队列,当主程序执行完之后,会轮训任务队列依次执行,这也是我们学习的异步任务,使用Promise实现异步操作。
同步:同一时间只能做一个任务;
异步:同一时间做多个任务。

比如:定时器就是异步任务,当程序解读到定时器时,不管定时的时间有多短,它都会被系统抛到任务队列中等侯,等到主程序任务执行完毕,任务队列会依次把定时器再抛回主程序执行。

        setTimeout(() => {
            console.log("宏任务1");
        }, 0)

        console.log("主程序同步任务1");

异步编程的实现 —— Promise_第1张图片

Promise三种状态

pending:进行中
fulfilled:已成功
rejected:已失败

resolved:表示已定型。当状态有pending到fulfilled还是pengding到rejected,只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。

Promise的特点:
Promise:对象的状态不受外界影响。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
Promise:一旦状态改变,就不会再变,任何时候都可以得到这个结果

promise语法

Promise是一个构造函数,需要实例化。这个构造函数的参数是一个函数,该函数接收两个参数。

        let p1 = new Promise((resolve, reject) => {
            // 成功 
            resolve();
            // 失败
            // reject();
        });

实例化对象之后,通过then方法分别指定resolved状态和rejected状态的回调函数。
参数1是resolved状态的回调函数;参数2是rejected状态的回调函数,这个参数是可选的,一般用catch方法捕获错误信息,后面会介绍的。

		p1.then(result => result, resaon = resaon)

完整的链式操作:

        let p1 = new Promise((resolve, reject) => {
            // 成功 
            // resolve();
            // 失败
            reject();
        }).then(success => {
            console.log("成功的业务处理 1");

        }, fail => {
            console.log("失败拒绝的业务处理");

        }).then(success => {
            console.log("成功的业务处理 2");

        }, fail => {
            console.log("失败拒绝的业务处理");
        });

第一个then方法是处理上面的Promise实例,同时返回一个新的Promise实例对象,第二个then方法是对该新Promise对象的处理,默认是resolved状态,所以是成功的。
异步编程的实现 —— Promise_第2张图片

Promise微任务队列

Promise的队列是微任务队列,定时器、函数等是宏任务队列。微任务队列同样是等主程序任务执行完成后再执行。

任务执行顺序

整个顺序是:主任务 、微任务队列、宏任务队列。

        setTimeout(() => {
            console.log("宏任务1");
        }, 0)

        console.log("主程序同步任务1");

        new Promise((resolve, reject) => {
            //这里面的代码是同步任务
            console.log("Promise中的同步任务");
            // 只有success和fail的执行是微任务,也就是对应着then方法的执行放到微任务队列中
            // then方法的代码只有在接收到成功或失败的信号时才会执行
            resolve(); // 它的位置不影响任务是主程序还是微任务 放到第一行显示还是一样的
        }).then(result => {
            console.log("成功微任务1");
        }, reason => {
            console.log("失败微任务2");
        })

宏任务中存在微任务

注释里有很清楚的解释。

        console.log("主1");
        new Promise(resolve => {
            // 程序走到这时,是主程序的同步任务 
            // 遇到定时器时,把它放入到宏任务当中,等到主程序和微任务执行完
            setTimeout(() => {
                console.log("setTimeout");
                // 此时把任务成功失败的标志写在定时器里时就不同了
                // 这就代表整个程序只有主任务和宏任务了,主任务执行完之后,开始执行宏任务setTimeout
                // 整个定时器会被抛到主任务中,当定时器的所有任务执行完之后(输出setTimeout),才会把resolve抛给微任务
                // 主程序执行完了,接着执行微任务 输出成功
                resolve(); // 输出: 主1  setTimeout 成功
            }, 0);

            // resolve(); // 输出: 主1  成功 setTimeout
        }).then(reslove => {
            console.log("成功");
        })

Promise.then()

then方法是处理Promise实例对象的两个状态的回调函数。
then方法实质上也是一个Promise对象,它执行过后返回一个新的Promise对象。
在多个then方法链式调用时,第二个then方法是对第一个then方法处理完Promise返回的新Promise对象的回调函数,依次类推。

		let p1 = new Promise((resolve, reject) => {
            // 成功 
            resolve("成功的业务处理 1");
        });
        let p2 = p1
            .then( // 这个then是处理上一个promise
                success => console.log(success),
                fail => console.log(fail)
            ) // 下面的then方法默认是对成功状态处理,自动走成功的函数
            .then(
                success => console.log("success"),
                fail => console.log(fail)
            );

异步编程的实现 —— Promise_第3张图片

then返回值的处理

在then中也可以返回一个新的Promise实例对象,则其后面紧接着的then方法是对返回的新Promise的处理。

        // Promise后面的then方法是对前面一个Promise的处理.
        new Promise((resolve, reject) => {
                reject("处理失败了");
            })
            .then(null, reson => {
                console.log(reson);
                // 返回了一个Promise,下面接着的then方法就是对这个返回的Promise做处理
                return new Promise((resolve, reject) => {
                        // resolve("成功处理.....");
                        reject("失败了........")
                    }) // 处理上面的promise
                    .then(null,
                        reason=> {
                            console.log(reason);
                            // 下面没有then方法 这个新的Promise实例对象返回出去
                            return new Promise((resolve, reject) => {
                                reject("最终还是失败了");
                            });
                        });
            })
            // 是对最里面返回的Promise做处理.  一个Promise对应一个then. 下一个then是一个新的Promise
            .then(
                res => console.log(res),
                reson => console.log("error: " + reson)
            )

Promise.catch()

then方法的两个参数中的第二个参数是可选的,是Promise状态为rejected的回调函数,通常我们不使用它,使用catch() 方法捕获错误信息。

        let p1 = new Promise((resolve, reject) => {
                reject("失败了");
            })
            .then(success => {
                console.log("成功的业务处理 1");
            })
            .catch(error => console.log(new Error(error)))

异步编程的实现 —— Promise_第4张图片

Promise.race()

该方法把多个Promise实例包装成一个新的Promise对象。
方法返回的实例的状态取决于 : 率先变换状态的那个Promise实例。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

        // Promise.race()方法 返回的是参数实例状态率改变的那个
        // 哪个返回的快  使用哪个
        const p1 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve("p1成功")
            }, 5000)
        });

        const p2 = new Promise((resolve, reject) => {
            setTimeout(() => {
                reject(new Error("request timeout"))
                // resolve("p2的2秒")
            }, 2000)
        });

        const p3 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve("p3的3秒")
            }, 3000)
        });
        const p = Promise.race([p1, p2, p3])
            .then(result => console.log(result))
            .catch(error => console.log(error));

最先状态改变的是p2,2秒。所以Promise.race() 返回的是p2的状态同时接收p2的返回值作为回调函数的参数。
异步编程的实现 —— Promise_第5张图片

Promise.finally()

finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。

        new Promise((resolve, reject) => {
            reject("error")
        }).finally(() => {
            console.log("不管怎样 都会执行");
        }).catch(error => error)

Promise.resolve()

把现有的对象变为Promise实例对象的方法。
参数的形式有四种:

  1. 参数是 Promise实例 ---- 返回实例本身
        // 1. Promise实例
        const promise = new Promise((resolve, reject) => {
            resolve("promise实例本身");
        }).then(res => console.log(res));
        console.log(promise); // 返回实例本身

异步编程的实现 —— Promise_第6张图片

  1. 参数是带有then方法的对象,转换为Promise对象,并立即执行原始对象的then方法
        const obj = {
            then: function (resolve, reject) {
                resolve("带then方法的对象");
            }
        };
        const objPromise = Promise.resolve(obj)
            .then(res => console.log(res))
        // console.log(objPromise); // 返回Promise实例,并执行源对象的then方法

异步编程的实现 —— Promise_第7张图片

  1. 参数是不带the方法的对象或者原始值,返回一个新的Promise对象,并把对应的参数值传给回调函数,状态值为resolved
        // 3.不带then方法的对象或者原始值
        const originNum = Promise.resolve("hello");
        originNum.then(res => console.log(res))
        console.log(originNum);

异步编程的实现 —— Promise_第8张图片

        // 4. 没有参数
        const nullParams = Promise.resolve();
        console.log(nullParams);

异步编程的实现 —— Promise_第9张图片

Promise.reject()

方法也会返回一个新的 Promise 实例,该实例的状态为rejected。
参数会原封不动的传给实例对象的rejected的回调函数。

        const selfReject = Promise.reject("错误程序");
        selfReject.then(null, reason => console.log(reason));
        console.log(selfReject);

异步编程的实现 —— Promise_第10张图片

Promise.all()

把多个Promise实例包装成一个新的Promise对象,接收多个Promise实例对象。返回对应的状态处理结果。

    const p = Promise.all([p1,p2,p3)
    
    p的状态由p1、p2、p3决定,分成两种情况。
    (1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,
        此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
    (2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,
        此时第一个被reject的实例的返回值,会传递给p的回调函数。

补充一点:若参数实例有自己的catch捕获错误,最终那个实例catch之后的对象是一个新的Promise对象,默认会走成功,
所以,最后带有自己的catch的实例返回状态是resolved

分别测试下这几种情况:
所以Promise实例对象全部返回resolved

        const p1 = new Promise((resolve, reject) => {
            resolve("p1成功");
        });

        const p2 = new Promise((resolve, reject) => {
            resolve("p2成功"); //1
        });

        const p3 = new Promise((resolve, reject) => {
            resolve("p3成功"); //1
        });
        const p = Promise.all([p1, p2, p3])
            .then(result => {
                console.log(result);
            })
            .catch(error => {
                console.log(new Error(error));
            })

三个Promise实例都是resolve,所以p结果的状态也是resolve,同时返回参数的返回值。
异步编程的实现 —— Promise_第11张图片
至少有一个Promise对象返回rejected

        const p1 = new Promise((resolve, reject) => {
            reject("p1失败"); // 2
        });

        const p2 = new Promise((resolve, reject) => {
            // resolve("p2成功"); //1
            reject("p2失败") // 2
            // throw new Error("p2失败"); // 2
        });

        const p3 = new Promise((resolve, reject) => {
            resolve("p3成功"); //1
        });
        const p = Promise.all([p1, p2, p3])
            .then(result => {
                console.log(result);
            })
            .catch(error => {
                console.log(new Error(error));
            })

其中有两个Promise实例的状态有pending变为rejected,则p就为rejected,同时这个实例的返回值返回给p的回调函数。
异步编程的实现 —— Promise_第12张图片
Promise实例对象中有的存在自己的catch方法

        const p1 = new Promise((resolve, reject) => {
            resolve("p1成功"); // 1
        });

        const p2 = new Promise((resolve, reject) => {
                reject("p2失败") // 2
                // throw new Error("p2失败"); // 2
            })
            .then(result => result)
            .catch(error => error);

        const p3 = new Promise((resolve, reject) => {
            resolve("p3成功"); //1
        });
        const p = Promise.all([p1, p2, p3])
            .then(result => {
                console.log(result);
            })
            .catch(error => {
                console.log(new Error(error));
            })

这里要注意,p2有自己的catch方法捕获rejected,所以p接收的p2这个Promise实例,是p2调用catch方法之后返回的一个新的Promise实例对象,该实例对象默认为resolved,所以会走then方法的第一回调函数,故p最终也能接收到由三个resolved的返回值组成的数组。
异步编程的实现 —— Promise_第13张图片

Promise.allSettled()

方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只有等到所有这些参数实例都返回结果,不管是fulfilled还是rejected,包装实例才会结束。

方法最终的返回值是数组,每个成员对应一个传入Promise.allSettled()的 Promise 实例。每个对象都有status属性,该属性的值只可能是字符串fulfilled或字符串rejected。fulfilled时,对象有value属性,rejected时有reason属性,对应两种状态的返回值。

此方法能够保证传入的所有Promise操作结束.
因为这个方法会保证参数Promise实例对象全部完成后,不管是resolved还是rejected,方法才会返回,并且是fulfilled。

        const p1 = new Promise((resolve, reject) => {
            resolve("p1成功");
        });

        const p2 = new Promise((resolve, reject) => {
            // resolve("p2成功"); //1
            reject("p2 fail")
        });

        const p3 = new Promise((resolve, reject) => {
            resolve("p3成功"); //1
        });
        const p = Promise.allSettled([p1, p2, p3]);
        p.then(results => {
            console.log(results);
        });

记录每个对象的状态,以及对应状态的消息。
异步编程的实现 —— Promise_第14张图片

异步加载图片

封装异步加载图片的函数。

        function loadImageAscy(src) {
            return new Promise(function (resolve, reject) {
                const img = new Image();
                img.onload = function () {
                    resolve("加载成功");
                }
                img.onerror = function () {
                    reject(new Error("Couled not load images ar " + src));
                }
                img.src = src;
                document.body.appendChild(img);
            })
        };

        loadImageAscy("./bianhua.JPG").then(resolve => {
            console.log(resolve);
        });

emmmm,看了文档,看了视频,练习了这些方法。着实是有点多啊,还有的方法我没有写出来,我就挑出来感觉比较常用的几个。
加油!!!

你可能感兴趣的:(Web—第二阶段)