Promise

作者: 猴子精h | 来源:发表于2018-08-23 18:54 被阅读16次

    前言

    古人云:“君子一诺千金”,这种“承诺将来会执行”的对象在 JavaScript 中称为 Promise 对象。

    Promise 最大的好处就是将异步操作从主逻辑中移除,异步回调处理放在 .then() or .catch() 中。

    Promise.png

    来看下一个经典的异步操作 AJAX:

    request.onreadystatechage = function () {
        if (request.readyState === 4) {
            // 执行成功回调
            return success(request.responseText);
        } else {
            // 执行失败回调
            return fail(request.status);
        }
    }
    

    上面把回调函数 success(request.responseText)fail(request.status) 写到一个 AJAX 里很正常,但是不好看,而且不利于代码复用。如果换成下面的写法呢:

    var ajax = ajaxGet('xxx');
    ajax.ifSuccess(success)
        .ifFail(fail);
    

    这种链式的写法好处在于,先统一执行 AJAX 逻辑,不关心如何处理结果。然后根据结果是成功还是失败,在将来的某个时刻调用 successfaild。Promise 就是来解决这个问题的,请往下看!

    Promise

    Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise 对象。

    Promise 对象代表一个异步操作,有三种状态:pending(进行中), fulfilled(已成功), rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
    状态变换只有这两种情况:

    1. pending -> fulfilled
    2. pending -> rejected

    Promise 对象是一个构造函数,通过 new 关键字初始化得到新的 Promise 对象

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

    Promise 实例生成以后,可以用 then 方法分别指定 resolved 状态和 catch 指定 rejected 状态的回调函数。这两个参数都接受 Promise 对象传出的值作为参数。

    promise.then((result) => {
        // success
    }).catch((err) => {
        // faild
    })
    

    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 最后输出。

    注意,调用 resolvereject 并不会终结 Promise 的参数函数的执行。

    new Promise((resolve, reject) => {
        reslove(1);
        console.log(2);
    }).then(r => {
        console.log(r);
    });
    
    // 2
    // 1
    

    最好在它们前面加上 return 语句,这样就不会有意外。

    new Promise((resolve, reject) => {
      return resolve(1);
      // 后面的语句不会执行
      console.log(2);
    })
    

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

    const getJSON = function(url) {
      const promise = 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();
    
      });
    
      return promise;
    };
    
    getJSON("/posts.json").then(function(json) {
      console.log('Contents: ' + json);
    }, function(error) {
      console.error('出错了', error);
    });
    

    Promise.all

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

    这个 api 在开发中也比较实用,如果 C 行为依赖于 A、B 行为,A、B 之间又没有依赖关系,而且只有当 A、B 的状态都为 fulfilled,或者有一个变为 rejected 时才会开始 C 行为。这时用 Promise.all() 就显得比较合适。

    var p1 = new Promise((reslove, reject) => {
        setTimeout(reslove, 5000, 'PI');
    })
    
    var p2 = new Promise((reslove, reject) => {
        setTimeout(reslove, 600, 'P2');
    })
    
    
    Promise.all([p1, p2]).then(([p1, p2]) => {
        console.log(p1);
        console.log(p2);
        
    })
    

    Promise.race

    Promise.race 方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。

    用法和 Promise.all 一样,C 依赖于 A、B,但只要 A,B 的任一状态改变了,C 便开始执行。

    var p1 = new Promise((reslove, reject) => {
        setTimeout(reslove, 5000, 'PI');
    })
    
    var p2 = new Promise((reslove, reject) => {
        setTimeout(reslove, 600, 'P2');
    })
    
    
    Promise.race([p1, p2]).then((result) => {
        console.log(result);
    })
    

    参考

    相关文章

      网友评论

          本文标题:Promise

          本文链接:https://www.haomeiwen.com/subject/hoimiftx.html