promise的三种状态及.then() .catch() .finally() .all() .race()的使用

Promise是ES6提出的一个新语法,用来优化异步代码的写法,是前端领域里的必会内容。

1.Promise的基本使用

1.1promise的三种状态

初始态pending:创建Promise对象时,且没有调用resolve或者是reject方法,相当于是初始状态。这个初始状态会随着你调用resolve,或者是reject函数而切换到另一种状态。

let p = new Promise((ok,err)=>{ console.info('发呆.....' )})
console.dir(p)//此时为初始态pending

成功态resolved(fulfilled ):表示解决了,就是说这个承诺实现了。 要实现从pending到resolved的转变,需要在创建Promise对象时,在函数体中调用了resolve方法(即第一个参数)。

var p = new Promise((resolve,reject)=>{ resolve();})
console.dir(p)//此时状态为fullfilled

失败态rejected:表示这个承诺没有做到,失败了。 要实现从pending到rejected的转换,需要在创建Promise对象时,调用reject函数(即第二个参数)。

var p = new Promise((resolve,reject)=>{ reject()} )
console.dir(p)//此时状态为rejected

小结:

1.状态是可转化。

最初创建promise对象时,默认状态是pending,如果在函数体内部调用了第一个参数对应的函数,则状态变成了resolved;如果调用了第二个参数对应的函数,则状态变成了rejected。

 pending -----  resolve() --> resolved;
 pending -----  reject()  --> rejected;

2.状态转换是不可逆的。一旦从pending ---> resolved(或者是rejected),就不可能再回到pending,也不能由resolved变成rejected。

1.2promise值

一个promise对象除了状态之外,还有promiseValue,这个值在调用resolve和reject方法时传入。

var p = new Promise( (resolve,reject) => { resolve(123); } );
//  此时,prommise对象p的状态是 resolved,值是123。
console.dir(p)
var p = new Promise( (resolve,reject) => { reject(123); } );
//  此时,prommise对象p的状态是 rejected,值是123
console.dir(p)

1.3promise的兑现

一旦状态发生了变化,就会进行then,或者是catch中去,同时把promiseValue传入对应的函数。

  • 状态从pending变成resolved,进入then中,调用函数,并传入此时的promiseValue(就是调用resolve时传入的实参)

  • 状态从pending变成rejected,进入catch中,调用函数,并传入此时的promiseValue(就是调用reject时传入的实参)

经典格式

 // 许下承诺
  const p= new Promise((resolve, reject) => {
    // 做异步操作
    // 把状态从pending设为resolved,用实参来设置值
    resolve(66)
    // 把状态从pending设为rejected,用实参来设置值
    // reject(55)
  })
  console.dir(p);//打印输出,可以观察状态和值
  // 兑现承诺
  p.then(res => {
    // 执行时机:当promise状态从pending ---> resolved时执行
    // res是此时promise的值
    console.log('成功了');
  }).catch(err => {
    // 执行时机:当promise状态从pending ---> rejected时执行
    // err是此时promise的值
    console.log('失败了');
  }).finally(res => {
    // 不管状态如何,都一定会执行此函数
    console.log('永远会执行');
  })

2.then的格式及执行逻辑

 2.1格式

then方法的作用是为Promise对象添加状态改变时的回调函数,有两个参数。

// p 是一个promise对象
p.then(函数1[,函数2])//第二个函数可省略

它的两个参数都是函数。

  • 第一个参数是resolved状态的回调函数。当p的状态从pending变成了resolved之后,函数1会执行。

  • 第二个参数是rejected状态的回调函数。 当p的状态从pending变成了rejected之后,函数2会执行。

  • 其中第二个参数是可选的,如果只写一个参数的话就是如下:

    promise对象.then(函数1)

2.2执行逻辑 

var p = new Promise((resolve,reject)=>{
   resolve(val1);
    // or reject(val2)
})

p.then((okVal)=>{
    console.info("成功");
    console.log(okValue);
}, (errVal)=>{
    console.info("失败");
    console.log(errValue);
})

