16 # 实现 catch 方法

简介: 16 # 实现 catch 方法

catch 就是 then,只是没有成功

可以理解为:

then(null, err)

实现:

// promise 就是一个类
// 1. promise 有三个状态:成功态(resolve) 失败态(reject) 等待态(pending)(又不成功又不失败)
// 2. 用户自己决定失败的原因和成功的原因,成功和失败也是用户定义的
// 3. promise 默认执行器立即执行
// 4. promise 的实例都拥有一个 then 方法,一个参数是成功的回调,另一个是失败的回调
// 5. 如果执行函数时发生了异常也会执行失败的逻辑
// 6. 如果 promise 一旦成功就不能失败,反之亦然,只有等待态的时候才能去更新状态
const RESOLVE = "RESOLVE"; // 成功态
const REJECT = "REJECT"; // 失败态
const PENDING = "PENDING"; // 等待态
// 解析 promise:所有的promise需要兼容,比如 bluebird q es6-promise
const resolvePromise = (promise2, x, resolve, reject) => {
    // 处理一下循环引用(自己等待自己的错误实现),这个时候我们用一个类型错误结束掉 promise。
    if (promise2 === x) {
        reject(new TypeError("Chaining cycle detected for promise #<Promise>"));
    }
    // 用于防止走成功又走失败
    let called;
    // 后续的条件要严格判断 保证代码能和别的库一起使用
    if ((typeof x === "object" && x !== null) || typeof x === "function") {
        // 要继续判断是否是一个promise
        try {
            // x.then 取值时可能会报错,需要捕获异常
            let then = x.then;
            // then 是个函数我们就认为是promise
            if (typeof then === "function") {
                // 下面为什么不写成 x.then 的原因,可能第二次取出报错,直接写成 then.call(x)
                // 根据 promise 的状态决定是成功还是失败
                then.call(
                    x,
                    (y) => {
                        if (called) return;
                        called = true;
                        // 递归解析
                        resolvePromise(promise2, y, resolve, reject);
                    },
                    (e) => {
                        if (called) return;
                        called = true;
                        reject(e);
                    }
                );
            } else {
                resolve(x);
            }
        } catch (e) {
            // 防止失败了再次进入成功
            if (called) return;
            called = true;
            reject(e);
        }
    } else {
        resolve(x);
    }
};
class KaimoPromise {
    constructor(executor) {
        this.status = PENDING;
        // value 是任意合法的 Javascript 值,(包括 undefined,thenable, promise)。
        this.value = undefined;
        // reason 是表示 promise 为什么被 rejected 的值
        this.reason = undefined;
        // 存放成功回调
        this.onResolveCallbacks = [];
        // 存放失败回调
        this.onRejectCallbacks = [];
        let resolve = (value) => {
            if (this.status === PENDING) {
                this.value = value;
                this.status = RESOLVE;
                this.onResolveCallbacks.forEach((fn) => fn());
            }
        };
        let reject = (reason) => {
            if (this.status === PENDING) {
                this.reason = reason;
                this.status = REJECT;
                this.onRejectCallbacks.forEach((fn) => fn());
            }
        };
        try {
            // 立即执行
            executor(resolve, reject);
        } catch (error) {
            // 处理错误异常
            console.log("inner---->", error);
            reject(error);
        }
    }
    // 1. promise 成功和失败的回调的返回值可以传递到外层的下一个 then
    // 2. promise 返回值情况
    //  2.1. 如果返回的是普通的值的话:传递到下一次的成功中(不是错误也不是 promise 就是普通值)
    //  2.2. 如果返回的是错误的情况:一定会走到下一次的失败中
    //  2.3. 如果返回的是 promise 的情况:会采用 promise 的状态,决定下一步是走成功还是失败
    // 3. 错误处理:如果离自己最近的 then 没有错误处理(没有写错误函数)会向下找
    // 4. 每次执行完 `promise.then` 方法后返回的都是一个新的 promise (promise 一旦成功或者失败都不能去修改状态)
    // promise 必须提供 then 方法来存取它当前或最终的值或者原因。
    // then 接收两个参数:onFulfilled 和 onRejected
    then(onFulfilled, onRejected) {
        onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (v) => v;
        onRejected =
            typeof onRejected === "function"
                ? onRejected
                : (err) => {
                      throw err;
                  };
        // 实现链式调用
        let promise2 = new KaimoPromise((resolve, reject) => {
            if (this.status === RESOLVE) {
                // setTimeout 处理 promise2 没有初始化的问题, 需要等 executor 执行完
                setTimeout(() => {
                    // try catch 无法捕获异步代码,所以需要在 promise2 里面也加 try catch
                    try {
                        let x = onFulfilled(this.value);
                        // x 可能是一个 promise
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                }, 0);
            }
            if (this.status === REJECT) {
                setTimeout(() => {
                    try {
                        let x = onRejected(this.reason);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                }, 0);
            }
            // 下面是异步的,可以不加setTimeout,统一一下加了一下
            if (this.status === PENDING) {
                this.onResolveCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onFulfilled(this.value);
                            resolvePromise(promise2, x, resolve, reject);
                        } catch (e) {
                            reject(e);
                        }
                    }, 0);
                });
                this.onRejectCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onRejected(this.reason);
                            resolvePromise(promise2, x, resolve, reject);
                        } catch (e) {
                            reject(e);
                        }
                    }, 0);
                });
            }
        });
        return promise2;
    }
    catch(errCallback) {
        return this.then(null, errCallback);
    }
}
// promise 延迟对象 规范测试入口
KaimoPromise.defer = KaimoPromise.deferred = function () {
    let dfd = {};
    dfd.promise = new KaimoPromise((resolve, reject) => {
        dfd.resolve = resolve;
        dfd.reject = reject;
    });
    return dfd;
};
module.exports = KaimoPromise;

