lihongjie0209 / myblog

4 stars 0 forks source link

JavaScript: Promise #242

Open lihongjie0209 opened 3 years ago

lihongjie0209 commented 3 years ago

Promise 是什么

Promise 是一个容器, 一个单值容器

和List之类的容器有什么区别

List 之类的集合他们的值都是静态的, 但是Promise的值是不确定的, 这个不确定有

  1. 可能在1s中之后容器中会出现, 也可能是10s中
  2. 可能在求值过程中失败了, 那么我的容器中只包含了一个 " Error " 对象

Promise 是什么

Promise {

var value; var error; // 错误对象

}

Promise 有什么接口

按照上面的数据结构, 我们大概可以设计出来

isError 判断是否出错

getError 获取error对象

setError 设置error对象

hasValue 判断值是否存在

getValue 获取值

setValue 设置值

Promise 中如何实现设置值或者错误的时候回调

很简单 实现一个监听者模式就可以了

首先注册回调函数

Promise.onValue(callback){

   this.valueListener.push(callback)

}

Promise.onError(callback){

   this.errorListener.push(callback)

}

然后在set方法中调用listener


Promise.setValue(value){

    this.valueListener.forearch(callback -> callback.call(value))

}
lihongjie0209 commented 3 years ago

如何实现链式调用

  1. 首先我们初始化一个Promise对象作为返回值
  2. 把回调封装成一个监听器添加到队列 2.1 如果回调调用成功 2.1.1 如果回调返回值也是Promise 那么需要把返回值的Promise中的值赋值给我们主函数的返回值 2.1.2 如果回调返回值是一个普通对象, 那么直接给主函数的返回值设置一下就可以了 2.1.3 如果回调发生异常, 那么需要给主函数的返回值设置error对象

这样我们就保证了一个链式调用, 然后通过监听器来赋值


P.prototype.onResolve = function (success, fail) {
    let ret = new P();
    if (success) {
        this.valueListener.push(function (value) {

            let tmp;
            try {

                tmp = success.call(null, value);
            } catch (e) {
                ret.setError(e);
                return;
            }

            if (tmp instanceof P) {

                tmp.onResolve(value => ret.setValue(value), error => ret.setError(error));

            } else {

                ret.setValue(tmp);

            }

        });

    }

return p;
lihongjie0209 commented 3 years ago

如何实现回调通知

只需要在setValue中调用一下监听器, 调用完成之后清空队列就可以了


P.prototype.setValue = function (value) {

    this.value = value;
    this.valueListener.forEach(l => l.call(null, value))
    this.valueListener = []

}

如何实现异步回调通知

Promise中的回调都是异步的, 实现起来也比较简单, 只需要把上面的foreach放在settimeout 中就可以了

lihongjie0209 commented 3 years ago

如何保证Promise对象不可变

promise在设值之后是不能再次设值的, 为了实现这个需求, 我们需要加一个状态字段, 表明当前的状态

比如:

0: 未设值 1: 已设值

  1. 错误

我们在set方法中判断一下状态就可以了