Promise运行规则和使用技巧

297 阅读3分钟

Promise 特性和使用技巧

相信学过js都知道Promise,但有没有思考过,在then或catch方法的函数中,return一个新的Promise会发生什么事? 由此探索Promise的特性和使用。

Promise一共有三个状态:

  • pending:未决,可以理解成无状态;
  • reslove:已决,类似成功;
  • reject:拒绝,类似失败;

1. Promise 中,必须有状态变化,才会执行后续的then或者catch

new Promise((resolove, reject) => {
    console.log('pending');
}).then(() => {
    console.log('then');
}).catch(() => {
    console.log('catch');
})
由于没有状态变化,所有是不会执行then或者catch中的方法,结果:
pending

2. Promise 中,进入reslove状态后,后续如果很有多个then,则按顺序执行

new Promise((resolove, reject) => {
    resolove()
}).then(() => {
    console.log('then1')
}).catch(() => {
    console.log('catch1')
}).then(()=>{
    console.log('then2')
}).catch(()=>{
    console.log('catch2')
})
由pending变成resolove状态,只会执行then方法,其后续有then,都按顺序执行,结果:
then1
then2

3. catch只会执行一次,如果后续有then,会继续执行then

new Promise((resolove, reject) => {
    reject()
}).then(() => {
    console.log('then1')
}).catch(() => {
    console.log('catch1')
}).then(()=>{
    console.log('then2')
}).catch(()=>{
    console.log('catch2')
})
由pending变成reject状态,只会执行catch方法,其后续没有状态变化,只会执行then,结果:
catch1
then2

4. 如果then中return了Promise,会根据返回Promise选择新状态变化

new Promise((resolove, reject) => {
    console.log('pending1')
    resolove()
}).then(() => {
    console.log('then1')
    return new Promise((resolove, reject)=>{
        console.log('pending2')
        reject()
    })
}).then((res)=>{
    console.log('then2')
}).catch((res)=>{
    console.log('catch1')
})
由于then1 后续return新的promise,且在Promise中把状态变成了reject,此时不会执行then2,而是执行catch1,结果:
pending1
then1
pending2
catch1

5. 第4点的规律也能和第1点组合,return的Promise若为无状态,则不再执行后续的then

new Promise((resolove, reject) => {
    console.log('pending1')
    resolove()
}).then(() => {
    console.log('then1')
    return new Promise((resolove, reject)=>{
        console.log('pending2')
    })
}).then(()=>{
    console.log('then2')
}).catch(()=>{
    console.log('catch1')
})
then1方法中return的Promise为pending,中断多个then会顺序执行的规则,结果:
pending1
then1
pending2

6. Promise类方法,Promise.resolove() 和 Promise.reject()实质就是改变状态

new Promise((resolove, reject) => {
    console.log('pending1')
    resolove()
}).then(() => {
    console.log('then1')
    return Promise.reject()
}).then((res)=>{
    console.log('then2')
}).catch((res)=>{
    console.log('catch1')
})
这里过程和第4点是一样的,只不过return new Promise 可以改写成无状态,或者在Promise中嵌套更复杂的运算,结果:
pending1
then1
catch1

7. Promise可以存起来,到特定的时机再用

const list = []
new Promise((resolove, reject) => {
    list.unshift({resolove, reject})
}).then(() => {
    console.log('then1')
})
new Promise((resolove, reject) => {
    list.unshift({resolove, reject})
}).then(() => {
    console.log('then2')
})
new Promise((resolove, reject) => {
    list.unshift({resolove, reject})
}).then(() => {
    console.log('then3')
})
list.forEach(item=>{
    item.resolove()
})
结果:
then3
then2
then1

总结

  1. new Promise(),then(),catch()返回的都是promise;
  2. new Promise是pending状态,then和catch在执行完成后,默认返回resolove状态,所有遇到后面的then,都会继续执行;
  3. 执行途中return 新的Promise,可以改变当前状态;
  4. 两个Promise的静态方法,Promise.resolove() 和 Promise.reject()返回的也是promise,前者是resolove状态,后者是reject状态;

课后习题

new Promise((resolove, reject) => {
    resolove()
}).then(res => {
    console.log('then1')
    return new Promise((resolove, reject) => {
        console.log('pending1')
        resolove()
    }).then(res=> {
        console.log('then2')
        // 问:如何根据当前then改变最顶层promise的状态,即结果变成 then1  pending1  then2  catch1
    })
}).then(() => {
    console.log('then3')
}).catch(() => {
    console.log('catch1')
}) 
结果:
then1
pending1
then2
then3

答案

new Promise((resolove, reject) => {
    resolove()
}).then(res => {
    console.log('then1')
    return new Promise((resolove, reject) => {
        console.log('pending1')
        resolove()
    }).then(res=> {
        console.log('then2')
        // 解:前面说过,then如果return一个新的promise,会根据内层的Promise更新外层的Promise状态,所以,当执行then2,默认返回的是resolove状态,接下来会执行外层的then3,若能改变当前then2的状态,则可以不执行then3,而是执行catch1
        return Promise.reject()
    })
}).then(() => {
    console.log('then3')
}).catch(() => {
    console.log('catch1')
}) 
结果:
then1
pending1
then2
catch1