zoukankan      html  css  js  c++  java
  • Promise

    描述:

    Promise,就是一个对象,简单说就是一个容器,用来传递异步操作的消息。它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个事件提供统一的 API,可供进一步处理。

    promise代表一个异步操作的执行返回状态,这个执行返回状态在promise对象创建时未必已知。它允许你为异步操作的成功或失败指定处理方法。

    这使得异步方法可以像同步方法那样返回值:异步方法会返回一个包含了原返回状态的 promise 对象来替代原返回状态。

    特点: 

    Promise 对象有以下两个特点。 

    (1)对象的状态不受外界影响。Promise 对象代表一个异步操作,有三种状态:

    Pending(进行中)、

    Resolved(已完成,又称 Fulfilled)

    Rejected(已失败)。

    只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。

    pending状态的promise对象既可转换为带着一个成功值的fulfilled 状态,也可变为带着一个失败信息的 rejected 状态。当状态发生转换时,promise.then绑定的方法(函数句柄)就会被调用。(当绑定方法时,如果 promise对象已经处于 fulfilled 或 rejected 状态,那么相应的方法将会被立刻调用, 所以在异步操作的完成情况和它的绑定方法之间不存在竞争条件。)

    因为Promise.prototype.then和 Promise.prototype.catch方法返回 promises对象, 所以它们可以被链式调用—— 一种被称为 composition 的操作。

    (2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected。只要这两种情况发生,就不会再变了。就算改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

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

    Promise的适用场景:

    Promise可以用来避免异步操作函数里的嵌套回调(callback hell)问题,因为解决异步最直接的方法是回调嵌套,将后一个的操作放在前一个操作的异步回调里,但如果操作多了,就会有很多层的嵌套。

    Promise并非适用于所有的异步场景,例如事件的绑定,某个程度上Promise有点类似事件的监听回调,当触发某个操作时进行后面特定的逻辑。但Promise只能执行一次,且需要前面特定的操作执行完成才会进行下一步,一般分成功和失败两种场景,成功或失败后会立即执行响应函数。

    promise很适合判断一个比较耗时的操作是否最终执行成功的场景,如我们通常理解的ajax网络请求、读取localstorage等操作。

    不同的Promise差异基本表现如下:

    • 构造Promise对象 new Promise().resolve() 或者newPomise(function(resolve, reject) {})

    • 是否有 .done().fail().always() 等方法

    • 是否有Promise.all()方法

    • 是否有isRejected()isResolved()

    • .then() return 结果链式的

     

    基本语法:

    属性

       Promise.length    长度属性,其值为 1 (构造器参数的数目).

       Promise.prototype   表示 Promise 构造器的原型

    方法

       Promise.all(iterable)   返回一个promise对象,当iterable参数里所有的promise都被解决后,该promise也会被解决。

       Promise.race(iterable)  当iterable参数里的任意一个子promise被成功或失败后,父promise马上也会用子promise的成功返回值或失败详情作为参数调用父promise绑定的相应句柄,并返回该promise对象。

       Promise.reject(reason)   调用Promise的rejected句柄,并返回这个Promise对象。

       Promise.resolve(value)   用成功值value解决一个Promise对象。如果该value为可继续的(thenable,即带有then方法),返回的Promise对象会“跟随”这个value,采用这个value的最终状态;否则的话返回值会用这个value满足(fullfil)返回的Promise对象。

    Promise原型

    属性

       Promise.prototype.constructor  返回创建了实例原型的函数.  默认为 Promise 函数.

    方法

       Promise.prototype.catch(onRejected)  添加一个否定(rejection) 回调到当前 promise, 返回一个新的promise。如果这个回调被调用,新 promise 将以它的返回值来resolve,否则如果当前promise 进入fulfilled状态,则以当前promise的肯定结果作为新promise的肯定结果.

       Promise.prototype.then(onFulfilled, onRejected)  添加肯定和否定回调到当前 promise, 返回一个新的 promise, 将以回调的返回值 来resolve.

    示例:

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

    下面代码创造了一个Promise实例。

    var promise = new Promise(function(resolve, reject) {
      // ... some code
    
      if (/* 异步操作成功 */){
        resolve(value);
      } else {
        reject(error);
      }
    });

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

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

    Promise实例生成以后,可以用then方法分别指定Resolved状态和Reject状态的回调函数。

    promise.then(function(value) {
      // success
    }, function(value) {
      // failure
    });

    then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为Resolved时调用,第二个回调函数是Promise对象的状态变为Reject时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。

    下面是一个Promise对象的简单例子。

    function timeout(ms) {
      return new Promise((resolve, reject) => {
        setTimeout(resolve, ms, 'done');
      });
    }
    
    timeout(100).then((value) => {
      console.log(value);
    });

    上面代码中,timeout方法返回一个Promise实例,表示一段时间以后才会发生的结果。过了指定的时间(ms参数)以后,Promise实例的状态变为Resolved,就会触发then方法绑定的回调函数。

    Promise新建后就会立即执行。

    let promise = new Promise(function(resolve, reject) {
      console.log('Promise');
      resolve();
    });
    
    promise.then(function() {
      console.log('Resolved.');
    });
    
    console.log('Hi!');
    
    // Promise
    // Hi!
    // Resolved

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

    异步加载图片

    function loadImageAsync(url) {
      return new Promise(function(resolve, reject) {
        var image = new Image();
    
        image.onload = function() {
          resolve(image);
        };
    
        image.onerror = function() {
          reject(new Error('Could not load image at ' + url));
        };
    
        image.src = url;
      });
    }

    下面是一个用Promise对象实现的Ajax操作的例子。

    var getJSON = function(url) {
      var promise = new Promise(function(resolve, reject){
        var client = new XMLHttpRequest();
        client.open("GET", url);
        client.onreadystatechange = handler;
        client.responseType = "json";
        client.setRequestHeader("Accept", "application/json");
        client.send();
    
        function handler() {
          if ( this.readyState !== 4 ) {
            return;
          }
          if (this.status === 200) {
            resolve(this.response);
          } else {
            reject(new Error(this.statusText));
          }
        };
      });
    
      return promise;
    };
    
    getJSON("/posts.json").then(function(json) {
      console.log('Contents: ' + json);
    }, function(error) {
      console.error('出错了', error);
    });

    上面代码中,getJSON是对XMLHttpRequest对象的封装,用于发出一个针对JSON数据的HTTP请求,并且返回一个Promise对象。需要注意的是,在getJSON内部,resolve函数和reject函数调用时,都带有参数。

    如果调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数。reject函数的参数通常是Error对象的实例,表示抛出的错误;resolve函数的参数除了正常的值以外,还可能是另一个Promise实例,表示异步操作的结果有可能是一个值,也有可能是另一个异步操作,比如像下面这样。

    var p1 = new Promise(function(resolve, reject){
      // ...
    });
    
    var p2 = new Promise(function(resolve, reject){
      // ...
      resolve(p1);
    })

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

    注意,这时p1的状态就会传递给p2,也就是说,p1的状态决定了p2的状态。如果p1的状态是Pending,那么p2的回调函数就会等待p1的状态改变;如果p1的状态已经是Resolved或者Rejected,那么p2的回调函数将会立刻执行。

    var p1 = new Promise(function (resolve, reject) {
      setTimeout(() => reject(new Error('fail')), 3000)
    })
    var p2 = new Promise(function (resolve, reject) {
      setTimeout(() => resolve(p1), 1000)
    })
    p2.then(result => console.log(result))
    p2.catch(error => console.log(error))
    // Error: fail

    上面代码中,p1是一个Promise,3秒之后变为rejectedp2的状态由p1决定,1秒之后,p2调用resolve方法,但是此时p1的状态还没有改变,因此p2的状态也不会变。又过了2秒,p1变为rejectedp2也跟着变为rejected

    下面这个例子展示了Promise的机制。每当<button>被按下时,testPromise() 函数就会被执行。该函数会创建一个用window.setTimeout在1到3秒(随机)后用‘result’字符串解决的promise。

    这里通过p1.then方法的满足回调,简单的输出了promise的满足过程,这些输出显示了该方法的同步部分是如何和promise的异步解决解耦的

    这个例子在按钮被按下后执行。你需要一个支持Promise的浏览器。你能通过短时间内按多次按钮看到不同的promise一个接一个的被满足。

    <div id="log"></div>
    <script>
        'use strict';
        var promiseCount = 0;
        function testPromise() {
            var thisPromiseCount = ++promiseCount;
    
            var log = document.getElementById('log');
            log.insertAdjacentHTML('beforeend', thisPromiseCount + ') 开始(同步代码开始)<br/>');
    
            // 我们创建一个新的promise: 然后用'result'字符串解决这个promise (3秒后)
            var p1 = new Promise(function (resolve, reject) {
                // 解决函数带着解决(resolve)或拒绝(reject)promise的能力被执行
                log.insertAdjacentHTML('beforeend', thisPromiseCount + ') Promise开始(异步代码开始)<br/>');
    
                // 这只是个创建异步解决的示例
                window.setTimeout(function () {
                    // 我们满足(fullfil)了这个promise!
                    resolve(thisPromiseCount)
                }, Math.random() * 2000 + 1000);
            });
    
            // 定义当promise被满足时应做什么
            p1.then(function (val) {
                // 输出一段信息和一个值
                log.insertAdjacentHTML('beforeend', val + ') Promise被满足了(异步代码结束)<br/>');
            });
    
            log.insertAdjacentHTML('beforeend', thisPromiseCount + ') 建立了Promise(同步代码结束)<br/><br/>');
        }
        testPromise();
        testPromise();
        testPromise();
    </script>

      

    总结:

    实现异步的方法目前有,自定义嵌套,Promise、generator、Defferd,还有ES7的async(generator的封装),不同场景可以选择不同的方式去实现


    参考链接:

    https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise

    http://ouvens.github.io/frontend-javascript/2016/03/04/promise-and-asyncjs.html

    http://es6.ruanyifeng.com/#docs/promise

    http://bluebirdjs.com/docs/api-reference.html

     https://github.com/ouvens/promise   简单的Promise实现样例

    https://github.com/tj/co    generator异步实现

  • 相关阅读:
    vue打包编译报错,These dependencies were not found:core-js/modules/es
    JS 新语法「可选链」「双问号」已进入 Stage 3
    vue 本地和线上跨域的问题 个人解决方案
    vue-router懒加载或者按需加载
    brew 切换国内的源
    vue 数组、对象 深度拷贝和赋值
    全局axios默认值 和 自定义实例默认值
    npm install 报node-sass错误
    linux端口探测
    linux批量操作(一)
  • 原文地址:https://www.cnblogs.com/doufu/p/promise.html
Copyright © 2011-2022 走看看