ES6中Promise的用法及resolve、rejected、catch、finally说明


Promise是异步编程的一种解决方案。避免了类似于$.ajax()这种多个异步操作层层嵌套的问题。

Promise对象的特点:

  1. Promise对象有三种状态:padding(初始状态)fulfilled(异步成功之后的状态)rejected(异步失败的状态),改变状态的方式只有一种即异步的结果:如果成功状态由padding——>fulfilled;否则状态由padding——>rejected。无法提供其他方式改变状态。
  2. 状态一旦改变就无法更改。
  3. 无法取消Promise,一旦建立就会执行。。。

Promise语法

new Promise((resolve, reject) => {
    if (异步成功后) {
        resolve(value)//将Promise的状态由padding改为fulfilled
    } else {
        reject(error)//将Promise的状态由padding改为rejected
    }
}).then(value => {
    // resolve回调 
}, error => {
    // reject回调
})

上面的代码表示如果异步成功后就会调用.then()里面的第一个参数方法,否则就会调用.then()里面的第二个参数方法。如果调用resolvereject有参数则会将参数分别传递给回调函数(.then里面的第一个和第二个参数方法)。

resolve的参数除了正常值外还可以是一个Promise实例。如:

let p1 = new Promise((resolve, reject) => {
    // ...
})
let p2 = new Promise((resolve, reject) => {
    // ...
    resolve(p1)
})

上面的代码中p1p2为Promise实例。p2resolvep1作为参数。即:一个异步操作的结果是返回另一个异步操作。
注意:这时p1的状态决定了p2的状态。如果p1的状态为padding那么p2的回调会等p1的状态改变后执行(即p1成功或失败);如果p1的状态为resolvedrejected那么p2的回调会立即执行。
示例:

let p1 = new Promise((resolve, reject) => {
    setTimeout(()=>{
        reject(new Error('发生错误嘹'))
    },3000)
})
let p2 = new Promise((resolve, reject) => {
    setTimeout(()=>{
        resolve(p1)
    },1000)
}).then(value => {
    console.log(value)
}).catch(error=>{
    console.log(error)
})

正因为如此上面代码p2最终执行的是catch()方法,并不会走then()方法。


调用resolvereject并不会终结 Promise 的参数函数的执行。
代码示意:

new Promise((resolve, reject) => {
    setTimeout(()=>{
        resolve('then')
        console.log('promise')
    },2000)
}).then(value => {
    console.log(value)
})
//执行结果
//promise
//then

一般来说上面的console.log('promise')如果要执行放到回调函数更加规范

Promise.then()

.then()的作用是为 Promise 实例添加状态改变时的回调函数
.then()方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。它的返回的是一个新的Promise实例。因此可以采用链式写法。

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

上面代码中,第一个then方法指定的回调函数,返回的是另一个Promise对象。这时,第二个then方法指定的回调函数,就会等待这个新的Promise对象状态发生变化。如果变为resolved,就调用funcA,如果状态变为rejected,就调用funcB

Promise.catch()

用于指定发生错误时的回调函数,最好是在.then()的链式调用最后调用一下此方法来捕获异常。它的返回值仍然是个Promise对象

new Promise((resolve, reject) => {
    throw new Error('出现错误了')
}).then(value => {

}).catch(error=>{
    console.log(error)
})

上面代码中如果Promise对象状态变为resolved,则会调用then方法指定的回调函数;如果异步操作抛出错误,状态就会变为rejected,就会调用catch方法指定的回调函数,处理这个错误。另外,then方法指定的回调函数,如果运行中抛出错误,也会被catch方法捕获。


如果 Promise 状态已经变成resolved,再抛出错误是无效的。

new Promise((resolve, reject) => {
    resolve('data')
    throw new Error('出现错误了')
}).then(value => {
    console.log(value)
}).catch(error=>{
    console.log(error)
})

这时不会运行catch()里面的方法


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

如果没有使用catch方法指定错误处理的回调函数,Promise 对象即便抛出错误也不会影响到其它代码

Promise.finally()

finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。
finally方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是fulfilled还是rejected。这表明,finally方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。
finally本质上是then方法的特例。如下代码是等效的:

promise
.finally(() => {
  // 语句
});
// 等同于
promise
.then(
  result => {
    // 语句
    return result;
  },
  error => {
    // 语句
    throw error;
  }
);

Promise.all()

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

const p = Promise.all([p1, p2, p3])
  1. p1p2p3都为Promise实例,如果不是调用Promise.resolve将它们转成Promise实例。
  2. p的状态由p1p2p3共同决定如果它们的状态全都fulfilledp的状态变成fulfilled,此时p1p2p3的返回值组成一个数组传递给p的回调
  3. p1p2p3中只要有一个为rejected,则p的状态变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
  4. p1p2p3自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法
const p1 = new Promise((resolve, reject) => {
  resolve('hello');
})
.then(result => result)
.catch(e => e);

const p2 = new Promise((resolve, reject) => {
  throw new Error('报错了');
})
.then(result => result)
.catch(e => e);

Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// ["hello", Error: 报错了]

上面代码中,p1resolvedp2首先会rejected,但是p2有自己的catch方法,该方法返回的是一个新的 Promise 实例,p2指向的实际上是这个实例。该实例执行完catch方法后,也会变成resolved,导致Promise.all()方法参数里面的两个实例都会resolved,因此会调用then方法指定的回调函数,而不会调用catch方法指定的回调函数。如果p2没有自己的catch方法,就会调用Promise.all()catch方法。

Promise.race()

此方法和Promise.all()一样接收多个Promise实例,返回一个新的Promise实例。

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

Promise.all()不同之处是只要p1、p2、p3中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数

Promise.resolve()

Promise.resolve()的作用是将现有对象转换成Promise对象。
以下的写法是等效的

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

Promise.resolve()参数的4种情况

参数是一个 Promise 实例

参数是一个 Promise 实例,这种情况Promise.resolve()什么都不做

参数是一个thenable对象

参数是具有then方法的对象(thenable对象)Promise.resolve方法会将这个对象转为Promise对象,然后就立即执行thenable对象的then方法。例如:

let thenable = {
  then: function(resolve, reject) {
    resolve(42);
  }
};
let p1 = Promise.resolve(thenable);
p1.then(function(value) {
  console.log(value);  // 42
});

上面代码中,thenable对象的then方法执行后,对象p1的状态就变为resolved,从而立即执行最后那个then方法指定的回调函数,输出 42

参数是普通对象或原始值

参数不是具有then方法的对象,或根本就不是对象,Promise.resolve返回一个状态为resolved的对象

const p = Promise.resolve('Hello');
// 因为p的状态为resolved所以.then()会立即执行
p.then(function (s){
 console.log(s)
});
// Hello

不带任何参数

这种情况直接返回状态为resolved的Promise对象。如果希望得到一个 Promise 对象,比较方便的方法就是直接调用。
立即resolve的 Promise 对象,是在本轮“事件循环”(event loop)的结束时,而不是在下一轮“事件循环”的开始时。示例:

setTimeout(function () {
  console.log('three');
}, 0);

Promise.resolve().then(function () {
  console.log('two');
});

console.log('one');
// one
// two
// three

上面代码中,setTimeout(fn, 0)在下一轮“事件循环”开始时执行,Promise.resolve()在本轮“事件循环”结束时执行,console.log(‘one’)则是立即执行,因此最先输出。

Promise.reject()

返回状态为rejected的Promise对象

猜你喜欢

转载自blog.csdn.net/one_four_two/article/details/86618309