PromiseA+规范之手写Promise

news2025/2/28 2:58:16

前言

1、Promise 的意义?

在javascript的世界中,所有代码都是单线程执行的,由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。Ajax可以解决这个问题,但是并不好复用。JQuery的链式调用同样可以解决,每次调用都会返回一个JQuery对象。为了更好的处理Promise 出现了,并且ECMAScript 对其进行了规范。

2、PromiseA+规范是什么?

其实 Promise 规范有很多,如 Promise/APromise/BPromise/D 以及 Promise/A 的升级版 Promise/A+ES6 (也叫ES2015)中采用了 Promise/A+ 规范。

目录

一、术语

二、Promise Status(三种状态及其关系)

   1. pending 

   2. fulfilled 

   3. rejected

   总结:

三、Promise then 方法 及其返回值

四、规范

  1.参数的规范

  2. onFulfilled 特性

  3. onRejected 特性

  4. onFulfilled 和 onRejected 应该是在微任务阶段执行

  5. then方法可以被调用多次

  6. 返回值

  7. resolvePromise

五、实现promise的具体步骤(大概九步);

  1. promise 应该是一个构造函数或者 class        

  2.定义三种状态  

  3.初始化状态

  4.实现 resolve 和 reject

  5.对于实例化 promise 时的入参处理

  6.实现 then 方法

   7. then 的返回值 

  8. resolvePromise 方法的具体实现

  9. onFulfilled 和 onRejected 是在微任务中执行的

到这里我们 简单的 promise 已经实现了,可以简单的去测试一下


一、术语

1. promise 有 then 方法的对象或者函数;

2. thenable 是一个有 then 方法的对象或者是函数;

3. value promise 状态成功时的值, resolve(value),可以是任何数据类型(String Number Boolean undefined thenable promise);

4. reason promise 状态失败时的值, reject(reason);

二、Promise Status(三种状态及其关系)

   1. pending 

        1.1 初始状态,可以改变.

        1.2 在 resolve 和 reject 之前都处于这个状态.

        1.3 通过resolve -->  fulfilled 状态.

        1.4 通过reject --> rejected 状态.

   2. fulfilled 

        2.1 最终态,不可改变.

        2.2 一个 promise 被 resolve 改变成这个状态.

        2.3 必须通过一个 value 值,成功以后的值.

   3. rejected

        3.1 最终态,不可改变;

        3.2 一个promise 被 reject 改变成这个状态;

        3.3 必须拥有一个 reason ,也就是失败的原因;

   总结:

         pending --> resolve(value)  -->  fulfilled 

         pending --> reject(reason)  --> rejected 

三、Promise then 方法 及其返回值

promise 应该(promiseA+规范,规范提出了,所以用的应该)提供一个 then 方法, 用来访问最终结果, 无论 value 还是 reason.

promise.then(onFuilled,onRejected)

四、规范

  1.参数的规范

        1.1 onFulfilled 必须是函数类型, 如果不是函数类型 ,应该被忽略(这里的忽略是指给一个默认值,并不是真正意义上的忽略);

        1.2 onRejected  必须是函数类型, 如果不是函数类型 ,应该被忽略(同上);

  2. onFulfilled 特性

        2.1 在 promise 变成 fulfilled 时, 应该调用 onFulfilled ,参数是 value;(onFulfilled 的执行时机?)

        2.2 在 promise 变成 fulfilled 之前, 不应该调用 onFulfilled;

        2.3 只能被调用一次,可以注册若干个回调函数(promise.then().then().then()....);(怎么实现只调用一次?)

  3. onRejected 特性

        3.1 在 promise 变成 rejected 时, 调用 onRejected ,参数是reason;

        3.2 在 promise 变成 rejected 之前,不应该调用 onRejected.

        3.3 只能调用一次

  4. onFulfilled 和 onRejected 应该是在微任务阶段执行

        为什么微任务阶段执行?

        一定要等前面的任务执行完,才进行调用. 微任务是在一轮宏任务执行完之后执行;

  5. then方法可以被调用多次

        5.1 promise 变成 fulfilled 之后 , 所有的 onFulfilled 回调都应该按照注册的顺序执行,也可以理解为按照 .then() 的顺序执行;

        例:

promise.then(onFulfilled , onRejected).then(onFulfilled1 => ( )).then(....)

        5.2 promise 变成 rejected 之后 , 所有的 onRejected 回调都应该按照注册的顺序执行,也可以理解为按照 .then() 的顺序执行;

  6. 返回值

        规范里定义 then 应该返回一个promise 

