zoukankan      html  css  js  c++  java
  • 动手写一个Promise

    现在Promise用的比较频繁了,如果哪天突然不用了,可能逻辑就不好厘清了,回调没的说是一大把

    废话不多说,进入正题

    Promise这个东西很神奇,用起来舒服,若自己写一下,恐怕还真不简单,关键就一个字“绕”,绕过了也就好了

    豌豆资源搜索网站https://55wd.com 广州vi设计公司http://www.maiqicn.com

    首先定义结构

    class MyPromise {
        constructor(excutor) {}
        then(onfulfilled, onrejected) {}
        catch(onrejected) {}
    }

    以上也就是大体的结构了

    结构清楚了,那么说如何设计呢,先看看Promise的示例

    var p = new Promise((resolve, reject) => {
        resolve(1)
    })
    p.then(console.log)
    p.then(console.log)

    以上的输出结果为

    1
    1

    所以说内部应该有必要存这个结果值,同时还有必要存一系列的回调函数,所以先来看看构造函数的实现

    构造函数

    constructor(excutor) {
        // 状态
        this._state = 'pending'
        // 成功回调
        this._callbacks_resolved = []
        // 失败回调
        this._callbacks_rejected = []
        // 执行
        excutor((data) => {
            // 避免重复执行
            if (this._state !== 'pending') {
                return
            }
            // 保存结果
            this._data = data
            // 状态变更
            this._state = "resolved"
            // 处理
            this._handle()
        }, (err) => {
            if (this._state !== 'pending') {
                return
            }
            // 错误信息
            this._err = err
            // 状态变更
            this._state = "rejected"
            this._handle()
        })
    }
     

    看看处理函数

    也就是根据对应的状态执行对应的回调,当然不要忘了处理完之后要清空

    _handle() {
        if (this._state === 'pending') {
            return;
        }
        // 为什么要延时,then的东西是不能马上执行的,可以看看micro-task和macro-task,这里只能模拟
        setTimeout(() => {
            if (this._state === 'resolved') {
                this._callbacks_resolved.forEach(cb => cb(this._data))
            } else {
                this._callbacks_rejected.forEach(cb => cb(this._err))
            }
            this._callbacks_resolved = []
            this._callbacks_rejected = []
        })
    }
     

    then

    到了关键的一步,也就是核心的then
    这个then的放回结果本身就是一个Promise,所以是可以无限的套的,也就像这样.then().then()
    还支持值传递,上一个没有处理的,直接流到下一级,上一级把错误处理后,下一级状态变更为resolved

    最开始想直接返回this,发觉这样问题大了去了,所以得另外new一个MyPromise实例,代码如下

    then(onfulfilled, onrejected) {
        return new MyPromise((resolve, reject) => {
            this._callbacks_resolved.push(data => {
                // 没有处理,直接往后传
                if (!onfulfilled) {
                    return resolve(data)
                }
                try {
                    let r = onfulfilled(data)
                    // 有then函数,就认为是Promise
                    if (r && typeof r.then === "function") {
                        return r.then(resolve, reject)
                    }
                    resolve(r)
                } catch(e) {
                    // 有错误直接向后传
                    reject(e)
                }
            })
            this._callbacks_rejected.push(err => {
                if (!onrejected) {
                    return reject(err)
                }
                try {
                    let r = onrejected(err)
                    if (r && typeof r.then === "function") {
                        return r.then(resolve, reject)
                    }
                    resolve(r)
                } catch(e) {
                    reject(e)
                }
            })
            this._handle()
        })
    }

    以上基本功能已经实现完成,最后还有一个catch函数,很简单,包装一下就好了

    catch(onrejected) {
        return this.then(undefined, onrejected)
    }

    随便写了个测试用例

    var p = new MyPromise((resolve, reject) => {
      resolve(1);
    })
      .then((n) => {
        console.log(n);
        return new MyPromise((resolve, reject) => {
          resolve(2);
        });
      })
      .then(console.log)
      .then(() => {
        throw new Error("error");
      });
    
    p.catch((e) => {
      console.error(e);
    });
    
    p.catch((e) => {
      console.error(e);
    });

    输出

    1
    2
    error
    error

    完全符合预期

    好了,完结

    附上全部代码

    class MyPromise {
      constructor(excutor) {
        // 状态
        this._state = "pending";
        // 成功回调
        this._callbacks_resolved = [];
        // 失败回调
        this._callbacks_rejected = [];
        // 执行
        excutor(
          (data) => {
            // 避免重复执行
            if (this._state !== "pending") {
              return;
            }
            // 保存结果
            this._data = data;
            // 状态变更
            this._state = "resolved";
            // 处理
            this._handle();
          },
          (err) => {
            if (this._state !== "pending") {
              return;
            }
            // 错误信息
            this._err = err;
            // 状态变更
            this._state = "rejected";
            this._handle();
          }
        );
      }
      then(onfulfilled, onrejected) {
        return new MyPromise((resolve, reject) => {
          this._callbacks_resolved.push((data) => {
            // 没有处理,直接往后传
            if (!onfulfilled) {
              return resolve(data);
            }
            try {
              let r = onfulfilled(data);
              // 有then函数
              if (r && typeof r.then === "function") {
                return r.then(resolve, reject);
              }
              resolve(r);
            } catch (e) {
              // 有错误直接向后传
              reject(e);
            }
          });
          this._callbacks_rejected.push((err) => {
            if (!onrejected) {
              return reject(err);
            }
            try {
              let r = onrejected(err);
              if (r && typeof r.then === "function") {
                return r.then(resolve, reject);
              }
              resolve(r);
            } catch (e) {
              reject(e);
            }
          });
          this._handle()
        });
      }
    
      catch(onrejected) {
        return this.then(undefined, onrejected);
      }
    
      _handle() {
        if (this._state === "pending") {
          return;
        }
        // 为什么要延时,then的东西是不能马上执行的,可以看看micro-task和macro-task,这里只能模拟
        setTimeout(() => {
          if (this._state === "resolved") {
            this._callbacks_resolved.forEach((cb) => cb(this._data));
          } else {
            this._callbacks_rejected.forEach((cb) => cb(this._err));
          }
          this._callbacks_resolved = [];
          this._callbacks_rejected = [];
        });
      }
    }
  • 相关阅读:
    Openresty+redis实现灰度发布
    Nginx keepalived
    Nginx反向代理、负载均衡、动静分离、缓存、压缩、防盗链、跨域访问
    MYCAT扩容
    MYCAT全局序列
    MYCAT分库分表
    MySQL主从复制
    [redis] linux下集群篇(4) docker部署
    [nginx] CORS配置多域名
    [mysql] 归档工具pt-archiver,binlog格式由mixed变成row
  • 原文地址:https://www.cnblogs.com/qianxiaox/p/13700351.html
Copyright © 2011-2022 走看看