Promise介绍和详解

Promise

Promise

        - Promise可以帮助我们解决异步中的回调函数的问题

        - Promise就是一个用来存储数据的容器

                它拥有着一套特殊存取数据的方式

                这个方式使得它里边可以存储异步调用的结果

创建promise

// 创建Promise
const promise = new Promise(executor)

是一个回调函数,进一步创建Promise时需要一个exexutor(执行器)为参数,执行器是一个回调函数,进一步调用大概长这个样子

// 创建Promise
const promise = new Promise((resolve, reject) => {})

回调函数再执行时会收到两个参数,两个参数都是函数,第一个函数通常命名为resolve,第二个函数通常会命名为reject,向Promise中存储值得关键就在于这两个函数,可以将想要存储到Promise中的值作为函数的参数传递,

// 创建Promise
const promise = new Promise((resolve, reject) => {
    resolve("哈哈哈哈")
})
console.log(promise)

两个函数:

  1. resolve用来存储运行正确时的数据
  2. reject用来存储运行出错时的错误信息

我们使用Promise时需要根据不同的情况,调用不同的函数来存储不同的数据;

Promise中存储的主要是异步调用的数据,也就是本来需要回调函数来传递的数据。

在Promise中,可以直接调用异步代码,在异步代码执行完毕后直接调用resolve或reject来执行结果存储到Promise中,这就解决了易怒代码无法设置返回值的情况,如下:

// 创建Promise
const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("哈哈哈")
    }, 10000)
})
console.log(promise)

上述代码中setTimeout实现了一个异步调用,定时器会在10秒后执行,并且调用resolve将“哈哈”存储到promise中;

获取Promise中的数据

then

then是Promise的实例方法,通过改方法可以获取到Promise中存储的数据,它需要一个回调函数作为参数,Promise中存储的数据会作为回调函数的实参返回给我们

const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("哈哈哈")
    }, 1000)
})

promise.then((data) => {
    console.log(data)  // 打印结果为"哈哈"
})

注意:这种方式只适用于读取通过reslove存储的数据,如果存储数据时出现了错误,或者是通过reject存储的数据,这种方式是无法读取的

const promise = new Promise((resolve, reject) => {
    // 出错的数据
    throw new Error("出错了")
    setTimeout(() => {
        resolve("哈哈哈")
    }, 1000)
})

promise.then((data) => {
    console.log(data)  // 打印结果为"哈哈"
})
const promise = new Promise((resolve, reject) => {   
    setTimeout(() => {
        // 通过reject来添加
        reject("哈哈哈")
    }, 1000)
})

promise.then((data) => {
    console.log(data)  // 打印结果为"哈哈"
})

上述两种情况均无法读取到数据,且控制台会在运行时候报错

第一种Promise的代码出错时,应该为其指定第二个参数来处理数据

第二种通过reject来添加数据时,添加的应该是有问题的数据,而不是正常数据

then的第二个参数依然是一个回调函数,两个回调函数的结构是相同的,不同点在于第一个回调函数在resolve添加数据,即没有异常时候被调用,而第二个函数会在出现错误(或者通过reject存储数据)时调用

const promise = new Promise((resolve, reject) => {   
    setTimeout(() => {
        // 通过reject来添加
        reject("哈哈哈")
    }, 1000)
})



promise.then((data) => {
    console.log(data)  // 打印结果为"哈哈"
},(err) => {
    console.log("出错了", err)
})
const promise = new Promise((resolve, reject) => {   
    throw new Error("主动抛出错误")
    setTimeout(() => {
        resolve("哈哈哈")
    }, 1000)
})



promise.then((data) => {
    console.log(data)  // 打印结果为"哈哈"
},(err) => {
    console.log("出错了", err)
})

上面的示例中,then的第二个回调函数会执行

执行时异常信息或通过reject返回的数据作为参数传递

开发过程中,then第二个回调函数通常会用来编写异常        在Promise中维护着两个隐藏的值PromiseResult和PromiseState,PromiseResult是Promise中真正存储值得地方,在Promise中无论是通过resolve、reject还是报错时得异常信息都会存储到PromiseResult中,PromiseState用来表示Promise中值的状态,

Promise一共有三种状态:pending、fulfilled、rejected此时Promise中没有任何值,fulfilled是Promise的完成状态,此时表示值已经正常存储到了Promise中(通过reslove)。rejected表示拒绝,此时表示值是通过reject存储或是执行时出现了错误

