Promise对象的基本使用

410 阅读7分钟

1.Promise对象的介绍以及基本使用

1.1 基本的介绍

基础:一个对象,有三种状态:

  • pending(进行中)
  • fulfilled(已执行)
  • rejected(已拒绝)

是能够异步执行(要了解JS的事件执行机制)对象。

仅此而已。

1.2 基本的使用

let p = new Promise((resolve, reject) => {
  // 做一些事情
  // 然后在某些条件下resolve,或者reject
  if (/* 条件随便写^_^ */) {
    resolve()
  } else {
    reject()
  }
})

p.then(() => {
    // 如果p的状态被resolve了,就进入这里
}, () => {
    // 如果p的状态被reject
})

2.Promise对象常用的方法和使用场景

2.1 Promise.then()

Promise对象的then方法主要用途是为promise对象的状态注册回调函数。

参数有两个,第一个是从promise对象中的resolve过来应该执行的回调函数,第二个参数是从promise对象中reject过来应该执行的回调函数,第二个参数是可选项。

then方法的返回值是什么呢?返回的还是Promise对象,没错,就是因为这样所以说Promise可以解决传说中的“地狱回调”问题。因为返回的还是一个异步的操作,如果要执行一个后续的任务,我们只能等前一个任务完成之后才有回调。

var pro = new Promise( function(resolve, reject) {
  if( 1 === 2) {
    resolve(['参数一','参数二'])
  }else {
    throw new Error('模拟发生在Promise里面的错误')
  }
}).then(
  /* .then 可以传两个函数,第一个在resolve的时候调用,第二个在reject的时候调用,两个函数的参数只有一个,
  如果有多个参数需要传递可以使用数组或对象的形式 */
  function funcResolve([arg1,arg2]) {
    console.log(arg1);
    console.log(arg2);
  },
  function funcReject(rejection) {
    console.log('then的接收Promise的reject错误函数:', rejection);
    throw new Error('模拟发生在rejection里面的错误')
  }
).catch(
  function(err) {
    console.log('发生错误:', err);
  }
)

2.2 Promise.catch()

Promise对象的.catch方法用于注册reject的回调函数,同时该回调也是程序出错的回调函数,就是说,如果前面的程序出错了也是会进入该函数执行的。和.then一样返回的一个promise对象。

catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数 什么时候调用这里面的方法:

  1. Promise里面抛出的错误
  2. 接收Error和reject的错误执行回调
  3. then里面的错误

:一般来说,不要在then方法里面定义Reject状态的回调函数(即then的第二个参数),总是使用catch方法。

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

一般来说,catch方法之中,还能再抛出错误。

2.3 Promise.all()

参数:Promise.all的 参数是接受一个数组作为参数的,数组的元素指定是多个Promise实例。

作用:.all函数的作用是最后返回一个状态(resolve或者reject),根据参数的数据传递进来的。大概的例子如下:

const promise = new Promise.all([p0,p1,p2])

在上面的举例中,传进去的数组中的p0p1p2,都应该是promise实例,如果不是的,会自动调用Promise.resolve()方法进行转换。 那这个promise什么时候才会返回一个resolve的状态呢? 只有全部的元素都返回了resolve的状态才会最终返回一个resolve给promise,其他的情况都是reject

返回值:以上情况就是p0,p1,p2都是fulfilled状态的话,promise才会状态变为fulfilled,此时p0p1p2的返回值组成一个数组,传递给promise的回调函数。

2.4 Promise.race()

参数:Promise.race的 参数是接受一个数组作为参数的,数组的元素指定是多个Promise实例。

作用:同样是将多个 Promise 实例,包装成一个新的 Promise 实例。

const promise = new Promise.all([p0,p1,p2])

上面代码中,只要p0p1p2之中有一个实例率先改变状态,promise的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

返回值:以上情况就是p0,p1,p2都是fulfilled状态的话,promise才会状态变为fulfilled,此时p0p1p2的返回值组成一个数组,传递给promise的回调函数。

2.5 Promise.resove()

参数:一个对象、Promise实例、一个thenable对象、原始值

作用:将该对象转化为resolve状态的Promise实例。

实例

var jsPromise = Promise.resolve($.ajax('/whatever.json'));

下面两种写法等价:

Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))

2.6 Promise.reject()

参数:一个对象

作用:将该对象转化为reject状态的Promise实例。

实例

var p = Promise.reject('出错了');
// 等同于
var p = new Promise((resolve, reject) => reject('出错了'))
p.then(null, function (s){
console.log(s)
});
// 出错了

