• Promise 对象


      • Promise 的含义

        • Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。
        • 所谓promise ,简单来说就是一个容器,里面保存着未来才会结束的事件(通常是一个异步的操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。
        • Promise 对象 有两个特点:
          1. 对象的状态不受外界影响。Promise 对象代表着一个异步操作,有三种状态:pending(等待态)、fulfilled(已完成、rejected(以失败)。只有异步操作结果可以决定是哪一种状态。任何其他操作都无法改变这个状态,这也是promise (承诺)的由来。
          2. promise 的状态一旦改变就不会再变,任何时候都可以得到这个结果。promise 的状态的改变,只有两种情况:①从pending => fulfilled 或 ②从pending => rejected。
        • 有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。
        • Promise也有一些缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
      • 基本用法

        • ES6 规定,Promise对象是一个构造函数,用来生成Promise实例。
        • 下面代码创造了一个Promise实例。
          • const promsime = new Prosime(function(resolve, reject){
              // todo ... 做一些事情
              if (/* 如果异步操作成功 */){
                resolve(data);
              } else {
                reject(error);
              }
            });
        • Promise构造函数接受一个函数 executor,这个函数接受两个参数 一个 resolve 和 reject。这两个参数由javaScript提供,不用自己部署。
        • Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
          • promsime.then(data => { // resolved
              // sunccess
            }, err => { // rejected
              // failure
            })
        • then 方法接受两个回调函数作为参数, 一个是成功的时候回调, 一个是失败的时候回调. 第二个参数是可选的.
        • eg:一个promise的简单例子
          • function timeout(ms) {
              return new Promise((resolve, reject) => {
                setTimeout(resolve, ms, 'done');
              });
            }

            timeout(100).then((value) => {
              console.log(value);
            });
        • promise 新建后会立即执行
          • let promise = new Promise((resolve, reject) => {
                console.log('Promise');
                resolve();
            });
            
            promise.then(function() {
                console.log('resolved.');
            });
            
            console.log('Hi!');

            // Promise
            // Hi!
            // resolved
        • 下面是异步加载图片的例子。
          • function loadImageAsync(url) {
              return new Promise(function(resolve, reject) {
                const image = new Image();
            
                image.onload = function() {
                  resolve(image);
                };
            
                image.onerror = function() {
                  reject(new Error('Could not load image at ' + url));
                };
            
                image.src = url;
              });
            }

            上面代码中,使用Promise包装了一个图片加载的异步操作。如果加载成功,就调用resolve方法,否则就调用reject方法。

        • 下面是一个用Promise对象实现的 Ajax 操作的例子。
          • const getJson = (url) => {
                return new Promise(function(resolve, reject) {
                    const handler = function() {
                        if (this.readyState !== 4) {
                            return;
                        }
                        if (this.status === 200) {
                            resolve(this.response);
                        } else {
                            reject(new Error(this.statusText));
                        }
                    };
                    const client = new XMLHttpRequest();
                    client.open('get', url);
                    client.onreadystatechange = handler;
                    client.responseType = 'json';
                    client.setRequestHeader("Accept", "application/json");
                    client.send();
                })
            }
            getJson("./posts.json").then((json) => {
                console.log('json :', json)
            }, err => {
                console.log('err :', err);
            })
        • 上面的代码中,getJson 是对XMLHttpRequest做了一个封装,用于发出一个针对 JSON 数据的 HTTP 请求,并且返回了一个promise对象.需要注意的是在resolve 函数 和  reject 函数调用时都带有参.

        • 如果调用 resolve 和 reject 函数时带有参数,那么他们的参数会被传递到回调函数.reject 函数的参数一般是Error对象的实例,表示抛出的错误.resolve 函数的参数除了传递正常的值之外,还可能是一个Promise对象,像下面的例子:
          • const p1 = new Promise((resolve, reject) => {
                // todo
            });
            
            const p2 = new Promise((resolve, reject) => {
                resolve(p1);
            });

            上面代码中,p1p2都是 Promise 的实例,但是p2resolve方法将p1作为参数,即一个异步操作的结果是返回另一个异步操作。

        • 这里需要注意的是  p1 和p2 都是Promise 的实例, 这时候 p1作为p2  resolve 的参数,就是说 p1 的状态决定 p2 的状态.如果p1 的结果是 pending , 那么p2 就会等待p1 的状态改变而改变,若p1 是 resolved  或者 rejected 中任意一种,那么p2 的回调函数就会立即执行.
        • const p1 = new Promise((resolve, reject) => {
              // todo
              setTimeout(() => reject(new Error('p1抛出的错误信息')), 3000);
          });
          
          const p2 = new Promise((resolve, reject) => {
              setTimeout(() => resolve(p1), 1000);
          });
          
          p2.then((result) => {
              console.log('result :', result);
          }).catch((err) => {
              console.log('err :', err);
          });

          上述代码中,在p1中写了个定时器 3s后执行抛出异常.p2是在1s 后执行resolve 返回的是p1.由于p2返回的是一个Promise,导致自己的状态无效了 ,等待p1的状态而确定p2的状态,所以后面的then() 语句是针对p1 的.又过了两秒p1执行reject() 抛出一个错误,状态变成rejected,导致出发catch方法指定的回调函数.

        • 注意 调用resolve 和 reject 并不会终结Promise的参数函数的执行.
          • new Promise((resolve, reject) => {
              resolve(1);
              console.log(2);
            }).then(r => {
              console.log(r);
            });
            
            // 2
            // 1
        • 上述代码中,执行resolve(1) 后 console.log(2) 还是回执行,并且先打印出来.因为promise 里面的resolve 是在本轮事件循环尾执行,总是晚于本轮循环的同步任务.
        • 一般来说调用 resolve 或者 reject 后 Promise 的使命就完成了,后续的操作我们应该放在then()方法里面,而不应该写在resolve / reject 后面.所以最好在他们前面添加 return 语句,这样既不会有意外了
          • new Promise((resolve, reject) => {
              return resolve(1);
              // 后面的语句不会执行
              console.log(2);
            })
    • Promise.prototype.then()

      • Promise 实例具有then方法,也就是说,then方法是定义在原型对象Promise.prototype上的.他的作用是为了Promise实例添加状态改变时的回调函数.
      • then 方法返回的是一个新的Promise 实例(注意: 不是原来的Promise). 因为可以采取链式写法,即then方法后面在调用另一个then 方法.
        •   eg:
          getJSON("/posts.json")
          .then(function(json) { return '123'; })
          .then(
          function(post) { console.log(post); }); // 123
      • 上述代码中 若是 return 的是一个异步操作,则第二个then 会等待return 的异步的返回的结果.给个栗子:
        • getJSON("/post/1.json").then(function(post) {
            return getJSON(post.commentURL);
          }).then(function funcA(comments) {
            console.log("resolved: ", comments);
          }, function funcB(err){
            console.log("rejected: ", err);
          });

           

    • Promise.prototype.catch()

      • Promise.prototype.catch() 是 .then(null,rejection)的别名,用于指定发生错误时候的回调函数.

      • getJSON('/posts.json').then(function(posts) {
          // ...
        }).catch(function(error) {
          // 处理 getJSON 和 前一个回调函数运行时发生的错误
          console.log('发生错误!', error);
        });
      • 上述代码中,getJSON方法返回一个 Promise 对象,如果该对象状态为resolved,则调用then方法指定的函数,如果异步操作操作抛出错误,状态为sejected,则会调用catch方法指定的回调函数,处理这个错误。另外,then 方法指定的函数中假若抛出错误也会被catch函数扑捉。

      • eg:
        const promise = new Promise(function(resolve, reject) {
          throw new Error('test');
        });
        promise.catch(function(error) {
          console.log(error);
        });
        // Error: test

        等价于另外两种写法

        // 写法一
        const promise = new Promise(function(resolve, reject) {
          try {
            throw new Error('test');
          } catch(e) {
            reject(e);
          }
        });
        promise.catch(function(error) {
          console.log(error);
        });
        
        // 写法二
        const promise = new Promise(function(resolve, reject) {
          reject(new Error('test'));
        });
        promise.catch(function(error) {
          console.log(error);
        });
      • 如果 Promise 状态已经变成resolved,再抛出错误是无效的。因为Promise 的状态一旦确定了是无法改变的。
      • Promise 对象的错误具有"冒泡"性质,也就是说会一层一层往外传,错误总会被下一个catch所扑捉。eg:
        getJson('./file1.json')
          .then((data) => {
            getJson(data.fileUrl);
          })
          .then((data) => {
            // todu
          })
          .catch((err) => {
            console.log('err :', err);
          });

        上述代码中 一共有三个 Promise , 一个是getJson 产生的 两个是 then 产生的 它们三个中任意一个抛出的错误异常都会被catch扑捉。

      • 之前在then方法里写 两个函数,一个是resolve的回调函数,另一个是 reject 的回调函数。但是通常我们不建议这样写,不在then方法里面写 reject 的回调,我们一般是用catch 方法来捕获错误信息。这样写可以then 方法里面执行的报错。这样写也更接近同步的写法(try/catch)。跟传统的 try/catch 不同的是,Promise 如果没有catch指定处理错误信息的回调函数,promise 抛出的错误是不会传递到外层代码,即不会有任何反应。
    • 应用

    冒泡

  • 相关阅读:
    在Postman用post方式请求webapi
    C#控制台为输出内容设置背景色和字体颜色
    不卡界面,实现文件上传
    编译后的dll,xml,pdb分别是什么内容,各有什么用处?
    C#的dynamic解析xml
    Oracle中的正则表达式
    oracle中 connect by 递归查询用法
    oracle中 listagg() WITHIN GROUP () 行转列函数的使用
    oracle中dualde使用
    MYSQL基本命令
  • 原文地址:https://www.cnblogs.com/xzqyun/p/10053478.html
Copyright © 2020-2023  润新知