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放入数组,然后不断的调用来实现的!