前端学习——Promise

Promise基本概念

基本概念

promise就是javscript中一种用于处理异步操作对象

Promise的三种状态:

1、pending(进行中):操作没有完成,也没有失败,正在进行中或等待某件事情发生。

2、Fulfilled(已完成):操作已经完成并返回了一个结果。

3、Rejected(以失败):操作未能发成,发生了某种错误或问题。

Promise 对象只有:从 pending 变为 fulfilled 和从 pending 变为 rejected 的状态改变。只要处于 fulfilled 和 rejected ,状态就不会再变了即 resolved(已定型)。

状态的缺点:

  • 无法取消 Promise ,一旦新建它就会立即执行,无法中途取消。
  • 如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。
  • 当处于 pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

Promise的链式调用规则:

Promise的链式调用是指:

  1. 在一个Promise.then() 方法中返回一个新的Promise,然后可以继续在这个新的Promise上调用.then() 方法
  2. 这种方式可以:让我们可以把多个异步操作串联起来,依次处理,避免回调地狱

Promise的静态方法

Promise.then()

then 方法接收两个函数作为参数,第一个参数是 Promise 执行成功时的回调,第二个参数是 Promise 执行失败时的回调,两个函数只会有一个被调用。

Promise.all(iterable):


接受一个可迭代对象(通常是一个数组)作为参数,其中每个元素都是一个 Promise。
只有当所有的 Promise 都完成时,返回的 Promise 才会被完成,结果是一个包含所有结果的数组
如果有任何一个Promise被拒绝,Promise.all会立即返回一个被拒绝的Promise

async和await

async和await是JavaScript中用于处理异步操作的关键字
它们让你能够像写同步代码那样编写异步代码,使得代码更加清晰和易读。

async 函数

async是用来定义一个异步函数的关键字。
一个函数一旦被定义为 async,它就会自动返回一个 Promise,而不论你在函数中实际返回的是什么。

await 关键字

await只能在async函数内部使用。
它用于等待一个Promise完成,并获得Promise解决的值

使用await,就像在告诉JS:“等一下,等这个Promise完成了,再继续执行后面的代码。”

async 和 await 的好处:

  • 更易读:它让你可以像写同步代码一样写异步代码,不需要再用.then()链式调用,代码逻辑更直观
  • 错误处理:你可以使用try...catch语句来处理异步操作中的错误,这样比处理Promise的.catch()更加清晰。

手写Promise

const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'

// 完整版
class myPromise {
    constructor(executor) {
        this.status = PENDING
        this.value = undefined
        this.reason = undefined

        //当存在异步回调时,先记录下来,等到前一个异步回调执行完成后再取出执行
        this.onResolvedCallbacks = []
        this.onRejectedCallbacks = []

        //通过调用resolve和reject来进行状态的流转
        let resolve = (value) => {
            if (this.status === PENDING) {
                this.status = FULFILLED
                //记录下resolve里面传进来的参数值,这也是下面then的第一个回调参数onFulfilled中的参数
                this.value = value
                this.onResolvedCallbacks.forEach((fn) => fn())
            }
        }

        let reject = (reason) => {
            if (this.status === PENDING) {
                this.status = REJECTED
                //记录下reject里面传进来的参数值,这也是下面then的第二个回调参数onRejected中的参数
                this.reason = reason
                this.onRejectedCallbacks.forEach((fn) => fn())
            }
        }

        try {
            executor(resolve, reject)
        } catch (error) {
            reject(error)
        }
    }

