Promise/A+

ES6将Promise列入了标准,提供了原生的接口,研究Promise/A+对于ES6的理解有很大的帮助。这里主要探究Promise构造函数,实例resolve方法、实例then方法以及实例子的notify方法。

const RESOLVED = 0;
const REJECTED = 1;
const PENDING = 2;

function Promise(executor) {

    this.state = PENDING;
    this.value = undefined;
    this.deferred = [];

    var promise = this;

    try {
        executor(function (x) {
            promise.resolve(x);
        }, function (r) {
            promise.reject(r);
        });
    } catch (e) {
        promise.reject(e);
    }
}

let a = new Promise(function (resolve, reject) {
    if (true) {
        reslove()
    }else{
        reject()
    }
}) 

可见实例传入的函数在构造函数内进行调用,resolve与reject分别为原型的resolve与reject方法。state为promise的状态,value为结果值,deferred为延迟执行action的列表。

p.resolve = function resolve(x) {
    var promise = this;

    if (promise.state === PENDING) {
        if (x === promise) {
            throw new TypeError('Promise settled with itself.');
        }

        var called = false;

        try {
            var then = x && x['then'];

            if (x !== null && typeof x === 'object' && typeof then === 'function') {
                then.call(x, function (x) {
                    if (!called) {
                        promise.resolve(x);
                    }
                    called = true;

                }, function (r) {
                    if (!called) {
                        promise.reject(r);
                    }
                    called = true;
                });
                return;
            }
        } catch (e) {
            if (!called) {
                promise.reject(e);
            }
            return;
        }
        promise.state = RESOLVED;
        promise.value = x;
        promise.notify();
    }
};

当执行实例原型的resolve方法时,会进行一个判断,如果传入的参数具有then方法,并且then方法为一个函数的时候(大多数情况为传入一个promise实例),以传入的promise实例作为this调用原型的then方法,传入2个参数,分别为成功与失败要执行的方法,后续会把这些方法置入实例的deferred内。如果传入的参数并非具有then方法的时候,调用原型的notify()方法。

p.then = function then(onResolved, onRejected) {
    console.log(this)
    var promise = this;
    return new Promise(function (resolve, reject) {
        promise.deferred.push([onResolved, onRejected, resolve, reject]);
        promise.notify();
    });
};

每次调用then方法都返回一个新的promise实例,这也是promise可以链式操作的原因所在,每次调用then时,会将实参onResolved,与onRejected,放入延迟执行的列表当中,因为只有当一个promise的实例不是pending时候,才会执行then里的函数,这就是实现同步操作的核心所在。那如何知道某个promise实例状态是否为pending与否呢,这里就要用到另一个关键的原型函数notify了。还要注意的一点事,每一次执行then函数的时候,返回的新的promise,但延迟处理列表仍保存在之前的列表中。

p.notify = function notify() {
    console.log(this.deferred)
    var promise = this;
    if (promise.state !== PENDING) {
        while (promise.deferred.length) {
            var deferred = promise.deferred.shift(),
                onResolved = deferred[0],
                onRejected = deferred[1],
                resolve = deferred[2],
                reject = deferred[3];

            if (promise.state === RESOLVED) {
                if (typeof onResolved === 'function') {
                    resolve(onResolved.call(undefined, promise.value));
                } else {
                    resolve(promise.value);
                }
            } else if (promise.state === REJECTED) {
                if (typeof onRejected === 'function') {
                    resolve(onRejected.call(undefined, promise.value));
                } else {
                    reject(promise.value);
                }
            }
        }
    }
};

每次执行完resolve或者then之后,执行notify来判断状态是否为pedding,如果不是则执行之前放入延迟列表的函数,以此来达到同步的效果。

这里举一个例子,场景如下:

let a = new Promise(function(resolve,reject){
    setTimeout(()=>{
        resolve(123)
    },1000)
}).then(res=>{
    return res+1
}).then(res=>{
    console.log(res)
})

首先实例传入函数,然后构造函数内部调用这个函数,其为异步,故执行第一条then语句,返回一个新的promise实例(这里将只称作为b),并将then的回调函数与b的resolve与reject置入a的延迟执行列表(注意实参和形参数)。然后执行a的notify函数,发现依旧为pedding状态。故继续执行第二个then语句,与第一条then语句一致,返回一个promise实例c。这个时候a有一个延迟执行列表,b也有一个延迟执行列表!一秒后,执行a的resolve(123)(这里先说resolve非promise的情况,下面再具体说resolve promise的情况),将实参赋值给实例的value之后(这里为123),执行a的notify函数,然后将a的延迟列表取出,根据状态执行对应的函数得到对应的值(如果onResolved或者onrRejected非函数时,直接返回值),这里执行后为124。然后执行b的resolve,执行a的resolve(),将b的value赋值124之后,执行b的notify函数,然后取出b的延迟列表,根据状态执行对应的函数,这里即为console.log(res),打印出124。整个代码就是通过将延迟执行action与resolve,reject放入数组,然后不断的调用来实现的!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值