它的两个参数都是函数,其执行逻辑是:

  • 如果promise对象的状态是resolved,则then()会执行第一个函数,并传入当前的PromiseValue(即上面的val1);

  • 如果promise对象的状态是rejected,则then()会执行第二个函数,并传入当前的PromiseValue(即上面的val2);

  • 特别地,如果promise对象的状态是rejected,且此时then方法并没有设置第二个参数,就会向外抛出一个错误,错误的提示大约是Uncaught (in promise)

    var p = new Promise((resolve,reject)=>{
    	resolve(1)//主动调用resolve,并传入
    })
    // 此时,P的状态是resolved,且值promiseValue 是1.
    p.then((res)=>{
        // 因为p的状态是resolved,所以自动执行then的第一个参数,并且把promisevalue传进来。
    	console.log("then,ok",res)
    })   //执行输出结果是:`then,ok,1`
    var p = new Promise((resolve,reject)=>{
    	reject(2)//主动调用reject,并传入实参
    })
    // 此时,P的状态是rejected,且值promiseValue 是2.
    
    p.then((res)=>{
        // 因为p的状态是resolved,所以这句代码不会执行。
    	console.log("then,ok",res)
    },(err)=>{
        // 因为p的状态是rejected,所以自动执行then的第二个参数,并且把promisevalue传进来。
    	console.log("then,err",err)
    })   //执行输出结果是:`then,err,2`

    2.3then的返回值(难点)

 then()方法的返回值也是一个promise对象,所以它支持链式写法。但是要注意的是它的返回值是一个新的promise对象,与调用then方法的并不是同一个对象

var p1 = new Promise(()=>{});
var p2 = p1.then(function f_ok(){}, function f_err(){}); 
// p2也是一个promise对象。

console.log(p1 === p2); // false

p2的状态及promiseValue按如下规则来确定

  • 如果p1的状态是pending,则p2的状态也是pending。

  • 如果p1的状态是resolved,then()会去执行f_ok,则p2的状态由f_ok的返回值决定。

    • 如果f_ok返回值不是promise对象,则p2的状态是resolved,且p2的promiseValue就是f_ok函数的return值。

    • 如果f_ok返回值是一个promise对象,则p2的状态及promiseValue以这个promise对象为准。

    • 如果f_ok这个函数内部发生了错误(或者是用户主动抛出错误),则p2的状态是rejected,且p2的promiseValue就是这个错误对象。

  • 如果p1的状态是rejected,then()会去执行f_err,则p2的状态由f_err的返回值决定。

    • 如果f_err返回值不是promise对象,则p2的状态是resolved,且p2的promiseValue就是f_err函数的return值。

    • 如果f_err返回值是一个promise对象,则p2的状态及promiseValue以这个promise对象为准。

    • 如果f_err这个函数内部发生了错误(或者是用户主动抛出错误),则p2的状态是rejected,且p2的promiseValue就是这个错误对象。

3.catch的格式及用法

3.1catch的格式

 Promise.prototype.catch 是 Promise.prototype.then(null, reject)的别名,用于指定当promise对象的状态从pending变成rejected的回调函数 。

var p1 = new Promise((resolve,reject)=>{
	reject('s')
});

p1.catch(function(err){
	console.log(err);
})

// 与下面的代码等价
p1.then(null, function(err){
	console.log(err);
})

单独使用catch没有什么意义,它一般与then一块使用。如下:

new Promise((resolve,reject)=>{

}).then(function(result){
	// 如果promise对象的状态是resolved的,就会到这里来,并且result会接收promiseValue的值
}).catch(function(err){
	// 如果promise对象的状态是rejected的,就会到这里来,并且err会接收promiseValue的值
})

// 上面的代码如何拆分来写的话,等价于:
var p1 = new Promise((resolve,reject){

});
var p2 = p1.then(function(result){

});
var p3 = p2.catch(function(err){

})

3.2catch的返回值

catch的返回值仍是一个promise对象,确定它的值的方式与then(null,(errVal)=>{ })的方式一致。  

4.promise的链式调用

function do1() {
    console.log("任务1");
}
function do2() {
    console.log("任务2");
}
function do3() {
     console.log("任务3");
}
function do4() {
    console.log("任务4");
}

var p = new Promise((resolve,reject)=>{ resolve()})
p.then(do1)
 .then(do2)
 .then(do3)
 .then(do4);


//结果输出是:`任务1,任务2,任务3,任务4`

 分析:

第一步:由于p的状态是resolved,所以p.then(do1)中,do1函数会执行。输出任务1

第二步:确定p1的状态。按前面关于then的部分的介绍,p1的状态由do1()来决定。因为do1并没有明确指定返回值,则返回值就是undefined. p1的状态就是resolved。