测试:

const KaimoPromise = require("./16/kaimo-promise.js");
new KaimoPromise((resolve, reject) => {
    reject("kaimo");
})
    .then((data) => {
        console.log(data);
    })
    .catch((err) => {
        console.log("err----->", err);
    });

目录
相关文章
|
监控 算法 Java
说一说JVM的垃圾回收器
说一说JVM的垃圾回收器
155 0
|
JSON 测试技术 数据库
unittest 测试框架的使用
1. unittest 框架解析 2. 批量执行测试脚本 1)构建测试套件 addTest() 方法 makeSuite() 方法 TestLoader() 方法 2)用例的执行顺序 3)忽略测试用例的执行 3. unittest 断言 4. HTML 报告生成 5. 异常捕获与错误截图 6. 数据驱动 1)测试多个不同数据 2)测试某个文件中的多组数据 txt 文件或者 csv 文件 JSON 文件
300 0
|
5天前
|
云安全 人工智能 自然语言处理
|
9天前
|
人工智能 Java API
Java 正式进入 Agentic AI 时代:Spring AI Alibaba 1.1 发布背后的技术演进
Spring AI Alibaba 1.1 正式发布,提供极简方式构建企业级AI智能体。基于ReactAgent核心,支持多智能体协作、上下文工程与生产级管控,助力开发者快速打造可靠、可扩展的智能应用。
846 25
|
3天前
|
机器学习/深度学习 人工智能 自然语言处理
Z-Image:冲击体验上限的下一代图像生成模型
通义实验室推出全新文生图模型Z-Image,以6B参数实现“快、稳、轻、准”突破。Turbo版本仅需8步亚秒级生成,支持16GB显存设备,中英双语理解与文字渲染尤为出色,真实感和美学表现媲美国际顶尖模型,被誉为“最值得关注的开源生图模型之一”。
421 4
|
12天前
|
数据采集 人工智能 自然语言处理
Meta SAM3开源:让图像分割,听懂你的话
Meta发布并开源SAM 3,首个支持文本或视觉提示的统一图像视频分割模型,可精准分割“红色条纹伞”等开放词汇概念,覆盖400万独特概念,性能达人类水平75%–80%,推动视觉分割新突破。
820 59
Meta SAM3开源:让图像分割,听懂你的话