ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

promise基本实现

2021-10-12 11:33:58  阅读:200  来源: 互联网

标签:基本 resolve const 实现 promise2 promise reject return onRejected


Promise基本实现

promise state状态的描述

A promise must be in one of three states: pending, fulfilled, or rejected.
     1),When pending, a promise:may transition to either the fulfilled or rejected state.
     2),When fulfilled, a promise:must not transition to any other state.   must have a value, which must not change.
     3),When rejected, a promise:must not transition to any other state.must have a reason, which must not change.

代码实现

const PENDING = 'pending';
const REJECTED = 'rejected';
const FULFILLED = 'fulfilled';
class Promise{
    constructor(executor) {
        this.status = PENDING;
        this.value = undefined;
        this.reason = undefined;
        const resolve = (value) => {
            if (this.status === FULFILLED) return;
            this.value = value;
            this.status = FULFILLED;
        }
        const reject = (reason) => {
            if (this.status === REJECTED) return;
            this.reason = reason;
            this.status = REJECTED;
        }
        try {
            executor(resolve, reject);
        } catch (e) {
            reject(e)
        }
    }
}

promise then method

描述

  • then返回的必须是一个Promise这样才能实现promise的链式调用
    代码实现如下
then(onFulfilled, onRejected) {
  const promise2 = new Promise1((resolve, reject)=>{
  });
  return promise2
}
  • A promise’s then method accepts two arguments:
promise.then(onFulfilled, onRejected)
  • then中的回调函数的返回值,决定了下一个then的行为:因此要特殊处理
    • then中的参数为函数,then中回调函数的返回值,会传递个下一个then的回调函数中的形参。此时分两种情况
      1,被then中失败函数捕获
      上一个返回的是失败态的Promise或者抛出异常,会被下一个一个then中的失败所捕获
      // Promise失败状态
         Promise.reject('1').then((v)=>{
         	console.log(v); //不走这里
         }, (r)=>{
         console.log(r); // 1
         })
         // 抛出异常错误
         Promise.resolve('1').then(()=>{
         	return throw new Error('error')
         }).then(()=>{
         }, 
         (r)=>{
         console.log(r); //会捕获到上一个then中抛出的错误
         })
      
      2,被then中成功函数捕获;
      上一个返回的成功的promise或者说上一个的失败回调返回的是一个普通的值,会被下一个then的成功所捕获 这里的普通值指的是非promise, 非错误,非异常
      Promise.reject('1').then(()=>{
      }, (r)=>{
      return 'pre then error'
      }).then((v)=>{
      console.log(v); //pre then error捕获上一个then失败函数中返回的普通值
      })
      
    • then中的参数为非函数,
      因为then没有传递值或者说值不是函数,因此值向下传递,也就是常说的值的穿透问题
    // 以下是原生Promise的行为
     Promise.resolve('1').then().then().then((res)=>{
     console.log(res); //1,
     })    
    
    • then中回调函数非返回值为Promise
    // then中返回成功的promise
    Promise.resolve('1').then(v=>{
    	return new Promise((resolve,reject)=>{
    		resolve('ok')
    	})
    }).then((v)=>{
    console.log(v); //ok
    });
    
    //then中返回promise失败态
    Promise.resolve('1').then(v=>{
    	return new Promise((resolve,reject)=>{
    		reject('reject')
    	})
    }).then((v)=>{
       console.log(v, 'onFulfilled'); //不走这里
    },(r)=>{
    	console.log(r, 'onRejected');//reject onRejected
    })
    

then 方法的完整实现

then(onFulfilled, onRejected) {
        const promise2 = new Promise1((resolve, reject) => {
            // 处理参数为非函数的情况
            onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
            // If `onRejected` is not a function and `promise1` is rejected, `promise2` must be rejected with the same reason.
            onRejected = typeof onRejected === 'function' ? onRejected : r => reject(r); 
             // 以下处理Promise状态异步改变的情况
             // 需要then的回调函数暂存起来
             // 需要对then函数的回调函数的返回值做处理 ,因为返回值有可能是Promise
             // onFulfilled or onRejected must not be called until the execution context stack contains only platform code. [3.1].
             // 因此这里需要异步来处理 
            
            if (this.status === PENDING) {
                this.onRejectedCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            const x = onRejected(this.reason);
                            resolvePromise(promise2, x, resolve, reject);
                        } catch (e) {
                            reject(e);
                        }
                    }, 0);
                });
            
                this.onFulfilledCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            const x = onFulfilled(this.value);
                            resolvePromise(promise2, x, resolve, reject);
                        } catch (e) {
                            reject(e);
                        }
                    }, 0);
                });
            }
            // 
            if (this.status === FULFILLED) {
                setTimeout(() => {
                    try {
                        const x = onFulfilled(this.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                }, 0);
            }
            if (this.status === REJECTED) {
               // const x = onRejected(this.reason); // 要求必须要在同意栈中调用
                setTimeout(() => {
                    try {
                        const x = onRejected(this.reason);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                }, 0);
            }
        });
        return promise2;
    }

platform code的意思