const promise2 = promise( onFulfilled , onRejected );

        6.1 onFulfilled 或 onRejected 执行结果 为 x(任何东西:值或者 promise),调用resolvePromise;

        6.2 onFulfilled 或 onRejected 执行过程中抛出了异常,promise2需要被 reject; 

        6.3 如果 onFulfilled 不是一个函数,promise2 应该以 promise1 的value 触发 fulfilled;

        6.4. 如果 onRejected 不是一个函数,promise2 应该以 promise1 的reason 触发 fulfilled

  7. resolvePromise

        promise2:当前第一个promise 的返回值;

        X:无论是 onFulfilled 还是 onRejected 的执行结果

        resolve、reject :变更方法        

resolvePromise(promise2, x, resolve, reject)

        7.1 如果promise2 和 x 相等 reject typeError;

        7.2 如果 x 是一个 promise 

                如果 x 是pending 状态 ,promise 必须要在pending 状态,直到 x 的状态变更。

                如果 x 是 fulfilled ,value -->  fulfilled

                如果 x 是 rejected ,reason -->  rejected

        7.3 如果 x 是一个 Object 或者 Function 

                去获取 x.then(),如果报错,reject reason 

                如果 then 是一个函数,then.call(x, resolvePromiseFn, rejectPromiseFn)

                为什么用 call 改变 this 指针,或者then的时候可能会导致 指针指向改变,所以用 call 继续执行之前的逻辑

五、实现promise的具体步骤(大概九步);

  1. promise 应该是一个构造函数或者 class        

const promise = new promise();

新建promise-class.js,今天我们用class 来实现promise

class MPromise{
    constructor(){
    
    }
}

  2.定义三种状态  

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';


class MPromise{
    constructor(){
    
    }
}

  3.初始化状态

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';


class MPromise{
    constructor(){
        this.status = PENDING;
        this.value = null;
        this.reason = null;
    }
}

  4.实现 resolve 和 reject

        4.1 这两个方法要更改 status,从 pending 变成 fulfilled / rejected

        4.2 入参分别是 value 和 reason

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';


class MPromise{
    constructor(){
        this.status = PENDING;
        this.value = null;
        this.reason = null;
    }

    resolve(value){
        // 最终态不可被改变,所以需要加一个判断
        // 只有当 status 为初始态的时候才可以改变
        if(this.status === PENDING){
            this.status = FULFILLED;
            this.value = value;
        }
        
    }

    reject(reason){
        if(this.status === PENDING){
            this.status = REJECTED;
            this.reason= reason;
        }
        
    }
}

  5.对于实例化 promise 时的入参处理

        5.1 入参是一个函数  

const promise = new promise((resolve,reject)=>{
    
})

        5.2 接受 resolve 和 rejected 两个参数

        5.3 初始化 promise 就要同步执行这个函数,并且有任何报错都要通过 reject 抛出

const promise = new promise((resolve,reject)=>{
    axios.get('www.baidu.com')
}).then(result=>{
    // 这里需要注意一下,创建之处就已经执行了
    // 并不是调用 .then()  的时候才会执行
    // 同步执行的,所以可以缓存一个 promise ,需要用到的时候直接取值即可
    // 获取的时候 并不会再次发送请求,所以不用担心流量的偷跑 与 性能的问题
   })
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';


class MPromise{
    constructor(fn){
        this.status = PENDING;
        this.value = null;
        this.reason = null;

        //需要里面调用,有报错需要立马抛出
        try{
            // 考虑严谨性,更改 this 指向为当前环境
            fn(this.resolve.bind(this), this.reject.bind(this));
        } catch(e){
            this.reject(e)
        }
    }

    resolve(value){
        // 最终态不可被改变,所以需要加一个判断
        // 只有当 status 为初始态的时候才可以改变
        if(this.status === PENDING){
            this.status = FULFILLED;
            this.value = value;
        }
        
    }

    reject(reason){
        if(this.status === PENDING){
            this.status = REJECTED;
            this.reason= reason;
        }
        
    }
}

  6.实现 then 方法

        6.1 then 接受 两个参数 onFulfilled 和 onRejected 

        6.2 检查并处理参数,如果参数不是一个 function 就忽略

        6.3 需要根据当前 promise 的状态,调用不同的函数

                如果 promise 是 fulfilled 的时候 我们需要调用 onFulfilled

                如果 promise 是 rejected 的时候 我们需要调用 onRejected

        6.4 首先拿到所有的回调,因为状态发生变化的时候,无论是成功还是失败我们都需要去执行对应的 回调;新建两个数组 ,分别存储成功和失败的回调,调用 then 的时候,如果还是pending 状态就存入数组。

        6.5 在 status 发生变化的时候,执行对应的回调。这里用 es6 的 getter setter,监听 status 的变化,在发生变化的时候来做对应的操作;