第三步:由于p1的状态是resolved,所以p1.then(do2)会继续执行do2。输出任务2 ,且p2的状态由do2来决定。与第二步的分析相同,p2的状态仍是resolved。

第四步:接下来看p3。由于p2的状态是resolved,所以p2.then(do3)会继续执行do3。输出任务2 ,且p3的状态由do3来定,仍是resolved。

最后:p3.then(do4)。由于p3的状态是resolved,所以执行do4。输出任务4

function do1() {
    console.log("任务1");
}
function do2() {
    console.log("任务2");
}
function do3() {
     console.log("任务3");
}
function do4() {
    console.log("任务4");
}

var p = new Promise((resolve,reject)=>{ resolve()})
p.then(do1)
 .then(do2)
 .catch(do3)
 .then(do4);

//的执行结果是:`任务1, 任务2, 任务4`

 分析:

第一步:由于p的状态是resolved,所以p.then(do1)中,do1函数会执行。输出任务1

第二步:确定p1的状态。按前面关于then的部分的介绍,p1的状态由do1()来决定。因为do1并没有明确指定返回值,则返回值就是undefined. p1的状态就是resolved。

第三步:由于p1的状态是resolved,所以p1.then(do2)会继续执行do2。输出任务2 ,且p2的状态由do2来决定。与第二步的分析相同,p2的状态仍是resolved。

第四步:接下来看p3。由于p2的状态是resolved,所以它并不会执行do3, p3的状态没有变化,仍保持p2的状态:resolved。

最后:p3.then(do4)。由于p3的状态是resolved,所以执行do4。输出任务4

function do1() {
    console.log("任务1");
    console.log(abc); //故意犯错
}
function do2() {
    console.log("任务2");
}
function do3() {
     console.log("任务3");
}
function do4() {
    console.log("任务4");
}

var p = new Promise((resolve,reject)=>{ resolve()})
p.then(do1)
 .then(do2)
 .then(do3)
 .catch(do4);

//执行结果是:`任务1, 任务4`。

分析:

第一步:由于p的状态是resolved,所以p.then(do1)中,do1函数会执行,输出任务1,同时由于这里有段错误代码,所以p1的状态就是rejected。

第二步:由于p1的状态是rejected,所以p1.then(do2) 就不会执行do2,同时p2的状态也是rejected。

第三步:对p3的分析也是如此。

第四步:p3的状态是rejected,所以会执行do4。

function increment(value) {
    return value + 1;
}
function doubleUp(value) {
    return value * 2;
}
function output(value) {
    console.log(value);// => (1 + 1) * 2
}
var p = Promise.resolve(1);
p.then(increment)
 .then(doubleUp)
 .then(output)    

//输出结果是 4

分析

// 状态:resolved; promiseValue: 1
var p = Promise.resolve(1); 

// p的状态是resolved; 
// 在执行then的第一个参数,即increment时
// 把p的 promiseValue 1 传入
// increment执行后的返回值就是2
// p1的状态是resolved,promiseValue是2 
var p1 = p.then(increment); 

// p1的状态是resolved; 
// 在执行then的第一个参数,即doubleUp时
// 把p1的promiseValue 2传入
// doubleUp执行后的返回值就是4
// p2的状态是resolved,promiseValue是4
var p2 = p1.then(doubleUp); 

// p2的状态是resolved,promiseValue是4
// 在执行then的第一个参数,即output时
// 把p2的promiseValue传入,就是4
var p3 = p2.then(output) ; 

5.Promise.all()希望并行执行多个 promise,并等待所有 promise 都准备就绪。

语法:let promise = Promise.all([...promises...]);

当我们做一个操作可能得同时需要不同的接口返回的数据,这时我们就可以使用Promise.all(),需要注意,结果数组中元素的顺序与其在源 promise 中的顺序相同。即使第一个 promise 花费了最长的时间才 resolve,但它仍是结果数组中的第一个

        let p1 = Promise.resolve('aaa')
        let p2 = Promise.resolve('bbb')
        let p3 = Promise.resolve('ccc')
        let p4 = Promise.resolve('ddd')
        Promise.all([p1, p2, p3, p4]).then(res => {
            console.log(res); //返回数组 ['aaa', 'bbb', 'ccc', 'ddd']
        }).catch(err => {
            console.log(err);
        })
        
        Promise.all([
        new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1
        new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
        new Promise(resolve => setTimeout(() => resolve(3), 1000))  // 3
        ]).then(res=>{
          console.log(res)//返回数组[1, 2, 3]
        })

