11 # promise2 和 x 引用同一个变量

简介: 11 # promise2 和 x 引用同一个变量

先看一个例子:promise2 等待 promise2,这个时候 x 跟 promise2 是同一个就会死循环

let p1 = new Promise((resolve, reject) => {
    resolve("kaimo");
});
let promise2 = p1.then((data) => {
    console.log("p1---resolve--->", data);
    // promise2 等待 promise2,这个时候 x 跟 promise2 是同一个就会死循环
    return promise2;
});
promise2.then(
    (data) => {
        console.log("p2---resolve--->", data);
    },
    (err) => {
        console.log("p2---reject--->", err);
    }
);

找到 promiseA+ 规范,https://promisesaplus.com/

下面在我们自己的库里实现这个功能:找到解析promise函数,处理一下循环引用(自己等待自己的错误实现),这个时候我们用一个类型错误结束掉 promise。

// 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
const resolvePromise = (promise2, x, resolve, reject) => {
    console.log("解析 promise----> promise2", promise2);
    // 处理一下循环引用(自己等待自己的错误实现),这个时候我们用一个类型错误结束掉 promise。
    if (promise2 === x) {
        reject(new TypeError("Chaining cycle detected for promise #<Promise>"));
    }
};
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) {
        // 实现链式调用
        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;
    }
}
module.exports = KaimoPromise;

测试一下:

const KaimoPromise = require("./11/kaimo-promise.js");
let p1 = new KaimoPromise((resolve, reject) => {
    resolve("kaimo");
});
let promise2 = p1.then((data) => {
    console.log("p1---resolve--->", data);
    // promise2 等待 promise2,这个时候 x 跟 promise2 是同一个就会死循环
    return promise2;
});
promise2.then(
    (data) => {
        console.log("p2---resolve--->", data);
    },
    (err) => {
        console.log("p2---reject--->", err);
    }
);

目录
相关文章
scrollIntoView()定位元素显示导致页面上移解决方法?
scrollIntoView()定位元素显示导致页面上移解决方法?
1030 0
|
11月前
|
Java 容器 Spring
Bean的实例化阶段
经过第一阶段,所有bean定义都通过BeanDefinition的方式注册到BeanDefinitionRegistry中当某个请求通过容器的getBean方法请求某个对象,或者因为依赖关系容器需要隐式的调用getBean时,就会触发第二阶段的活动:容器会首先检查所请求的对象之前是否已经实例化完成。 如果没有,则会根据注册的BeanDefinition所提供的信息实例化被请求对象,并为其注入依赖。 当该对象装配完毕后,容器会立即将其返回给请求方法使用。BeanFactory只是Spring IoC容器的一种实现,如果没有特殊指定,它采用采用延迟初始化策略:只有当访问容器中的某个对象时,才对
|
机器学习/深度学习 安全 Perl
时间卷积网络TCN:时间序列处理的新模型
时间卷积网络TCN:时间序列处理的新模型
1573 0
时间卷积网络TCN:时间序列处理的新模型
|
jenkins 应用服务中间件 Shell
自动化部署之旅 - 当我放弃了Jenkins而选择了Drone CI
一直以来对于项目的部署管理我都是采用Jenkins,但其实我使用到的也只是它接收webhook的功能,然后触发对应的项目预设shell脚本来运行部署,最近突然心血来潮,想尝试下不同的集成构建方案,在简单调研后选择了Drone,其轻量、高颜值的特点立刻吸引了我。
|
Python
一日一技:使用Python翻译HTML中的文本字符串
一日一技:使用Python翻译HTML中的文本字符串
706 0
一日一技:使用Python翻译HTML中的文本字符串
|
安全
阿里云产品体系分为6大分类——安全——安全的6种模块——安全服务
阿里云产品体系分为6大分类——安全——安全的6种模块——安全服务自制脑图
224 1
|
NoSQL Redis Docker
容器数据卷
容器数据卷
173 0
|
缓存 网络协议 网络架构
当你打开一个网页,到底发生了什么?——计算机网络
当你打开一个网页,到底发生了什么?——计算机网络
242 0
|
算法
m通过目标形心提取、颜色模型以及边缘提取实现两个相向移动人员交叉遮挡过程的检测和分割matlab仿真
m通过目标形心提取、颜色模型以及边缘提取实现两个相向移动人员交叉遮挡过程的检测和分割matlab仿真
224 0
|
存储 消息中间件 缓存
消息存储核心类介绍|学习笔记
快速学习消息存储核心类介绍
消息存储核心类介绍|学习笔记