当我们调用Promise方法,相当于为Promise设置了一个回调函数,

then中的回调函数不会立即执行,而是在Promise的PromiseState发生变化才会执行。

如果PromiseState从pending变成了fulfilled则then的第一个回调函数执行,且PromiseResult的值作为参数传递给回调函数

如果PromiseState从pending变成了rejected则then的第二个回调函数执行,且PromiseResult的值作为参数传递给回调函数

总结:

Promise中维护了两个隐藏属性:

        PromiseResult

                - 用来存储数据

PromiseState

        - 记录Promise的状态(三种状态)

                pending (进行中)

                fulfilled (完成) 通过resolve存储数据

                rejected  (拒绝,出错了)  出错了或通过reject存储数据时

        - state只能修改一次,修改以后永远不会再变

流程总结:

当Promise创建时,PromiseState初始值为pending

        当通过resolve存储数据时候 PromiseState 变为fulfilled(完成)

                PromiseResult变为存储的数据

        当通过reject存储数据或出错时 PromiseState 变为rejected(拒绝,出错了)

                PromiseResult变为存储的数据 或者 异常对象

当我们通过then读取数据时,相当于为Promise设置了回调函数

        如果PromiseState变为fulfilled,则调用then的第一个回调函数来返回数据

        如果PromiseState变为rejected,则调用then的第二个回调函数来返回数据

 Catch

catch()用法和then类似,但是只需要一个回调函数作为参数

        catch()中的回调函数只会在Promise被拒绝时才调用

        catch()相当于then(null, reson => {} )  即第一个参数为null的then

        catch() 就是一个专门处理Promise异常的方法

const promise = new Promise((resolve, reject) => {   
   
    reject("出错了")
})


// 出现异常,使用catch来读取数据
promise.catch(err => {
    console.log(err)
})

处理Promise时,如果没有对Promise中的异常进行处理(无论是then的二参数,还是catch),则异常信息总是会封装到下一步的Promise中进行传递,直到找到异常处理代码的位置,如果没有处理,则报错

这种设计方式使得我们可以在任意位置对Promise的异常进行处理,如下实例

function sum(a, b) {
    return new Promise((resolve, reject) => {
        if (Math.random() > 0.7) {
            throw new Error("出错了")
        }
        resolve(a + b)
    })
}

sum(123, 456)
    .then(result => sum(result, 777))
    .then(result => sum(result, 888))
    .then(result => console.log(result))

上述示例中,sum函数有几率会出现异常,但我们并不确定何时出现异常,

因为在出现异常后所有的then在异常处理前都不会执行,所以可以将catch写在调用链的最后,这样无论哪一步出现异常,我们都可以在最后统一处理

sum(123, 456)
    .then(result => sum(result, 777))
    .then(result => sum(result, 888))
    .then(result => console.log(result))
    .catch(err => console.log("出错了", 88888))

当然如果我们想在中间处理异常也是可以的,只是需要注意在链式中间处理异常时候,由于后续还有then要执行,所以一点过不要忘了来考虑是否需要在catch中返回一个结果供后续的promise使用:

function sum(a, b) {
    return new Promise((resolve, reject) => {
        if (Math.random() > 0.7) {
            throw new Error("出错了")
        }
        resolve(a + b)
    })
}

sum(123, 456)
    .then(result => sum(result, 777))
    .catch(err => {
        // 在调用链的中间处理异常
        console.log("出错了,选择忽略这个错误,重新计算")
        // 返回一个结果供后续运算
        return sum(123, 456)
    })
    .then(result => sum(result, 888))
    .then(result => console.log(result))
    

需要注意的是。在Promise正常执行的情况下如果遇到catch,catch是不会执行的,此时Promise中的结果会自动传递给下一个Promise供后续使用

Finally

  • 无论是正常存储数据还是出现异常了,finally总会执行
  • 通常在finally中定义一些无论Promise正常执行与否都需要处理的工作
  • finally的回调函数不接收任何参数
  • finally的返回值不会成为下一步的Promise中的结果
  • finally只是编写一些必要执行的代码,不会对Promise产生任何实质性的影响

猜你喜欢

转载自blog.csdn.net/z972065491/article/details/129495068