这里说一下如果是ES5没有 getter setter,那么我们可以直接在resolve 和 reject 两个方法里面去更改 status 的状态;使用getter setter 后面可以更好的维护,不用关注 status ;

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';


class MPromise{
    //直接生命两个数组即可,这里的数组不会被修改 只会被push进来
    // 状态完成的 list
    FULFILLED_CALLBACK_LIST = [];
    // 状态失败的 list
    REJECTED_CALLBACK_LIST = [];
    // 存储初始化 status 
    _status = PENDING;
    
    constructor(fn){
        this.status = PENDING;
        this.value = null;
        this.reason = null;

        //需要里面调用,有报错需要立马抛出
        try{
            // 考虑严谨性,更改 this 指向为当前环境
            fn(this.resolve.bind(this), this.reject.bind(this));
        } catch(e){
            this.reject(e)
        }
    }


    get status(){
        // 所有真实的 status 
        return this._status;
    }

    set status(newStatus){
        this._status = newStatus;

        // 判断不同的状态 执行不同的逻辑
        switch(newStatus){
            case FULFILLED: {
                // then 方法已经判断过是不是function 所以这里不需要判断
                // 在 status 发生变化的时候,执行对应的回调。
                this.FULFILLED_CALLBACK_LIST.forEach(callback=>{
                     callback(this.value)
                });
                break;
            }
            case REJECTED: {
                this.REJECTED_CALLBACK_LIST.forEach(callback=>{
                     callback(this.reason)
                });
                break;
            }
        }
    }


    resolve(value){
        // 最终态不可被改变,所以需要加一个判断
        // 只有当 status 为初始态的时候才可以改变
        if(this.status === PENDING){
            this.value = value;
            this.status = FULFILLED;

        }
        
    }

    reject(reason){
        if(this.status === PENDING){
            this.reason= reason;
            this.status = REJECTED;

        }
        
    }

    then(onFulfilled, onRejected){
        const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : (value) => value
        const rejectedFn = this.isFunction(onRejected) ? onRejected : (reason) => throw(reason)
        
        switch(this.status){
            case FULFILLED: {
                fulFilledFn(this.value);
                break;
            }
            case REJECTED: {
                rejectedFn(this.reason);
                break;
            }
            case PENDING: {
                this.FULFILLED_CALLBACK_LIST.push(fulFilledFn);
                this.REJECTED_CALLBACK_LIST.push(rejectedFn);
                break;
            }
        }
        
    }

    isFunction(param){
        return typeof param === 'function';
    }
}

   7. then 的返回值 

        7.1 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,那么新的 promise 必须 reject e;

        7.2 返回值应该是一个 promise

        7.3 如果 onFulfilled 不是函数,且 promise1 成功(resolve 状态)执行,promise2 必须返回同样的状态和value;(规范里定义的)

        7.4 如果 onRejected 不是函数,且 promise1 拒绝执行,promise2 必须返回同样的状态和 reason;

        7.5 如果 onFulfilled 或者 onRejected 返回一个值 x ,运行 resolvePromise 方法。

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';


class MPromise{
    //直接生命两个数组即可,这里的数组不会被修改 只会被push进来
    // 状态完成的 list
    FULFILLED_CALLBACK_LIST = [];
    // 状态失败的 list
    REJECTED_CALLBACK_LIST = [];
    // 存储初始化 status 
    _status = PENDING;
    
    constructor(fn){
        this.status = PENDING;
        this.value = null;
        this.reason = null;

        //需要里面调用,有报错需要立马抛出
        try{
            // 考虑严谨性,更改 this 指向为当前环境
            fn(this.resolve.bind(this), this.reject.bind(this));
        } catch(e){
            this.reject(e)
        }
    }


    get status(){
        // 所有真实的 status 
        return this._status;
    }

    set status(newStatus){
        this._status = newStatus;

        // 判断不同的状态 执行不同的逻辑
        switch(newStatus){
            case FULFILLED: {
                // then 方法已经判断过是不是function 所以这里不需要判断
                // 在 status 发生变化的时候,执行对应的回调。
                this.FULFILLED_CALLBACK_LIST.forEach(callback=>{
                     callback(this.value)
                });
                break;
            }
            case REJECTED: {
                this.REJECTED_CALLBACK_LIST.forEach(callback=>{
                     callback(this.reason)
                });
                break;
            }
        }
    }


