Loading...
墨滴

长生

2021/12/26  阅读:45  主题:蔷薇紫

promise学习笔记

学习目标

  • 学习promise规范
  • 手写ES6版本promise
  • 有关promise衍生问题

知识要点

术语

  • Promise,是一个有then方法的对象或者函数
  • thenable,是一个有then方法的函数或者对象
  • value,promise状态成功值,resolve的参数
  • reason,promise状态失败的值,reject的参数
  • exception, 异常值

规范

状态

有三种状态

  • pending(resolve,reject之前的状态)
  • fulfilled(pending --> resolve(value) --> fulfiled, 最终态不可变)
  • rejected(pending --> reject(reason) --> rejected,最终态不可变)

then

promise提供then方法,用来访问最终结果(无论结果是value或者是reason都必须提供)

promise.then(onFulfiled, onRejected)
参数要求

onFulfiled与onReject必须是函数类型,否则应被忽略(透传原值)

onFulfiled特性
  • promise变成fulfilled时,应该调用onFulfilled,参数时value
  • promise变成onFulfiled前无法被调用
  • 仅能调用一次
onRejected特性(同onFulfiled特性)
onFulfilled与onRejected执行环境在微任务
then方法可以被调用多次

例:

const promise = new Promise()
promise.then(cb1,cb2)
promise.then(cb1,cb2)
promise.then(cb1,cb2)
promise.then(cb1,cb2)

回调按照then顺序执行

返回值

then的返回值是个promise,是一个新的promise!

const promise1 = new Promise()
const promise2 = promise1.then(onFulfiled,onRejected)
const promise3 = promise2.then(onFulfiled,onRejected)
  • onFulfiled或者onRejected的执行结果为x,调用resolvePromise()
  • onFulfiled或者onRejected的执行时报错,promise2需要被reject
  • onFulfiled不是函数,promise2以promise1的value,触发fulfilled
  • onRejected不是函数,promise2以promise1的reason,触发rejected
resolvePromise
resolvePromise(promise2,x,resolve,reject)
  • promise2 === x, reject TypeErroe
  • x是一个promise,x随promise状态,举个例子:
const p1 = new Promise((resolve,reject) => {
    resolve('ok')
})
const p2 = new Promise((resolve,reject) => {
    resolve(p1)
})
console.log(p1)
console.log(p2)
//打印顺序为promise{ 'ok' }, promise{ <pending> }, ok

resolve一个Promise时会pending一个循环,因为构造式resolve需要走PromiseResolveThenableJob 的流程

  • x的类型为object/function

手写promise

  1. 构造函数并定义状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class HPromise{
    constructor() {
    }
}
  1. 设置初始状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class HPromise{
    constructor() {
        this.status = PENDING
        this.value = null
        this.reason = null
    }
}
  1. resolve与reject方法
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class HPromise{
    constructor() {
        this.status = PENDING
        this.value = null
        this.reason = null
    }
    resolve(value) {
        this.status = FULFILLED
        this.value = value
    }
    reject(reason){
        this.status = REJECTED
        this.reason = reason
    }
    
}
  1. promise的入参
  • 入参是一个函数,函数接受resolve与reject
  • 初始化promise,就需要执行这个函数
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class HPromise{
    constructor(fn) {
        this.status = PENDING
        this.value = null
        this.reason = null
        //所有方法指向实例,防止this丢失
        try{
            fn(this.resolve.bind(this),this.reject.bind(this))
        } catch(e) {
            this.reject(e)
        }
    }
    resolve(value) {
        this.status = FULFILLED
        this.value = value
    }
    reject(reason){
        this.status = REJECTED
        this.reason = reason
    }
}
  1. 实现then方法
then(onFulfilled, onRejected) {}

需要先对onFulfilled以及onRejected进行检查,如果二者不是function,就会原样返回value或者reason

isFunction(param){
    return typeof param === 'function'
}
then(onFullfilled,onRejected) {
    //不是函数则透传
    const realOnfulfilled = this.isFunction(onFullfilled) ? onFullfilled : (value) => {
        return value
    }
    const realOnRejected = this.isFunction(onRejected)? onRejected: (reason) => {
        throw reason
    }
}

.then的返回值是个promise,根据当前promise状态调用不同函数(只能cover同步的case)

isFunction(param){
        return typeof param === 'function'
    }
then(onFullfilled,onRejected) {
    //不是函数则透传
    const realOnfulfilled = this.isFunction(onFullfilled) ? onFullfilled : (value) => {
        return value
    }
    const realOnRejected = this.isFunction(onRejected)? onRejected: (reason) => {
        throw reason
    }
    const promise2 = new HPromise((resolve,reject) => {
        switch(this.status){
            case FULFILLED:{
                realOnfulfilled()
                break
            }
            case REJECTED:{
                realOnRejected()
                break
            }
        }
    })
    return promise2
}

