本章节纯粹是对promise手写实现。如果不了解promise自行了解再来学习本章知识。
promise初体验
首先,看一下
var p1 = new Promise(function(reslove,reject){
reslove(1)
})
运行原理
它是怎么执行的,以及对应的代码是什么
function Promise(exector){
exector(function(value){//这个函数对应的就是reslove函数
},function(reason){//这个函数对应的就是reject函数
})
}
后面会对exector函数中的reslove函数和reject函数添加许多功能,所以我们可以将它拆开
function Promise(exector){
function reslove(value){}//这个函数对应的就是reslove函数
function reject(reason){}//这个函数对应的就是reject函数
exector(reslove,reject)
}
接下来我们可以打印value和reason的值
function Promise(exector){
function reslove(value) {
console.log(value)
}
function reject(err) {
console.log(err)
}
exector(reslove,reject)
}
问题
现在这样的问题是,对于异步的处理还是要写到当前这个构造函数中。还是会导致回调地狱。如何解决?Promise ES6的实现都是约定 通过then方法来获取数据 。对构造函数添加then方法。
查看then方法的调用,需要传递两个函数,一个是成功时的调用,一个是失败时的调用。两个方法不会同时执行。
p1.then(function (data) {
console.log(data);
},function (err) {
console.log(err);
})
如何实现then方法?
Promise.prototype.then = function(onFulfaild,onRejected){
}
两个方法不会同时执行, 那么如何决策?我们可以根据一个状态来决定,也就是用户在new Promise方法中会调用reslove或者reject方法,在调用这两个方法时候,我们可以将状态值修改为约定的值,然后在then方法中根据它们的状态来进行区分到底谁需要执行。
约定状态fulfaild和rejected两个状态,当用户调用reslove方法时将状态改为fulfailed,同样的在then方法中根据这个状态为fulfailed来执行onFulfailed方法。
当用户调用reject方法时将状态改为rejected,同样的在then方法中根据这个状态为rejected来执行onRejected方法。
function Promise(exector) {
var that = this;
this.status = 'pending'
this.value = undefined;
this.reason = undefined;
function reslove(value) {
console.log(value)
that.value = value;
that.status = 'fulfailed'
}
function reject(err) {
console.log(err)
that.reason = err;
that.status = 'rejected'
}
exector(reslove, reject)
}
Promise.prototype.then = function (onFulfaild, onRejected) {
if (this.status === 'fulfailed') {
onFulfaild(this.value)
}
if (this.status === 'rejected') {
onRejected(this.reason)
}
}
同样的将new Promise中执行的reslove或者reject方法中传的值,也记录到Promise这个构造函数身上。执行reslove时,对应的this.value值进行修改,在then方法中,执行onFulfailed方法时传递的是成功时的值即this.value。
执行reject函数时对应的this.reason进行修改,在then方法中,执行onRejected方法时传递的是失败时的值即this.reason。
问题
将new Promise中的方法进行修改,我们改写为异步,查看一下效果
var p1 = new Promise(function (reslove,reject) {
setTimeout(function () {
reslove('这是reslove方法执行')
},1000)
})
p1.then(function (data) {
console.log('成功调用'+data);
},function (err) {
console.log('失败调用'+err);
})
最终不会打印任何的结果。原因是因为什么?new Promise方法是同步的,不过exector方法执行中有异步,而修改状态是等到异步完成才会修改,then方法中是同步,它在执行时候异步还没有执行完毕,那么这时的status一直是 pending。那么条件判断中没有一个是成功的,所以then中的onFulfaild和onRejected方法都没有执行。
思考
这时候我们可以考虑订阅发布者模式。当 reslove方法执行完毕或者当rejected执行完毕时,我们再将对应的功能执行。
当为异步时,then方法中获取的status一直是pending。在这时,我们可以将它们对应的方法存放在一个数组中。当异步中的reslove或者reject方法执行时,对数组循环,全部执行。即可。
function Promise(exector) {
var that = this;
this.status = 'pending'
this.value = undefined;
this.reason = undefined;
this.onFulfiledCallbacks =[];
this.onRejectedCallbacks = [];
function reslove(value) {
that.value = value;
that.status = 'fulfailed'
that.onFulfiledCallbacks.forEach(fn=>{fn()})
}
function reject(err) {
that.reason = err;
that.status = 'rejected'
that.onRejectedCallbacks.forEach(fn=>{fn()})
}
exector(reslove, reject)
}
Promise.prototype.then = function (onFulfaild, onRejected) {
var that = this;
if (this.status === 'fulfailed') {
onFulfaild(that.value)
}
if (this.status === 'rejected') {
onRejected(that.reason)
}
if(this.status === 'pending'){
this.onFulfiledCallbacks.push(()=>{onFulfaild(that.value)})
this.onRejectedCallbacks.push(()=>{onRejected(that.reason)})
}
}
状态统一
执行reslove或者reject方法后这两者之间不可以修改状态。我们可以再添加判断。也就是当状态为初始状态pending时才可以执行reslove或者reject,其它状态时,这两个方法不会再执行。
function reslove(value) {
if(that.status === 'pending'){
that.value = value;
that.status = 'fulfailed'
}
that.onFulfiledCallbacks.forEach(fn=>{fn()})
}
function reject(err) {
if(that.status === 'pending'){
that.reason = err;
that.status = 'rejected'
}
that.onRejectedCallbacks.forEach(fn=>{fn()})
}
exector(reslove, reject)
}
链式编程(简易版)
希望有then之后,还可以继续使用then。那么我们考虑一下,有的同学会觉得直接return this
就可以了,不过在这里面,我们要明白一点,then是对promise这个实例才有用。return this
确实返回的是当前的实例对象,但是当前实例完成以后状态已经更新,而不再是pending
,所以reject和reslove函数就不会再次触发。
解决
在then方法中,可以尝试执行代码时候我们先对其实现生成一次promise实例,然后再将新的实例返回。每次then调用时产生的都是新的promise实例,这样的话,所有的状态都是pending
开始,就可以再次执行reslove方法。
Promise.prototype.then = function (onFulfaild, onRejected) {
var that = this;
let promise2;
promise2 = new Promise(function (reslove,reject) {
if (that.status === 'fulfailed') {
let x = onFulfaild(that.value)
reslove(x)
}
if (that.status === 'rejected') {
let x = onRejected(that.reason)
resolve(x)
}
if(that.status === 'pending'){
that.onFulfiledCallbacks.push(()=>{
let x = onFulfaild(that.value)
reslove(x)
})
that.onRejectedCallbacks.push(()=>{
let x = onRejected(that.reason)
reslove(x)
})
}
})
return promise2;
}
解释,这里每次不论reslove或者reject方法执行完成之后,都可能有结果。结果可能是普通值,我们这里的代码实现的仅仅是返回一个普通值。后面考虑更多的值,函数或者promise实例等。
完善代码
执行reslove或者reject函数时,可能会报错。应该对其抛出异常,而且通过reject来抛出。
Promise.prototype.then = function (onFulfaild, onRejected) {
var that = this;
let promise2;
promise2 = new Promise(function (reslove,reject) {
if (that.status === 'fulfailed') {
try{
let x = onFulfaild(that.value)
reslove(x)
}
catch (e) {
reject(e)
}
}
if (that.status === 'rejected') {
try{
let x = onRejected(that.reason)
resolve(x)
}catch (e) {
reject(e)
}
}
if(that.status === 'pending'){
that.onFulfiledCallbacks.push(()=>{
try{
let x = onFulfaild(that.value)
reslove(x)
}catch (e) {
reject(e)
}
})
that.onRejectedCallbacks.push(()=>{
try{
let x = onRejected(that.reason)
reslove(x)
}catch (e) {
reject(e)
}
})
}
})
return promise2;
}
其实学到这里,应该就可以够面试了,如果你还想对源码有更高的要求,那么还要继续往下学习。
网友评论