    resolve(value){
        // 最终态不可被改变,所以需要加一个判断
        // 只有当 status 为初始态的时候才可以改变
        if(this.status === PENDING){
            this.value = value;
            this.status = FULFILLED;

        }
        
    }

    reject(reason){
        if(this.status === PENDING){
            this.reason= reason;
            this.status = REJECTED;

        }
        
    }

    then(onFulfilled, onRejected){
        const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : (value) => value
        const rejectedFn = this.isFunction(onRejected) ? onRejected : (reason) => throw(reason)
        
        //如果 onFulfilled 或者 onRejected 抛出一个异常 e ,那么新的 promise 必须 reject e;
        const fulFilledFnWitchCatch = (resolve, reject, newPromise) => {
            try{
                // 不是一个函数 就直接resolve ,因为有返回值了,所以需要判断
                if(!this.isFunction(onFulfilled)){
                    resolve(this.value)
                }else{
                    const x = fulFilledFn(this.value);
                    this.resolvePromise(newPromise, x, resolve, reject);
                }
            }catch(e) {
                reject(e)
            }
        }
    
        
        const rejectedFnWitchCatch = (resolve, reject, newPromise) => {
            try{
                if(!this.isFunction(onRejected)){
                    reject(this.reason);
                }else{
                    const x =  rejectedFn(this.reason);
                    this.resolvePromise(newPromise, x, resolve, reject); 
                }
                   
            }catch(e) {
                reject(e)
            }
        }

        switch(this.status){
            // then 的返回值是一个promise
            case FULFILLED: {
                const newPromise = new MPromise((resolve, reject) => fulFilledFnWitchCatch(resolve, reject, newPromise));
                return newPromise;
            }
            case REJECTED: {
                const newPromise = new MPromise((resolve, reject) => rejectedFnWitchCatch(resolve, reject, newPromise));
                return newPromise;
            }
            case PENDING: {
                const newPromise = new MPromise((resolve, reject) => {
                    this.FULFILLED_CALLBACK_LIST.push(() => fulFilledFnWitchCatch(resolve, reject, newPromise));
                    this.REJECTED_CALLBACK_LIST.push(() => rejectedFnWitchCatch(resolve, reject, newPromise));         
                });
                return newPromise;
            }
        }
        
    }
    
    // 规范里定义resolvePromise 需要接受一个 newPromise
    // resolvePromise 函数的意义,就是对promise 各种值的处理
    // 让 promise 可以返回一个结果,无论是 resolve 还是 reject
    resolvePromise(newPromise, x, resolve, reject){
        
    }
    
    
    isFunction(param){
        return typeof param === 'function';
    }
}

  8. resolvePromise 方法的具体实现

        resolvePromise 函数的意义,就是对promise 各种值的处理, 让 promise 可以返回一个结果,无论是 resolve 还是 reject

        8.1 如果 promise2 和 x 相等

        8.1 如果 x 是一个promise ,promise 必须要在 pending 状态,直到 x 的状态变更

                如果 x fulfilled ,value --->  fulfilled

                如果 x rejected ,reason ----> rejected

        8.1 如果 x 是一个 object / Function

                去获取 const then = x.then, reject reason

                then 是一个函数,then.call(x,resolvePromiseFn, rejectPromiseFn)

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';


class MPromise{
    //直接生命两个数组即可,这里的数组不会被修改 只会被push进来
    // 状态完成的 list
    FULFILLED_CALLBACK_LIST = [];
    // 状态失败的 list
    REJECTED_CALLBACK_LIST = [];
    // 存储初始化 status 
    _status = PENDING;
    
    constructor(fn){
        this.status = PENDING;
        this.value = null;
        this.reason = null;

        //需要里面调用,有报错需要立马抛出
        try{
            // 考虑严谨性,更改 this 指向为当前环境
            fn(this.resolve.bind(this), this.reject.bind(this));
        } catch(e){
            this.reject(e)
        }
    }


    get status(){
        // 所有真实的 status 
        return this._status;
    }

