实现一个Promise

实现一个Promise

参考:

在开发过程中,已经使用的非常多了;多以解决ajax获取数据回调的问题;
基本使用:

getData().then(res=>{
  console.log(res);
})
function getData(){
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      resolve({
        name:"admin",
        age:"23"
      });
    });
  })
}

Promise不是新技术,它只是一个规范,任何人都可以按照此规范去实现自己的处理逻辑;并应用于自己的代码中。

基本特性
  • Promise是一个对象或者函数,它拥有的方法必须符合Promise规范。
  • 拥有一个then方法,具有thenable特性(伪Promise对象);
  • 返回值resolve是合法的javascript值,包括undefined/Promise实例/thenable对象;
  • 有被拒绝rejected的原因;

状态
在某一时刻必须是三个状态之一:pending等待期/fulfilled完成/rejected被拒绝(不等于失败)
状态转换:

  • pending转换为其他两个状态之一:
pending
fulfilled
rejected
  • 转换为fulfilled状态后,状态不会在发生变化;必须有返回值;
  • 转换为rejected状态后,状态不会在发生变化;必须有原因;

then方法
必须存在then方法,用来访问状态变化之后的返回值(被拒原因);
promise.then(onFulfilled,onRejected)

  • 可选参数;onFulfilled,onRejected必须是一个函数;不是则被忽略; ::

  • 状态变化为fulfilled时,调用onFulfilled函数一次 ,将返回值作为第一个参数;

  • 状态变化为rejected时,调用onRejected函数一次,将被拒原因作为第一个参数;

  • onFulfilled/onRejected仅作为函数调用,内部无this对象;

  • 有多个Promise实例被执行时,按照他们原有的顺序访问结果(调用多次then);比如Promise.all()

  • 调用promise.then(onFulfilled,onRejected)必须返回一个Promise实例:

    • 调用then()方法返回一个有效值,则这个值作为新Promise实例状态为fulfilled的返回值;
    • 调用then()方法代码执行错误,或手动throw一个Exception,则这个e作为新Promise实例状态为rejected的原因;
    • onFulfilled不是有效函数,则将原Promise实例状态转换后的返回值作为返回值;
    • onRejected不是有效函数,则将原Promise实例状态转换后的被拒原因作为实例被拒原因;

Promise返回结果处理流程
针对返回值x做一下假设,并按照此流程处理:

x有可能是一个对象或者函数,自身实现了then方法,属于不合规的实现,也需按照流程处理。

promise表示当前实例,x表示返回值resolve; 官方表示[[Resolve]](promise,x)
在这里插入图片描述
说明:

  1. 使用then方法操作是一种异步调用,也就是如果由于一些因素导致状态还处于pending,我们调用then就不会立即拿到结果;那它内部就必须等待到结果才能返回,使用setTimeout延时处理,如果获得了结果,就执行。
  2. this对象不可用,在严格模式是undefined,混杂模式下为全局对象;
  3. 在实现中注意如何处理这种情况promise2 === promise1;
  4. 判断返回值x是是否是当前Promise的一个实例,才能按照当前状态处理它;
  5. 避免对返回值x多次调用x.then(),确保一致性;
  6. 正视多次调用then(),实现代码中不应限制调用次数;只有真的无限循环时才会允许抛出TypeError错误;
实现过程