如果任意一个 promise 被 reject,由 Promise.all() 返回的 promise 就会立即 reject,完全忽略列表中其他的 promise,并且带有的就是这个 error。

        let p1 = Promise.resolve('aaa')
        let p2 = Promise.resolve('bbb')
        let p3 = Promise.reject('ccc')
        let p4 = Promise.resolve('ddd')
        Promise.all([p1, p2, p3, p4]).then(res => {
            console.log(res); //这里不执行
        }).catch(err => {
            console.log(err);//返回ccc
        })

6.Promise.race() 只等待第一个 settled 的 promise 并获取其结果(或 error),即谁快,就获取谁的结果,不论成功或失败

  Promise.race([
   new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)),
   new Promise((resolve, reject) => setTimeout(() => reject(new Error("Whoops!")), 2000)),
   new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000))
  ]).then(err => 
   console.log(err);// 1
  }); 

  Promise.race([
    new Promise((resolve, reject) => setTimeout(() => resolve(1), 2000)),
    new Promise((resolve, reject) => setTimeout(() => reject(2), 1000)),
    new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000))
  ]).catch(err => {
    console.log(err);// 2
  }); 

### 回答1: promise的then方法用于处理promise对象的成功状态,它接收一个回调函数作为参数,当promise对象成功时,then方法会调用该回调函数。 promisecatch方法用于处理promise对象的失败状态,它接收一个回调函数作为参数,当promise对象失败时,catch方法会调用该回调函数。 promisefinally方法用于在promise对象无论成功或失败都会执行的操作,它接收一个回调函数作为参数,当promise对象无论成功或失败时,finally方法都会调用该回调函数。 ### 回答2: promise对象是用于处理异步操作结果的,它有一个then方法和一个catch方法,还有一个可选的finally方法。 首先,then方法用于处理promise对象的成功状态。当promise对象成功解决时,then方法会被调用,我们可以在then方法中指定一个回调函数来处理成功的结果。这个回调函数接收promise对象成功时的解决值作为参数,并返回一个新的promise对象。通过链式调用多个then方法,我们可以实现多个异步操作的顺序执行。 其次,catch方法用于处理promise对象的失败状态。当promise对象被拒绝时,即出现错误或异常,catch方法会被调用。我们可以在catch方法中指定一个回调函数来处理失败的原因,并返回一个新的promise对象。与then方法类似,catch方法也可以通过链式调用多个catch方法,以处理不同的失败情况。 最后,finally方法可选的。它会在promise对象无论是成功还是失败后都被调用。无论是在then或catch方法中返回的promise对象是解决还是拒绝,finally方法都会在最后被调用。我们可以在finally方法中执行一些清理操作,比如关闭资源或释放内存。 总结来说,then方法用于处理promise对象的解决状态catch方法用于处理promise对象的拒绝状态finally方法可选的用于在最后执行一些清理操作。通过这三个方法的灵活组合使用,我们可以更好地管理和处理异步操作的结果。 ### 回答3: promise的then方法和catch方法是Promise对象上的方法,用于处理异步操作的结果或捕获异常。 then方法可以接受两个参数——onFulfilled(成功时的回调函数)和onRejected(失败时的回调函数)。当一个Promise对象的状态变为fulfilled(成功)时,then方法会执行onFulfilled回调函数;当一个Promise对象的状态变为rejected(失败)时,then方法会执行onRejected回调函数。其中,onFulfilled和onRejected都是可选参数,可以根据实际需求只传入其中一个。 catch方法用于捕获Promise对象内部抛出的异常。它是then方法的语法糖,相当于只传递onRejected回调函数的then方法。当一个Promise对象的状态变为rejected(失败)时,catch方法会执行传入的回调函数,用于处理异常情况。 finally方法是Promise对象的另一个方法,它接受一个回调函数作为参数。不管Promise对象的状态是fulfilled(成功)还是rejected(失败),finally方法都会执行传入的回调函数。该回调函数无论如何都会被执行,用于处理一些需要在Promise结束时执行的逻辑,比如清理工作。 总结来说,then方法用于处理Promise对象的成功和失败状态catch方法用于捕获异常,finally方法用于执行一些无论Promise对象状态如何都需要执行的操作。这三个方法的链式调用可以有效地处理异步操作的结果,并进行必要的处理和清理工作。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值