    set status(newStatus){
        this._status = newStatus;

        // 判断不同的状态 执行不同的逻辑
        switch(newStatus){
            case FULFILLED: {
                // then 方法已经判断过是不是function 所以这里不需要判断
                // 在 status 发生变化的时候,执行对应的回调。
                this.FULFILLED_CALLBACK_LIST.forEach(callback=>{
                     callback(this.value)
                });
                break;
            }
            case REJECTED: {
                this.REJECTED_CALLBACK_LIST.forEach(callback=>{
                     callback(this.reason)
                });
                break;
            }
        }
    }


    resolve(value){
        // 最终态不可被改变,所以需要加一个判断
        // 只有当 status 为初始态的时候才可以改变
        if(this.status === PENDING){
            this.value = value;
            this.status = FULFILLED;

        }
        
    }

    reject(reason){
        if(this.status === PENDING){
            this.reason= reason;
            this.status = REJECTED;

        }
        
    }

    then(onFulfilled, onRejected){
        const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : (value) => value
        const rejectedFn = this.isFunction(onRejected) ? onRejected : (reason) => throw(reason)
        
        //如果 onFulfilled 或者 onRejected 抛出一个异常 e ,那么新的 promise 必须 reject e;
        const fulFilledFnWitchCatch = (resolve, reject, newPromise) => {
            try{
                // 不是一个函数 就直接resolve ,因为有返回值了,所以需要判断
                if(!this.isFunction(onFulfilled)){
                    resolve(this.value)
                }else{
                    const x = fulFilledFn(this.value);
                    this.resolvePromise(newPromise, x, resolve, reject);
                }
            }catch(e) {
                reject(e)
            }
        }
    
        
        const rejectedFnWitchCatch = (resolve, reject, newPromise) => {
            try{
                if(!this.isFunction(onRejected)){
                    reject(this.reason);
                }else{
                    const x =  rejectedFn(this.reason);
                    this.resolvePromise(newPromise, x, resolve, reject); 
                }
                   
            }catch(e) {
                reject(e)
            }
        }

        switch(this.status){
            // then 的返回值是一个promise
            case FULFILLED: {
                const newPromise = new MPromise((resolve, reject) => fulFilledFnWitchCatch(resolve, reject, newPromise));
                return newPromise;
            }
            case REJECTED: {
                const newPromise = new MPromise((resolve, reject) => rejectedFnWitchCatch(resolve, reject, newPromise));
                return newPromise;
            }
            case PENDING: {
                const newPromise = new MPromise((resolve, reject) => {
                    this.FULFILLED_CALLBACK_LIST.push(() => fulFilledFnWitchCatch(resolve, reject, newPromise));
                    this.REJECTED_CALLBACK_LIST.push(() => rejectedFnWitchCatch(resolve, reject, newPromise));         
                });
                return newPromise;
            }
        }
        
    }
    
