Promise

2019-12-12  本文已影响0人  骑着蜗牛追飞机_f7fa

1. Promise是什么 ?

Promise是异步编程的一种解决方案。ES6将其写进了语言标准,比回调函数和事件更强大更合理。
Promise就是一个容器,保存着未来才会结束的事件(异步操作)的结果。有以下2个特点:

优点:
缺点:

2. 基本用法

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

    const promise = new Promise(function(resolve, reject){
            if(异步操作成功){
                resolve(value)
            } else {
                reject(error)
            }
    })

Promise构造函数接收一个函数作为参数,该函数的两个参数分别是resolve和reject,它们是两个函数,由JavaScript引擎提供,不用自己部署。
resolve函数的作用是,将promise从pending变成fulfilled,并将异步操作的结果,作为参数传递出去。reject同理。
promise实例生成完成之后,可以用then方法分别指定resolved状态和rejected状态的回调函数。这两个回调函数都接受promise对象传出的值作为参数。

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对象实现的 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);
});
resolve函数的参数除了正常的值之外,还可能是另一个Promise实例。
var p1 = new Promise(function (resolve, reject) {
      setTimeout(() => reject('fail'), 3000)
})

var p2 = new Promise(function (resolve, reject) {
      setTimeout(() => resolve(p1), 1000)
})

p2.then(function(a){
  console.log(a);
},function(b){
  console.log('b')
  console.log(b);
}).catch(error => {
  console.log('error')
  console.log(error)
})

p1.then(function(a){
  console.log(a);
},function(b){
  console.log('bv')
  console.log(b);
}).catch(error => console.log(error))
// 输出结果:
// b
// TypeError: Cannot read property 'push' of undefined
//    at Function.then (public_dc35c87.js:779)
//    at public_dc35c87.js:777
//    at MutationObserver.a (public_dc35c87.js:545)
//bv
//fail

上面代码中,p1和p2都是 Promise 的实例,但是p2的resolve方法将p1作为参数,即一个异步操作的结果是返回另一个异步操作。p1是一个 Promise,3 秒之后变为rejected。p2的状态在 1 秒之后改变,resolve方法返回的是p1。由于p2返回的是另一个 Promise,导致p2自己的状态无效了,由p1的状态决定p2的状态。所以,后面的then语句都变成针对后者(p1)。又过了 2 秒,p1变为rejected,导致触发catch方法指定的回调函数。

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

注意,调用resolve或reject并不会终结 Promise 的参数函数的执行。
new Promise((resolve, reject) => {
    resolve(1);
    console.log(2);
}).then(r => {
    console.log(r);
});
// 2
// 1

所以一般,可以在resolve或reject前面加上return语句。

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

3. Promise.prototype.then()

Promise实例具有then方法,定义在原型对象伤。作用:为Promise实例添加状态改变时的回调函数。then方法第一个参数是resolved状态的回调函数,第二个参数是rejected状态的回调函数。then方法返回的是一个新的Promise实例,所以可以链式调用。前一个then方法回调函数完成后,会将返回结果作为参数,传给后一个then回调函数。采用箭头函数书写更简洁。

getJSON("/post/1.json").then(
      post => getJSON(post.commentURL)
).then(
      comments => console.log("resolved: ", comments),
      err => console.log("rejected: ", err)
);

4. Promise.prototype.catch()

Promise.prototype.catch方法是.then(null, rejection)或 .then(undefined, rejection)的别名。用于指定发生错误时的回调函数。
catch不仅会抛出promise里的错误,还会抛出then方法里执行时候的错误,还能抛出前面catch里执行的错误。 所以一般不建议then里面同时写resolve和reject的回调处理函数。而是写一个catch回调函数替代then方法里reject的回调函数。

Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。一般来说,不要在then方法里面定义 Reject 状态的回调函数(即then的第二个参数),总是使用catch方法。

// bad
promise
  .then(function(data) {
  // success
}, function(err) {
  // error
});

// good
promise
  .then(function(data) { //cb
    // success
  })
  .catch(function(err) {
    // error
});

5. Promise.prototype.finally()

finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。

promise
  .then(result => {···})
  .catch(error => {···})
  .finally(() => {···});

它的实现也很简单。

Promise.prototype.finally = function (callback) {
    let P = this.constructor;
    return this.then(
        value  => P.resolve(callback()).then(() => value),
        reason => P.resolve(callback()).then(() => { throw reason })
    ) ;
};

上面代码中,不管前面的 Promise 是fulfilled还是rejected,都会执行回调函数callback。

6. Promise.all()

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

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

上面代码中,Promise.all()方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。

6. Promise.race()

7. Promise.allSettled()

8. Promise.any()

9. Promise.resolve()

10. Promise.reject()

11. Promise.try()

12. Promise应用

上一篇 下一篇

猜你喜欢

热点阅读