如果出现异步的情况,是无法直接命中代码中的case,因为此时status可能是pending,所以需要状态监听机制

  • 新建两个数组来存储成功和失败的回调,调用then方法是,如果status是pending,就分别丢入各自数组
FULFILLED_CALLBACK_LIST = []
REJECTED_CALLBACK_LIST = []

then(onFullfilled,onRejected) {
    //不是函数则透传
    const realOnfulfilled = this.isFunction(onFullfilled) ? onFullfilled : (value) => {
        return value
    }
    const realOnRejected = this.isFunction(onRejected)? onRejected: (reason) => {
        throw reason
    }
    const promise2 = new HPromise((resolve,reject) => {
        switch(this.status){
            case FULFILLED:{
                realOnfulfilled()
                break
            }
            case REJECTED:{
                realOnRejected()
                break
            }
            case PENDING: {
                this.FULFILLED_CALLBACK_LIST.push(realOnfulfilled)
                this.REJECTED_CALLBACK_LIST.push(realOnRejected)
            }
        }
    })
    return promise2
}

通过ES6自带的get set方法监听status变化

_status = PENDING
get status() {
        // 不能return this.status,陷入死循环
        return this._status
    }

set status(newStatus) {
    this._status = newStatus
    switch(newStatus){
        case FULFILLED{
            this.FULFILLED_CALLBACK_LIST.forEach((cb) => {
                cb(this.value)
            })
            break
        }
        case REJECTED{
            this.REJECTED_CALLBACK_LIST.forEach((cb) => {
                cb(this.reason)
            })
            break
        }
    }
}

then的返回值

  • 如果onFullfilled或者onRejected抛出异常e,则promise2必须拒绝执行,并返回e
then(onFullfilled,onRejected) {
    //不是函数则透传
    const realOnfulfilled = this.isFunction(onFullfilled) ? onFullfilled : (value) => {
        return value
    }
    const realOnRejected = this.isFunction(onRejected)? onRejected: (reason) => {
        throw reason
    }
    const promise2 = new HPromise((resolve,reject) => {
        const fulfilledMicrotask = () => {
            try{
                realOnfulfilled(this.value)
            }catch(e){
                reject(e)
            }
        }
        const rejectedMicrotask = () => {
            try{
                realOnfRejected(this.value)
            }catch(e){
                reject(e)
            }
        }
        switch(this.status){
            case FULFILLED:{
                realOnfulfilled()
                break
            }
            case REJECTED:{
                realOnRejected()
                break
            }
            case PENDING: {
                this.FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask)
                this.REJECTED_CALLBACK_LIST.push(rejectedMicrotask)
            }
        }
    })
    return promise2
}

如果onFulfilled/onRejected成功返回一个x,则执行resolvePromise方法

const promise2 = new HPromise((resolve,reject) => {
    //onFulfilled/onRejected是微任务,所以用queueMicroTask包裹
    const fulfilledMicrotask = () => {
        queueMicrotask(() => {
            try{
                const x = realOnfulfilled(this.value)
                this.resolvePromise(promise2,x,resolve,reject)
            }catch(e){
                reject(e)
            }
        })
    }
    const rejectedMicrotask = () => {
        queueMicrotask(() => {
            try{
                const x = realOnfRejected(this.value)
                this.resolvePromise(promise2,x,resolve,reject)
            }catch(e){
                reject(e)
            }
        })
    }
    switch(this.status){
        case FULFILLED:{
            realOnfulfilled()
            break
        }
        case REJECTED:{
            realOnRejected()
            break
        }
        case PENDING: {
            this.FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask)
            this.REJECTED_CALLBACK_LIST.push(rejectedMicrotask)
        }
    }
})
    return promise2
}
resolvePromise(promise2,x,resolve,reject){
    if(promise2 === x){
        return reject(new TypeError('The promise and the return value are thesame'))
    }
    if(x instanceof HPromise){
        queueMicrotask(() => {
            x.then(
                (y) => {
                    this.resolvePromise(promise2,y,resolve,reject)
                },
                reject
            )
        })
    }else if(typeof x === 'object' || this.isFunction(x)){
        if(x === null){
            return resolve(x)
        }
        let then = null;
        try{
            then = x.then
        }catch(e){
            return reject(e)
        }
        if(this.isFunction(then)){
            //约定回调次数
            let called = false;
            try{
                then.call(
                    x,
                    (y) => {
                        if(called){
                            return
                        }
                        called = true
                        this.resolvePromise(promise2,y,resolve,reject)
                    },
                    (r) => {
                        if(called){
                            return
                        }
                        called = true
                        reject(r)
                    }
                )

            }catch(e){
                if(called){
                    return
                }
                reject(e)
            }
        }else{
            resolve(x)
        }
    }else{
        resolve(x)
    }
}

长生

2021/12/26  阅读:45  主题:蔷薇紫

作者介绍

长生