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