• ES5-ES6-ES7_Promise对象详解


    Promise对象概述(什么是Promise)

    Promise 是异步编程的一种解决方案,比传统的异步解决方案——回调函数和事件——更合理和更强大

    所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。

    Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理

    有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易

    Promise 对象的特点

    对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和Rejected(已失败)

    只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是承诺,表示其他手段无法改变。

    一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从Pending变为Resolved和从Pending变为Rejected

    只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。

    如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

    Promise对象的缺点

    无法取消Promise,一旦新建它就会立即执行,无法中途取消。

    如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。

    当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

    如果某些事件不断地反复发生,一般来说,使用 Stream 模式是比部署Promise更好的选择。

    Promise 对象的基本使用

    ES6 规定,Promise对象是一个构造函数来生成Promise实例

    Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolvereject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署

    Promise 新建后就会立即执行里面的代码,不需要调用,所以首先输出的是Promise。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以Resolved最后输出

    Promise的运行机制查看:js的运行机制这篇文章中的关于Promise运行机制

    let promise = new Promise(function (resolve,reject) {
      console.log("Promise");
      resolve();   //表示让Promise这个对象的状态从Pending变为Resolved
    });
    
    promise.then(function () {
      console.log("执行完成")
    });
    
    console.log("HI")

    最后的执行结果是Promise—HI—执行完成

    Promise的resolve函数和reject函数

    resolve函数的作用是,将Promise对象的状态从未完成变为成功(即从 Pending 变为 Resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去

        const imgs = [
            './1.jpg',
            './2.jpg',
            './3.jpg'
        ]
        let promise = new Promise(function (resolve, reject) {
            const img = new Image();
            img.src = '';
            img.onload = function () {
                resolve(this);   //将异步操作的结果,作为参数传递出去
            };
        });

    reject函数的作用是,将Promise对象的状态从未完成变为失败(即从 Pending 变为 Rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去

        const imgs = [
            './1.jpg',
            './2.jpg',
            './3.jpg'
        ]
        let promise = new Promise(function (resolve, reject) {
            const img = new Image();
            img.src = '';
            img.onload = function () {
                resolve(this);   //将异步操作的结果,作为参数传递出去
            };
            img.onerror = function () {
                reject(new Error('图片加载失败'));//将异步操作报出的错误,作为参数传递出去
            }
        });

    Promise对象的两个原型方法then()和catch()

    Promise.prototype.then(),Promise 实例具有then方法,就是说,then方法是定义在原型对象Promise.prototype上的它的作用是为 Promise 实例添加状态改变时的回调函数。

    then方法的第一个参数是Resolved状态的回调函数,第二个参数(可选)是Rejected状态的回调函数(一般不用这个参数,使用catch()方法来获取错误的信息)

        const imgs = [
            './1.jpg',
            './2.jpg',
            './3.jpg'
        ]
        let promise = new Promise(function (resolve, reject) {
            const img = new Image();
            img.src = imgs[0];   //将它改为'',也就是图片加载失败的时候,会触发then的第二个参数,获取错误信息
            img.onload = function () {
                resolve(this);   //将异步操作的结果,作为参数传递出去
            };
            img.onerror = function () {
                reject(new Error('图片加载失败'));//将异步操作报出的错误,作为参数传递出去
            }
        });
    
        promise.then(function (img) {
            console.log("图片加载完成");
            document.body.appendChild(img)
        },function (err) {
            console.log(err)
        })

    then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法(但是这个方法里面的代码不管异步执行成功还是失败,都会执行)

        const imgs = [
            './1.jpg',
            './2.jpg',
            './3.jpg'
        ]
        let promise = new Promise(function (resolve, reject) {
            const img = new Image();
            img.src = imgs[0];   //将它改为'',图片不存在的情况下,也就是图片加载失败的时候,会触发then的第二个参数,获取错误信息
            img.onload = function () {
                resolve(this);   //将异步操作的结果,作为参数传递出去
            };
            img.onerror = function () {
                reject(new Error('图片加载失败'));//将异步操作报出的错误,作为参数传递出去
            }
        });
    
        promise.then(function (img) {
            console.log("图片加载完成1");
            document.body.appendChild(img);
        },function (err) {
            console.log(err)
        }).then(function (img) {
            console.log("图片加载完成2");
            console.log(img)// undefined   ,因为不是原来那个Promise实例了,所以获取不到这个img对象,不管是resolve还是reject这里都会执行
        })

    原型方法catch(),Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。

        const imgs = [
            './1.jpg',
            './2.jpg',
            './3.jpg'
        ]
        let promise = new Promise(function (resolve, reject) {
            const img = new Image();
            img.src = '';   //将它改为'',也就是图片加载失败的时候,会触发then的第二个参数,获取错误信息
            img.onload = function () {
                resolve(this);   //将异步操作的结果,作为参数传递出去
            };
            img.onerror = function () {
                reject(new Error('图片加载失败'));//将异步操作报出的错误,作为参数传递出去
            }
        });
    
        promise.then(function (img) {
            console.log("图片加载完成1");
            document.body.appendChild(img);
        }).catch(function (err) {
            console.log(err);//Error: 图片加载失败
        });

    promise过程分析

    异步加载图片的例子

    这个例子就是以上代码中的一个例子,这里是做一个封装,将这个例子封装成一个函数

    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body></body></html>
    <script>
        const imgs = [
            './1.jpg',
            './2.jpg',
            './3.jpg'
        ]
    
        function loadImageAsync(url) {
            var p = new Promise(function (resolve, reject) {
                const img = new Image();
                img.src = url;
                img.onload = function () {
                    resolve(this);
                };
                img.onerror = function () {
                    reject(new Error('图片加载失败'));  //将异步操作的结果,作为参数传递出去
                };
            });
            return p
        }
    
        console.log(123);
    
        const allDone = Promise.all([loadImageAsync(imgs[0]),loadImageAsync(imgs[1]),loadImageAsync(imgs[2])]);
        allDone.then(function (datas) {
            console.log("图片加载完成")
            console.log(datas);  //这个datas存放的是每个loadImageAsync方法传进来的参数的的一个集合
    
            //遍历这个集合,并且放入页面的body标签内
            datas.forEach(function (item,i) {
                document.body.appendChild(item);
            })
        }).catch(function (err) {
            console.log(err)
        });
        console.log(456)
    
    </script>

    Promise对象的静态方法Promise.all()

    Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例

    Promise.all方法接受一个数组作为参数,并且数组里的元素都是 Promise 实例,如果不是,就会先调用Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。(Promise.all方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。)

    let p = Promise.all([p1,p2,p3])

    p的状态由p1、p2、p3决定,分成两种情况。

    只有p1、p2、p3的状态都变成Resolved,p的状态才会变成Resolved,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。(异步加载多张图片的示例)

    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body></body></html>
    <script>
        const imgs = [
            './1.jpg',
            './2.jpg',
            './3.jpg'
        ]
    
        function loadImageAsync(url) {
            var p = new Promise(function (resolve, reject) {
                const img = new Image();
                img.src = url;
                img.onload = function () {
                    resolve(this);
                };
                img.onerror = function () {
                    reject(new Error('图片加载失败'));  //将异步操作的结果,作为参数传递出去
                };
            });
            return p
        }
    
        console.log(123);
    
        const allDone = Promise.all([loadImageAsync(imgs[0]),loadImageAsync(imgs[1]),loadImageAsync(imgs[2])]);
        allDone.then(function (datas) {
            console.log("图片加载完成")
            console.log(datas);  //这个datas存放的是每个loadImageAsync方法传进来的参数的的一个集合
    
            //遍历这个集合,并且放入页面的body标签内
            datas.forEach(function (item,i) {
                document.body.appendChild(item);
            })
        }).catch(function (err) {
            console.log(err)
        });
        console.log(456)
    
    </script>

    只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。(异步加载多张图片的示例,第二张图片加载失败)

    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body></body></html>
    <script>
        const imgs = [
            './1.jpg',
            './2.jpg',
            './3.jpg'
        ]
    
        function loadImageAsync(url) {
            var p = new Promise(function (resolve, reject) {
                const img = new Image();
                img.src = url;
                img.onload = function () {
                    resolve(this);
                };
                img.onerror = function () {
                    reject(new Error('图片加载失败'));  //将异步操作的结果,作为参数传递出去
                };
            });
            return p
        }
    
        console.log(123);
    
        const allDone = Promise.all([loadImageAsync(imgs[0]),loadImageAsync(''),loadImageAsync(imgs[2])]);
        allDone.then(function (datas) {
            console.log("图片加载完成")
            console.log(datas);  //这个datas存放的是每个loadImageAsync方法传进来的参数的的一个集合
    
            //遍历这个集合,并且放入页面的body标签内
            datas.forEach(function (item,i) {
                document.body.appendChild(item);
            })
        }).catch(function (err) {
            console.log(err)
        });
        console.log(456)
    
    </script>

    Promise对象的静态方法Promise.resolve()

    主要用来将现有对象转为Promise对象,参数是Promise对象的话,将不做任何修改,原封不动的返回这个对象

    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body></body></html>
    <script>
        const imgs = [
            './1.jpg',
            './2.jpg',
            './3.jpg'
        ]
        function loadImageAsync(url) {
            var p = new Promise(function (resolve, reject) {
                const img = new Image();
                img.src = url;
                img.onload = function () {
                    resolve(this);
                };
                img.onerror = function () {
                    reject(new Error('图片加载失败'));  //将异步操作的结果,作为参数传递出去
                };
            });
            return p
        }
        Promise.resolve(loadImageAsync(imgs[0])).then(function (img) {
            document.body.appendChild(img)
        })
    </script>

    参数是一个thenable对象,thenable对象指的是具有then方法的对象,Promise.resolve方法会将这个对象转为Promise对象,然后就立即执行thenable对象的then方法

    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body></body></html>
    <script>
        const imgs = [
            './1.jpg',
            './2.jpg',
            './3.jpg'
        ]
        Promise.resolve({
            then(resolve, reject){
                const img = new Image();
                img.src = imgs[0]; // 正常情况下,图片存在,不正常情况下,图片不存在
                img.onload = function () {
                    resolve(this)
                };
                img.onerror = function () {
                    reject(new Error('图片加载失败'));  //将异步操作的结果,作为参数传递出去
                };
            }
        }).then(function (img) {
            document.body.appendChild(img);
        }).catch(function (err) {
            console.log(err)
        })
    </script>

    如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的Promise对象,状态为Resolved

      const p = Promise.resolve('Hello');
    
        p.then(function (s){
            console.log(s)  // Hello
        });

    由于字符串Hello不属于异步操作(判断方法是字符串对象不具有then方法),返回Promise实例的状态从一生成就是Resolved,所以回调函数会立即执行。Promise.resolve方法的参数,会同时传给回调函数。

    Promise.resolve方法允许调用时不带参数,直接返回一个Resolved状态的Promise对象。所以,如果希望得到一个Promise对象,比较方便的方法就是直接调用Promise.resolve方法

      const p = Promise.resolve();
    
        p.then(function () {
            console.log(p)
        });

    实现一个完整的 Promise

    下面我们来写一个简单的 promsie。Promise 的参数是函数 fn,把内部定义 resolve 方法作为参数传到 fn 中,调用 fn。当异步操作成功后会调用 resolve 方法,然后就会执行 then 中注册的回调函数。

     

     

     

     

  • 相关阅读:
    day1记一次无列名注入
    无参数RCE
    ThinkPHP 5.x远程命令执行漏洞
    phpmyadmin4.8.1文件包含漏洞
    foreach循环导致变量覆盖
    绕过空格的报错注入
    布尔盲注payload补充
    php后台验证两种方式绕过
    CentOS yum 配置阿里镜像
    CentOS通过yum安装配置Java环境
  • 原文地址:https://www.cnblogs.com/LO-ME/p/7398536.html
Copyright © 2020-2023  润新知