    then(onFulfilled, onRejected) {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => value
        onRejected =
            typeof onRejected === 'function'
                ? onRejected
                : (error) => {
                      throw error
                  }

        let promise2 = new myPromise((resolve, reject) => {
            if (this.status === FULFILLED) {
                //直接调用
                setTimeout(() => {
                    try {
                        let x = onFulfilled(this.value)
                        this.resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            }

            if (this.status === REJECTED) {
                //直接调用
                setTimeout(() => {
                    try {
                        let x = onRejected(this.reason)
                        this.resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            }
            //执行.then()的时候,Promise实例化的部分可能存在异步,因此需要先把then里面的执行单独开辟一个空间存起来,然后等实例化的部分执行到resolve的时候,就拿出来执行
            //单独开辟一个空间是为了保证他们的执行顺序,每一个执行都是一次独立的tick
            if (this.status === PENDING) {
                //储存函数
                this.onResolvedCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            //x是then里面第一个参数onFulfilled的返回值
                            //这里调用onFulfilled,先执行onFulfilled函数体,然后拿到onFulfilled的返回值赋值给x
                            let x = onFulfilled(this.value)
                            //this.resolvePromise针对x的情况做处理
                            this.resolvePromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                })

                this.onRejectedCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onRejected(this.reason)
                            this.resolvePromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                })
            }
        })

        return promise2
    }
    catch(onRejected) {
        return this.then(null, onRejected)
    }

    resolvePromise(promise2, x, resolve, reject) {
        //promise2是then的返回值,x是then里面参数回调的返回值,不应该是同一个引用
        if (promise2 === x) {
            //链式调用类型检测失败
            return reject(new TypeError('Chaining cycle detected for promise'))
        }

        let called = false
        //typeof x === 'object'说明x是promise,说明是then的参数回调返回了一个promise
        //例如:new Promise().then((value) => {
        //          return new myPromise(resolve=>{
        //              resolve(1)
        //           })
        //      })
        //x就是 new myPromise(resolve=>{
        //              resolve(1)
        //           })
        if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
            try {
                let then = x.then
                if (typeof then === 'function') {
                    //call的作用 ===> this指向x,并调用then()
                    then.call(
                        x,
                        //onFulfilled then的第一个参数
                        (y) => {
                            //called是为了确保这里只执行一次
                            if (called) return
                            called = true
                            this.resolvePromise(promise2, y, resolve, reject)
                        },
                        //onRejected then的第二个参数
                        (error) => {
                            if (called) return
                            called = true
                            reject(error)
                        }
                    )
                } else {
                    //typeof x === 'function'就直接传给resolve,流转状态
                    resolve(x)
                }
            } catch (error) {
                if (called) return
                called = true
                reject(error)
            }
        } else {
            resolve(x)
        }
    }
}

// 测试用例
const asyncOperation = new myPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('异步逻辑 等待1s')
        console.log('异步promise')
    }, 1000)
})

asyncOperation
    .then((value) => {
        console.log('then:', value)
        //若这里是return 1223456  执行.then()时就是pending状态,就存起来
        //下面这种返回了一个Promise,也是先存起来;取出来调用时,发现传入的x是一个Promise,就执行了x.then(),相当于循环处理
        return new myPromise((resolve, reject) => {
            //这里执行到x.then()之前,这个Promise调用了resolve,状态变为fulfilled,因此.then()的逻辑中会直接调用条件为FULFILLED中的函数体
            // resolve(123456)

            //如果是异步的调用resolve,
            //那么这里执行到x.then()之前,这个Promise实例化还没有完成,状态时依旧是pending,那么就存起来,等到Promise实例化完成后,调用了resolve时,取出来再调用这个then()的处理逻辑函数
            setTimeout(() => {
                resolve('异步逻辑 123456')
            }, 1000)
        })
    })
    .then((res) => console.log('res', res))
    .then((value) => {
        console.log('then:', value)
        return `1`
    })
    .then((value) => {
        console.log('Second then:', value)
        return new myPromise((resolve, reject) => {
            setTimeout(() => {
                resolve('2. 第二个then的返回')
            }, 500)
        })
    })
    .then((value) => {
        console.log('Third then:', value)
        throw new Error('3. 第三个then会报一个错误')
    })
    .catch((error) => {
        console.error('Catch:', error.message)
    })

文章参考:https://zhuanlan.zhihu.com/p/691259089

Promise详解及面试例题_promise面试-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值