先写一个简单的Promise:
function Promise(executor) {
var self = this;
this.status = 'pending';
this.value = undefined;
this.reason = undefined;
function resolve(value) {
if(self.status === 'pending') {
self.status = 'resolve';
self.value = value;
}
}
function reject(reason) {
if(self.status === 'pending') {
self.status = 'rejected';
self.reason = reason;
}
}
executor(resolve, reject);
}
Promise.prototype.then = function (infulfilled, inrejected) {
if(this.status === 'resolve') {
infulfilled(this.value)
}
if(this.status === 'rejected') {
inrejected(this.reason)
}
};
var p = new Promise(function (resolve, reject) {
resolve('resolve');
});
p.then(function (data) {
console.log(data);
}, function (err) {
console.log(err);
});
流程大概就是:
先用构造函数new一个对象p
var p = new Promise(function (resolve, reject) {
resolve('resolve');
});
在构造函数Promise中将p对象属性初始化:
this.status = 'pending';
this.value = undefined;
this.reason = undefined;
构造函数内部会执行executor这个函数,而这个函数就是传进去的函数:
function (resolve, reject) {
resolve('resolve');
}
这个再调用构造函数写好的resolve函数:
function resolve(value) {
if(self.status === 'pending') {
self.status = 'resolve';
self.value = value;
}
}
把p对象的status属性改为resolve,把到时候调用的参数value值保存中自身的属性value中。
然后p调用原型对象的then属性,它是一个函数:
function (infulfilled, inrejected) {
if(this.status === 'resolve') {
infulfilled(this.value)
}
if(this.status === 'rejected') {
infulfilled(this.value)
}
}
根据p此时p对象自身的status状态执行对应函数,此时status === ‘resolve’,执行infulfilled函数即then参数中的第一个函数,最后:
p.then(function (data) {
console.log(data); // 输出suc
}, function (err) {
console.log(err);
});
一个简单的Promise就写完了,现在只支持同步调用,不支持异步调用,比如改成这样就没法调用
var p = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('resolve');
})
});
不能支持异步的是因为:当构造函数调用executor函数时,发现了setTimeout(一个异步函数),它就会把它放到一边,继续运行下面的函数,即到了p调用then,此时它的status因为没有调用resolve,所以它的status还是pending,所以什么都没有执行。
解决方法就是:在then里面添加一个判断,如果status是pending的话,就把函数存进一个数组,这个数组专门用来执行回调函数:
if(this.status === 'pending') {
this.onResolvedCallbacks.push(function () { //onResolvedCallbacks是一个存放函数的数组
infulfilled(self.value)
});
this.onRejectedCallbacks.push(function () { //onRejectedCallbacks是一个存放函数的数组
infulfilled(self.reason)
});
}
在构造函数创建专门拿来放函数的数组:
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
function resolve(value) {
if(self.status === 'pending') {
self.status = 'resolve';
self.value = value;
self.onResolvedCallbacks.forEach(function (fn) {
fn();
})
}
}
function reject(reason) {
if(self.status === 'pending') {
self.status = 'rejected';
self.reason = reason;
self.onRejectedCallbacks.forEach(function (fn) {
fn();
})
}
}
并且每次执行executor函数时会将函数数组里的都执行一遍。
完整代码:
function Promise(executor) {
var self = this;
this.status = 'pending';
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
function resolve(value) {
if(self.status === 'pending') {
self.status = 'resolve';
self.value = value;
self.onResolvedCallbacks.forEach(function (fn) {
fn();
})
}
}
function reject(reason) {
if(self.status === 'pending') {
self.status = 'rejected';
self.reason = reason;
self.onRejectedCallbacks.forEach(function (fn) {
fn();
})
}
}
executor(resolve, reject);
}
Promise.prototype.then = function (infulfilled, inrejected) {
var self = this;
if(this.status === 'resolve') {
infulfilled(this.value)
}
if(this.status === 'rejected') {
inrejected(this.reason)
}
if(this.status === 'pending') {
this.onResolvedCallbacks.push(function () {
infulfilled(self.value)
});
this.onRejectedCallbacks.push(function () {
inrejected(self.reason)
});
}
};
var p = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('resolve');
})
});
p.then(function (data) {
console.log(data);
}, function (err) {
console.log(err);
});
再对比之前的流程:
不能支持异步的是因为:当构造函数调用executor函数时,发现了setTimeout(一个异步函数),它就会把它放到一边,继续运行下面的函数,即到了p调用then,此时它的status因为没有调用resolve,所以它的status还是pending,所以什么都没有执行。
这样到了调用then时,因为status是pending,就会将要调用的函数放入函数数组,这个时候同步函数执行完了,开始执行放在一边的seTimeout里面的函数resolve,它就会把之前存放数组的函数遍历执行,最后输出了suc。
上面的Promise还没支持捕获异常,因为异常时,没有执行任何函数,它的status还是pending, 所以要修改一下executor的执行条件:
try {
executor(resolve, reject);
} catch(err) {
reject(err)
}
这样捕获到异常时会直接执行reject,输出error:
var p = new Promise(function (resolve, reject) {
throw new Error('error')
});
p.then(function (data) {
console.log(data);
}, function (err) {
console.log(err); //输出Error: error
});
关于链式调用先等着吧,他妈也太复杂了……