    // 规范里定义resolvePromise 需要接受一个 newPromise
    // resolvePromise 函数的意义,就是对promise 各种值的处理
    // 让 promise 可以返回一个结果,无论是 resolve 还是 reject
    resolvePromise(newPromise, x, resolve, reject){
        if(newPromise === x){
            // 返回一个错误信息,信息无所谓什么都可以
            // 为什么要 reject 一个错误信息,因为如果 newPromise 和 x 相等会相互调用,形成一个死循环
            return reject(new TypeError('Type Error,Please....'))
        }

        if(x instanceOf MPromise){
        //如果是promise 肯定有then 方法
            
            x.then(y =>{
                this.resolvePromise(newPromise, y, resolve, reject)
            }, reject);        

        } else if(typeof x === 'object' || this.isFunction(x)){
            // typeof null 也是 object,所以需要加判断
            if(x === null){
                return resolve(x)
            }
        
            // 按照规范的语义化写法
            let then = null;
            try{
                then = x.then;
            }catch(error){
                return reject(error);
            }

            if(this.isFunction(then)){
                // 规范中要求 then 方法 只能被调用一次
                // 定义一个 called 变量,标识是否被调用
    
                let called = false;
                try{
                    // 为了不发生异常错误,更换then 的 this 指向 为x
                    then.call(
                        x,
                        (y) =>{
                            if(called){
                                return;
                            }
                            called = true;
                            // 简单的递归,目的就是找到所有的 x 
                            this.resolvePromise(newPromise, y, resolve, reject);
                        },
                        (r) =>{
                            if(called){
                                return;
                            }
                            called = true;
                            reject(r);
                        }

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

        } else {
            resolve(x)
        }
    }
    
    
    isFunction(param){
        return typeof param === 'function';
    }
}

  9. onFulfilled 和 onRejected 是在微任务中执行的

        如何实现?

        queueMicrotask(()=>{});传入一个函数,放在微任务里面调用

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';


class MPromise{
    //直接生命两个数组即可,这里的数组不会被修改 只会被push进来
    // 状态完成的 list
    FULFILLED_CALLBACK_LIST = [];
    // 状态失败的 list
    REJECTED_CALLBACK_LIST = [];
    // 存储初始化 status 
    _status = PENDING;
    
    constructor(fn){
        this.status = PENDING;
        this.value = null;
        this.reason = null;

        //需要里面调用,有报错需要立马抛出
        try{
            // 考虑严谨性,更改 this 指向为当前环境
            fn(this.resolve.bind(this), this.reject.bind(this));
        } catch(e){
            this.reject(e)
        }
    }


    get status(){
        // 所有真实的 status 
        return this._status;
    }

    set status(newStatus){
        this._status = newStatus;

        // 判断不同的状态 执行不同的逻辑
        switch(newStatus){
            case FULFILLED: {
                // then 方法已经判断过是不是function 所以这里不需要判断
                // 在 status 发生变化的时候,执行对应的回调。
                this.FULFILLED_CALLBACK_LIST.forEach(callback=>{
                     callback(this.value)
                });
                break;
            }
            case REJECTED: {
                this.REJECTED_CALLBACK_LIST.forEach(callback=>{
                     callback(this.reason)
                });
                break;
            }
        }
    }


    resolve(value){
        // 最终态不可被改变,所以需要加一个判断
        // 只有当 status 为初始态的时候才可以改变
        if(this.status === PENDING){
            this.value = value;
            this.status = FULFILLED;

        }
        
    }

    reject(reason){
        if(this.status === PENDING){
            this.reason= reason;
            this.status = REJECTED;

        }
        
    }

    then(onFulfilled, onRejected){
        const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : (value) => value
        const rejectedFn = this.isFunction(onRejected) ? onRejected : (reason) => throw(reason)
        
        //如果 onFulfilled 或者 onRejected 抛出一个异常 e ,那么新的 promise 必须 reject e;
        const fulFilledFnWitchCatch = (resolve, reject, newPromise) => {
            queueMicrotask(() => {
                try{
                    // 不是一个函数 就直接resolve ,因为有返回值了,所以需要判断
                    if(!this.isFunction(onFulfilled)){
                        resolve(this.value)
                    }else{
                        const x = fulFilledFn(this.value);
                        this.resolvePromise(newPromise, x, resolve, reject);
                    }
                }catch(e) {
                    reject(e)
                }
            });
        }
    
        
        const rejectedFnWitchCatch = (resolve, reject, newPromise) => {
            queueMicrotask(() => {
                try{
                    if(!this.isFunction(onRejected)){
                        reject(this.reason);
                    }else{
                        const x =  rejectedFn(this.reason);
                        this.resolvePromise(newPromise, x, resolve, reject); 
                    }
                }catch(e) {
                    reject(e)
                }
            });
        }

        switch(this.status){
            // then 的返回值是一个promise
            case FULFILLED: {
                const newPromise = new MPromise((resolve, reject) => fulFilledFnWitchCatch(resolve, reject, newPromise));
                return newPromise;
            }
            case REJECTED: {
                const newPromise = new MPromise((resolve, reject) => rejectedFnWitchCatch(resolve, reject, newPromise));
                return newPromise;
            }
            case PENDING: {
                const newPromise = new MPromise((resolve, reject) => {
                    this.FULFILLED_CALLBACK_LIST.push(() => fulFilledFnWitchCatch(resolve, reject, newPromise));
                    this.REJECTED_CALLBACK_LIST.push(() => rejectedFnWitchCatch(resolve, reject, newPromise));         
                });
                return newPromise;
            }
        }
        
    }
    

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


    // 规范里定义resolvePromise 需要接受一个 newPromise
    // resolvePromise 函数的意义,就是对promise 各种值的处理
    // 让 promise 可以返回一个结果,无论是 resolve 还是 reject
    resolvePromise(newPromise, x, resolve, reject){
        if(newPromise === x){
            // 返回一个错误信息,信息无所谓什么都可以
            // 为什么要 reject 一个错误信息,因为如果 newPromise 和 x 相等会相互调用,形成一个死循环
            return reject(new TypeError('Type Error,Please....'))
        }

        if(x instanceOf MPromise){
        //如果是promise 肯定有then 方法
            
            x.then(y =>{
                this.resolvePromise(newPromise, y, resolve, reject)
            }, reject);        

        } else if(typeof x === 'object' || this.isFunction(x)){
            // typeof null 也是 object,所以需要加判断
            if(x === null){
                return resolve(x)
            }
        
            // 按照规范的语义化写法
            let then = null;
            try{
                then = x.then;
            }catch(error){
                return reject(error);
            }

            if(this.isFunction(then)){
                // 规范中要求 then 方法 只能被调用一次
                // 定义一个 called 变量,标识是否被调用
    
                let called = false;
                try{
                    // 为了不发生异常错误,更换then 的 this 指向 为x
                    then.call(
                        x,
                        (y) =>{
                            if(called){
                                return;
                            }
                            called = true;
                            // 简单的递归,目的就是找到所有的 x 
                            this.resolvePromise(newPromise, y, resolve, reject);
                        },
                        (r) =>{
                            if(called){
                                return;
                            }
                            called = true;
                            reject(r);
                        }

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

        } else {
            resolve(x)
        }
    }
    
    
    isFunction(param){
        return typeof param === 'function';
    }
}

到这里我们 简单的 promise 已经实现了,可以简单的去测试一下

const test = new MPromise((resolve, reject) => {
    setTimeout(()=>{
        resolve(1111);
    },1000)
}).then(console.log)



const test = new MPromise((resolve, reject) => {
    setTimeout(()=>{
        reject(1111);
    },1000)
}).then((value) => {
    console.log('完成' + value)
}).catch((reason) => {
    console.log('报错' + reason)
})

 

 到这里 实例方法 resolve reject 已经 加完了,静态方法后期给大家补充;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/405096.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【flask进阶】Flask实现自定义分页(python web通用)

📋 个人简介 💖 作者简介:大家好,我是阿牛,全栈领域新星创作者。😜🎉 支持我:点赞👍+收藏⭐️+留言📝📣 系列专栏:flask框架快速入门🍁💬格言:要成为光,因为有怕黑的人!🔥 目录 📋 个人简介前言后端后端思路后端代码前端前端思路前端代码

微信小程序 - 完美解决 web-view 公众号文章或第三方网站分享转发后,打开提示 “无法打开该页面,不支持打开” 或 “页面不存在”(IOS 苹果系统打开是空白页,安卓系统会有提示)超详细排查

前言 由于出现这种问题的原因有很多种,绝对不像其他文章教程那样无效,本文提供了超级详细的排查思路与解决方案。 本文从 [初步排查] 到 [代码排查],完美解决 因各种原因导致 webview 页面分享后,用户打不开提示错误 这类问题, 您只需要按照排查步骤一步一步的走,从检查…

echarts入门教程(超级详细带案例)

一.echarts的介绍 1.echarts是一款基于JavaScript的数据可视化图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表。ECharts最初由百度团队开源,并于2018年初捐赠给Apache基金会,成为ASF孵化级项目…

防抖、节流的介绍

目录 一、什么时候要用到防抖节流 输入框连续输入的案例 滚动条案例 二、什么是防抖、节流 使用防抖来解决输入框案例造成的浪费现象: 使用节流来解决滚动条案例造成的浪费现象: 三、总结 一、什么时候要用到防抖节流 针一类类快速连续触发和不可控…

不会前端没事,用GWT Boot和Spring Boot构建Web程序

本文介绍了一种使用Java构建Web应用程序的方式,其中GWT或者J2CL是必不可少的,另外还有多个UI框架可以配套使用,比如Domino UI、VueGWT、GWT Material Design (GMD),React4J、WebFX,还有一些活跃低的框架GWTBootstrap3、…

2023前端面试题及答案整理(Vue)

watch 和 computed 区别 watch 是监听动作,computed 是计算属性watch 没缓存,只要数据变化就执行。computed 有缓存,只在属性变化的时候才去计算。watch 可以执行异步操作,而 computed 不能watch 常用于一个数据影响多个数据&…

Vue项目部署上线全过程(保姆级教程)

Vue项目部署上线全过程(保姆级教程) 上线前准备 1.先在vue.config.js文件中配置反向代理解决跨域请求问题 const { defineConfig } require(vue/cli-service) module.exports defineConfig({transpileDependencies: true,devServer: {proxy: {"…

web渗透测试学习路线

web渗透学习路线 文章目录*web渗透学习路线*前言一、web渗透测试是什么?二、web渗透步骤1.前期工作2.中期提高3.后期打牢总结前言 本文整理的学习路线,清晰明了,重点分明,能快速上手实践,相信想学的同学们都能轻松学完…

vue实现文件上传

这里使用的是vue2,ui用的是element ui ,后期有时间会更新vue3版本的。前端文件上传使用的是ui框架中的Upload的图片列表缩略图,喜欢别的样式可以直接更改。看图注fileChange():方法可以直接获取到上传文件的状态及可以直接拿到图片的值可以新…

Redux中进行异步操作(网络请求)的方案

文章目录Redux中的异步操作组件中进行异步操作redux中进行异步操作Redux中的异步操作 在之前简单的案例中,redux中保存的counter是一个本地定义的数据 我们可以直接通过同步的操作来dispatch action,state就会被立即更新。 但是真实开发中,r…

Vue3 项目创建

安装 1、安装node vue 3需要node10以上版本 node官网下载地址以往的版本 | Node.js 2、安装vue/cli 如果已经全局安装过旧版本的vue-cli npm uninstall vue-cli -g //yarn global remove vue-cli 然后安装 npm install -g vue/cli //yarn global add vue/cli 为什…

使用vue,实现前端导入excel数据

文章目录 前言一、引入组件二、封装导入功能的组件 1.编写组件template2.获取数据3.调用接口把数据传给后端三、总结前言 继前边的vue的导出功能后,自己又去在网上搜了vue导入excel一些文章,自己通过对代码的整理和调整,实现了vue导入excel的…

Vue3报错:Property “xxx“ was accessed during render but is not defined on instance.

Vue3报错:Property “xxx” was accessed during render but is not defined on instance. 翻译:属性“xxx”在呈现期间被访问,但没有在实例上定义。 其实就是在模板上有,但是在script上没有定义 很多同学跟说这不是报错&#…

Vue2-基础知识

目录 一.vue简介 1.概念 2.特性 (1)数据驱动视图 (2)双向数据绑定 3.MVVM 4.基本使用步骤 5.调试工具 二.vue基础 1.指令 (1)内容渲染指令 (2)属性绑定指令 (3)事件绑定指令 (4)双向绑定指令 ​编辑(5)条件渲染指令 (6)列表渲染指令 2.过滤器 (1)概念 (2)分…

HTML5设计注册/登录界面

学习目标: 掌握 HTML5入门知识掌握 CSS入门知识学习内容: 掌握 HTML5基本语法掌握CSS基本语法HTML5网页设计掌握块级标签掌握行内标签表单的使用方法iput常用属性学习时间: 周一至周五早上 7 点—晚上9点周六上午 9 点-晚上9点周日下午 3 …

Redux的基本使用过程详解

文章目录Redux的使用过程Redux测试项目的搭建Redux的基本使用步骤Redux目录的结构划分React的三大原则Redux的使用过程 Redux测试项目的搭建 1.创建一个新的项目文件夹:learn-redux # 执行初始化操作 npm init -y或yarn init -y # 安装redux:npm install redux --save或yarn …

Tomcat使用教程(超详细)

文章目录Tomcat学习笔记1、Tomcat概述2、Tomcat的基本使用2.1 基本操作2.1.1 安装2.1.2 卸载2.1.3 配置2.1.4 启动2.1.5 部署2.1.6 关闭3、IDEA中使用Maven创建Web项目3.0 Web项目目录结构介绍3.1 使用骨架创建Web项目3.2 直接创建web项目4、Web项目部署4.1 集成本地的Tomcat4.…

别找了诸位 【十二款超级好用的谷歌插件都在这】(确定不来看看?)

目录 🌌前言: 🌇第一款、油猴插件 🌇第二款、Adblock Plus - 免费的广告拦截器 🌇第三款、谷歌清理大师(CleanMaster) 🌇第四款、google翻译 🌇第五款、OneTab &a…

vue的双击事件(dbclick的使用)

双击事件(dblclick) vue事件中基于点击事件,有一个双击事件,通过dblclick事件触发。 语言:vue3/Ts 函数库:vueuse 1、需求分析 双击事件触发; 在双击时隐藏对应文字元素; 展示输入框; 输入…

Vue系列之插槽(slot)详解

文章の目录1、什么是插槽了2、插槽的分类3、默认插槽的使用3.1、语法3.2、示例4、具名插槽的使用4.1、什么是具名插槽4.2、语法4.3、示例4.4、缩写5、作用域插槽的使用5.1、什么是作用域插槽了5.2、语法5.3、示例6、动态插槽名6.1、什么是动态插槽名6.2、示例写在最后Vue 版本&…