本来想自己慢慢写的,却熬不住耐心去尝试;突然就看到了一个地址的实现promise实现 ; 另加一点自己的想法;

  1. Promise是一个函数或对象(用函数来写);三个状态、初始状态、状态转换后的值、状态改变之后的回调、状态改变之后的处理函数;

    当前返回的值不是一个函数或对象时,基本就可以这样处理;如果是函数或对象还要额外处理。

     function Promise(){
         // 三个状态
         const states = {
             PEDNING:"pending",
             FULFILLED:"fulfilled",
             REJECTED:"rejected"
         };
         // 初始当前状态
         let state = states.PEDNING;
    
         // 存储状态 改变之后的值
         let value = null;
         // 存储fulfilled 或 rejected 需要回调的函数
         // 同一个Promise对象会多次调用 `.then()` ,
         let handles = [];
    
         // 成功之后的函数
         function fulfilled(result){
            state = states.FULFILLED;
            value = result;
         }
         // 失败之后 、被拒之后 的函数
         function rejected(err){
            state = states.REJECTED;
            value = err;
         }
     }
    
  2. 当获取的值不是简单值,是一个函数或独享;需要处理是否存在then方法,如果存在,则调用;不存在则进行简单状态转换。
    resolve()用来针对性处理返回的结果值如果是一个对象或函数且具有then()方法时递归调用;
    保证状态值只改变一次,且调用fulfilled()rejected()一次;

    第一阶段说明文字很长,有流程处理图,还请耐心看完,理解就会很快。

    function Promise(){
    	// ...
    	// 处理更深层次的值,返回值是函数、对象
        function resolve(result){
            try{
                // 返回的结果是否存在 `then` 函数,是否可调用 ; 手动实现 getThen()方法。
                let then = getThen(result);
                if(then){
                    // 存在 then 方法,则属于伪 Promise; 但还是要按照Promise的流程处理它;
                    // 手动实现 doResolve()方法
                    doResolve(then.bind(result),resolve,rejected);
                    return;
                }
                fulfilled(result);
            }catch(e){
                rejected(e);
            }
        }	
    }
    /**
     * 判断传入的值是否是函数或者对象,
     * 并且是否拥有then方法,并返回
     * @param {需要判断 处理的值} value 
     */
     function getThen(value){
        let t = typeof value;
        if(value&&(t === 'object' || t === 'function')){
            let thenMethods = value.then;
            if(typeof thenMethods === 'function'){
                return thenMethods;
            }
        }
        return null;
     }
    /**
     * 1. 需要处理的then 方法,不确定该 then方法是否是规范的Promise.then() ;
     * 2. try...catch..捕获可能调用方法出现的错误;
     * 3. 如果该 then 方法符合规范,则按照正常的 Promise 流程处理
     * 4. 调用处理 onFulfilled方法也就是 resolve() 可以处理多次递归的问题;
     * @param {*} fn 
     * @param {*} onFulfilled 
     * @param {*} onRejected 
     */
     function doResolve(fn,onFulfilled,onRejected){
        let done = false;
        try{
            fn(value=>{
                if(done) return;
                done = true;
                onFulfilled(value);
            },reason=>{
                if(done) return;
                done = true;
                onRejected(reason);
            });
        }catch(e){
            if(done) return;
            done = true;
            onRejected(e);
        }
     }
    
  3. 按照正常的调用Promise,有一个参数(resolve,reject),用于手动处理返回的值。

    function Promise(fn){
    	// ...
    	// 考虑到递归调用,保证状态只改变一次;
        // fulfilled() 调用一次;rejected()调用一次;
        doResolve(fn,resolve,rejected);
    }
    
  4. 接受用户调用Promise实例后.then方法的处理函数;
    说明
    done函数时then方法的一个简化版,如果不考虑返回值是函数、对象;多次调用等问题就可以直接使用done()方法;
    有了done方法,多次调用then()方法以返回多个Promise实例而分割处理,不会造成混乱;

    // 为了保证 处理函数 handle 时异步的;
    this.done = function(onFulfilled,onRejected){
        setTimeout(()=>{
            handle({
                onFulfilled:onFulfilled,
                onRejected:onRejected
            });
        });
    }
    
    // 实现 then() 方法
    // 按照then 的规范实现:
    // 1. 必须返回一个Promise实例
    this.then = function(onFulfilled,onRejected){
        let self = this;
        return new Promise(function(resolve,reject){
            return self.done((result)=>{
                if(typeof onFulfilled === 'function'){
                    try{
                        return resolve(onFulfilled(result));
                    }catch(err){
                        return reject(err);
                    }
                }else{
                    return resolve(result);
                }
            },(error)=>{
                if(typeof onRejected === 'function'){
                    try{
                        return resolve(onRejected(error));
                    }catch(e){
                        return reject(e);
                    }
                }else{
                    return reject(error);
                }
            })
        });
    }
    
测试结果
  1. 实例测试结果展示
    在这里插入图片描述
  2. 通过工具测试结果promises-aplus-tests
    错误一:如果onFulfilled/onRejected就没必要在延时后调用了,而是在之前进行调用;
    错误二:当返回值x和当前实例promise相同时,没有抛出错误TypeError
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

heroboyluck

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值