上面代码生成一个Promise对象的实例p,状态为rejected,回调函数会立即执行。

3.Promise对象和async、await的区别

关于更多的async、await的基础与使用请关注:www.xyhtml5.com/5027.html

一个面试题

for (var i = 0; i < 5; i++) {
    (function(j) {  // j = i
        setTimeout(function() {
            console.log(new Date, j);
        }, 1000);
    })(i);
}
console.log(new Date, i);

输出:

image.png

现要修改输出的顺序为:0 -> 1 -> 2 -> 3 -> 4 -> 5

ES6之前

for (var i = 0; i < 5; i++) {
  (function(j) {  // j = i
  setTimeout(function() {
    console.log(new Date, j);
  }, 1000);
  })(i);
}
  
setTimeout(() => {
  console.log(new Date, i);
}, 1000);

ES6 Promise

new Promise(function(resolve) {
  for (var i = 0; i < 5; i++) {
    (function(j) {  // j = i
    setTimeout(function() {
      console.log(new Date, j);
    }, 1000);
    })(i);
  }
  resolve(i)
  }
).then(
  val => {
    setTimeout(() => {
      console.log(new Date,val);
    }, 1000);
  }
)

ES7 async await

async function test() {
  for (var i = 0; i < 5; i++) {
    await (function(j) {
    setTimeout(function() {
      console.log(new Date, j);
    }, 1000);
    })(i);
  }
  await (() => { 
    setTimeout(() => {
      console.log(new Date, i)
  }, 1000); })()
}
test()

ES7 async await + Promise

const sleep = (timeountMS) => new Promise((resolve) => {
  setTimeout(resolve, timeountMS);
});

(
  async () => {  // 声明即执行的 async 函数表达式
    for (var i = 0; i < 5; i++) {
      await sleep(1000);
      console.log(new Date, i);
    }
    await sleep(1000);
    console.log(new Date, i);
  }
)();

4.总结

上面这样构造promise实例,然后调用.then.then.then的编写代码方式,就是promise。

其基本模式是:

  • 将异步过程转化成promise对象
  • 对象有3种状态
  • 通过.then注册状态的回调
  • 已完成的状态能触发回调

采用这种方式来处理编程中的异步任务,就是在使用promise了。

所以promise就是一种异步编程模式。

首先,promise实例有三种状态:

  • pending(进行中)
  • fulfilled(已执行)
  • rejected(已拒绝)

fulfilledrejected有可以说是已成功和已失败,这两种状态又归为已完成状态

resolve和reject

调用resolvereject能将分别将promise实例的状态变成fulfilled和rejected,只有状态变成已完成(即fulfilled和rejected之一),才能触发状态的回调

Promise API

promise的内容分为构造函数、实例方法和静态方法

  • 1个构造函数: new Promise
  • 2个实例方法:.then.catch
  • 4个静态方法:Promise.allPromise.racePromise.resolvePromise.reject

new Promise能将一个异步过程转化成promise对象。先有了promise对象,然后才有promise编程方式。

  1. .then用于为promise对象的状态注册回调函数。它会返回一个promise对象,所以可以进行链式调用,也就是.then后面可以继续.then。在注册的状态回调函数中,可以通过return语句改变.then返回的promise对象的状态,以及向后面.then注册的状态回调传递数据;也可以不使用return语句,那样默认就是将返回的promise对象resolve。
  2. .catch用于注册rejected状态的回调函数,同时该回调也是程序出错的回调,即如果前面的程序运行过程中出错,也会进入执行该回调函数。同.then一样,也会返回新的promise对象。
  3. 调用Promise.resolve会返回一个状态为fulfilled状态的promise对象,参数会作为数据传递给后面的状态回调函数
  4. Promise.rejectPromise.resolve同理,区别在于返回的promise对象状态为rejected

Promise.all

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

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

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

p的状态由p1p2p3决定,分成两种情况。

(1)只有p1p2p3的状态都变成fulfilledp的状态才会变成fulfilled,此时p1p2p3的返回值组成一个数组,传递给p的回调函数。

(2)只要p1p2p3之中有一个被rejectedp的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

Promise.race

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

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

上面代码中,只要p1p2p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

Promise.resolve 有时需要将现有对象转为 Promise 对象

Promise.reject 会返回一个新的 Promise 实例,该实例的状态为rejected

[参考资料]:

www.xyhtml5.com/5862.html

ES6 入门教程 - ECMAScript 6入门 (ruanyifeng.com)