Here “platform code” means engine, environment, and promise implementation code. In practice, this requirement ensures that onFulfilled and onRejected execute asynchronously, after the event loop turn in which then is called, and with a fresh stack. This can be implemented with either a “macro-task” mechanism such as setTimeout or setImmediate, or with a “micro-task” mechanism such as MutationObserver or process.nextTick. Since the promise implementation is considered platform code, it may itself contain a task-scheduling queue or “trampoline” in which the handlers are called.

The Promise Resolution Procedure

  • promise2 和x不能相等,如果相等就用TypeError作为reject的值返回
  • 如果x 不是对象或者函数 直接resolve(x);
  • 如果x是对象或者函数 如果let then = x.then
    • 1、如果then为对象则resolve(x)
    • 2、如果then为函数,x为then的this,y为then的value; r为then的reason,直接reject(r)返回失败的结果
      注意 这里的y有可能还是Promise,因此需要对y进行resolvePromise处理;
      还需要注意的是,有可能内部调用promise改变promsie的状态,因此需要做冻结处理,次数再取then的地方加个开关

resolvePromise 方法的实现

const resolvePromise = (promise2, x, resolve, reject) => {
    if (promise2 === x) {
        return reject(new TypeError('不能循环引用'));
    }
    // x为对象或者函数
    if ((x !== null && typeof x === 'object') || typeof x === 'function') {
        let called = false; //加开关防止then中的状态被篡改
        try {
            // x为函数
            let then = x.then;
            if (typeof then === 'function') {
                then.call(x,
                    (y) => {
                        if (called) return;
                        called = true;
                        resolvePromise(promise2, y, resolve, reject); //继续递归处理y
                    },
                    (r) => {
                        if (called) return;
                        called = true;
                        reject(r)
                    },
                )
                //x为对象
            } else {
                resolve(x);
            }
        } catch (e) {
            if (called) return;
            called = true;
            reject(e);
        }
    // x为普通值
    }else {
        resolve(x);
    }
}

Promise基本代码的实现

const PENDING = 'pending';
const REJECTED = 'rejected';
const FULFILLED = 'fulfilled';
const resolvePromise = (promise2, x, resolve, reject) => {
    if (promise2 === x) {
        return reject(new TypeError('不能循环引用'));
    }
    // x为对象或者函数
    if ((x !== null && typeof x === 'object') || typeof x === 'function') {
        let called = false;
        try {
            // x为函数
            let then = x.then;
            if (typeof then === 'function') {
                then.call(x,
                    (y) => {
                        if (called) return;
                        called = true;
                        resolvePromise(promise2, y, resolve, reject)
                    },
                    (r) => {
                        if (called) return;
                        called = true;
                        reject(r)
                    },
                )
                //x为对象
            } else {
                resolve(x);
            }
        } catch (e) {
            if (called) return;
            called = true;
            reject(e);
        }
    // x为普通值
    }else {
        resolve(x);
    }
}
class Promise1 {
    constructor(executor) {
        this.status = PENDING;
        this.value = undefined;
        this.reason = undefined;
        this.onFulfilledCallbacks = [];
        this.onRejectedCallbacks = [];
        const resolve = (value) => {
            if (this.status === FULFILLED) return;
            this.value = value;
            this.status = FULFILLED;
            this.onFulfilledCallbacks.forEach(fn => fn());
        }
        const reject = (reason) => {
            if (this.status === REJECTED) return;
            this.reason = reason;
            this.status = REJECTED;
            this.onRejectedCallbacks.forEach(fn => fn())
        }
        try {
            executor(resolve, reject);
        } catch (e) {
            reject(e)
        }
    }
    then(onFulfilled, onRejected) {
        const promise2 = new Promise1((resolve, reject) => {
            onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
            onRejected = typeof onRejected === 'function' ? onRejected : r => reject(r); // If `onRejected` is not a function and `promise1` is rejected, `promise2` must be rejected with the same reason.
            if (this.status === PENDING) {
                this.onRejectedCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            const x = onRejected(this.reason);
                            resolvePromise(promise2, x, resolve, reject);
                        } catch (e) {
                            reject(e);
                        }
                    }, 0);
                });
                this.onFulfilledCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            const x = onFulfilled(this.value);
                            resolvePromise(promise2, x, resolve, reject);
                        } catch (e) {
                            reject(e);
                        }
                    }, 0);
                });
            }
            if (this.status === FULFILLED) {
                setTimeout(() => {
                    try {
                        const x = onFulfilled(this.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                }, 0);
            }
            if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        const x = onRejected(this.reason);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                }, 0);
            }
        });
        return promise2;
    }
}
Promise1.deferred = function () {
    const dfd = {};
    dfd.promise = new Promise1((resolve, reject) => {
        dfd.resolve = resolve;
        dfd.reject = reject;
    });
    return dfd;
}
module.exports = Promise1;

测试

用promises-aplus-tests这包来测试proise代码

下载包
npm install promises-aplus-tests -g

运行测试文件
promises-aplus-tests 文件名

promise其他方法的实现待续

标签:基本,resolve,const,实现,promise2,promise,reject,return,onRejected
来源: https://blog.csdn.net/qq_38352648/article/details/120708884

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有