如果让你实现一个 promise ,你会怎么做?
自己实现promise的大体思路
- 我们要明确我们需要一个异步的操作方法,满足异步回调。所以选择加入setTimeout 作为实现的基础, 让函数实现延迟触发。
- 保持一个原则,控制 promise 改变状态的只有 promise 构造函数里的 reslove 、 reject 函数。
- 链式调用的原理, 类似jQuery,它会在调用方法后, return this. 从而形成链式调用。所以我们采用在调用then(fn)、 catch(fn) 后 会返回一个新的 promise 对象, 然而 这个 promise 对象 受到 它的上级promise 对象的状态结果 和 fn 运行结果的控制。
知识点:
里面 应该 用到点 js 作用域 、 函数闭包、 继承 、 上下文 绑定知识、引用传递。
存在问题
cbList、rhList、 cs 这个三个, Promise 对象能直接访问, 如果对其直接操作可能造成 程序紊乱。
代码如有纰漏,望大家指正
var JcPromise = function (fn) {
// 防止 用户 直接 更改 state
var state = 'wait'
// state 为 resolve 状态, 回调函数数组
var cbList = []
// state 为 reject 状态, 回调函数数组
var rjList = []
this.cbList = cbList
this.rjList = rjList
//
this.cs = undefined
// 获取 promise 的状态
this.getState = function () {
return state
}
/* 函数闭包,函数 定义在里面, 防止 外面用户 直接 使用 resolve 和 reject; */
// Promise成功触发 函数
var reslove = function (data) {
this.cs = data
if (state !== 'wait') {
return
} else {
state = 'solve'
while (this.cbList.length) {
cbList.shift()(data)
}
}
}
// Promise 拒绝 触发函数
var reject = function (e) {
this.cs = e
if (state !== 'wait') {
return
} else {
state = 'reject'
while (rjList.length) {
rjList.shift()(e)
}
}
}
// 绑定函数 conext 及 this 为当前 promise对象
reslove = reslove.bind(this)
reject = reject.bind(this)
// 延迟 触发
setTimeout(function () {
fn(reslove, reject)
}, 0)
}
JcPromise.prototype.then = function (fn) {
var handleObj = {}
var nextPromise = new JcPromise(function (r, j) {
handleObj.r = r
handleObj.j = j
})
var fixFn = function (data) {
var result = null
try {
result = fn(data)
// 判断result是不是 JcPromise实例。
if (result instanceof JcPromise) {
result.then(function (data) {
handleObj.r(data)
}).catch(function (e) {
handleObj.j(e)
})
} else {
handleObj.r(result)
}
} catch (e){
handleObj.j(e)
}
}
//判断当前状态 如果 是 solve 直接 运行, 如果不是,酒吧 fixFn 推入 cbList 数组。
if (this.getState() === 'solve') {
setTimeout(function () {
fixFn(this.cs)
}, 0)
} else {
this.cbList.push(fixFn)
}
return nextPromise
}
JcPromise.prototype.catch = function (fn) {
var handleObj = {}
var nextPromise = new JcPromise(function (r, j) {
handleObj.r = r
handleObj.j = j
})
var fixFn = function (e) {
var result = null
try {
result = fn(e)
if (result instanceof JcPromise) {
result.then(function (data) {
handleObj.r(data)
}).catch(function (e) {
handleObj.j(e)
})
} else {
handleObj.r(result)
}
} catch (e){
handleObj.j(e)
}
}
if (this.getState() === "reject") {
setTimeout(function () {
fixFn(this.cs)
}, 0)
} else {
this.rjList.push(fixFn)
}
return nextPromise
}
// 测试代码
var p = new JcPromise(function(r, j) {
setTimeout(function() {r(100)}, 3000)
}).then(data => {
console.log('1', data)
return new JcPromise((r, j) => {
setTimeout(() => {
r('hi')
}, 3000)
})
}).then(data => console.log('2', data)).then(function () {
console.log('xxx', xx + 1)
}).catch(e => console.log(e)).then(data => console.log(data, 'end'))
demo 测试
第二版 jcPromise 实现
var JcPromise = (function() {
function JcPromise(fn) {
fn = fn || noop;
var statusList = ['start', 'pending', 'succeed', 'err'];
var cbStatus = [0, 1];
var status = statusList[0];
var data = null;
var err = null;
var that = this;
var successFn = [];
var errFn = [];
function resolve(d) {
data = d;
that._changeStatus(2);
};
function reject(e) {
err = e;
that._changeStatus(3);
};
this.getData = function() {
return data;
};
this.getErr = function() {
return err
};
this.getStatus = function() {
return status
};
this._changeStatus = function(idx) {
switch (status) {
case statusList[2]:
case statusList[3]:
{
return false
}
};
status = statusList[idx];
if (status === statusList[3]) {
setTimeout(function() {
that._triggerCatch();
}, 0)
}
if (status === statusList[2]) {
setTimeout(function() {
that._triggerThen();
}, 0)
}
};
this._pushThenCb = function(cb) {
successFn.push({
status: cbStatus[0],
cb: cb
});
if (status === statusList[2]) {
this._triggerThen();
}
};
this._pushCatchCb = function(cb) {
errFn.push({
status: cbStatus[0],
cb: cb
});
if (status === statusList[3]) {
this._triggerCatch();
}
};
this._triggerThen = function() {
successFn.map(function(item) {
if (item.status === cbStatus[0]) {
item.cb(data);
item.status = cbStatus[1];
}
})
};
this._triggerCatch = function() {
errFn.map(function(item) {
if (item.status === cbStatus[0]) {
item.cb(err);
item.status = cbStatus[1];
}
})
};
this._changeStatus(1);
this.uuid = uuid++;
try {
fn(resolve, reject);
} catch (e) {
reject(e)
}
return this
};
JcPromise.fn = JcPromise.prototype;
// 返回一个promise
JcPromise.fn.then = function(cb) {
var promiseR = null;
var promiseJ = null;
var result = null;
var that = this;
var fn = function() {
setTimeout(function() {
try {
var data = that.getData();
result = cb(data);
if (typeof result === 'object' && result !== null && result.constructor === JcPromise) {
result.then(function(data) {
promiseR(data)
}).catch(function(e) {
promiseJ(e)
})
} else {
promiseR(result)
}
} catch (e) {
promiseJ(e)
}
}, 0);
};
this._pushThenCb(fn);
// 触发promise
return new JcPromise(function(r, j) {
promiseR = r;
promiseJ = j;
});
};
// 返回一个promise
JcPromise.fn.catch = function(cb) {
var promiseR = null;
var promiseJ = null;
var result = null;
var that = this;
var fn = function() {
setTimeout(function() {
try {
var data = that.getErr();
result = cb(data);
if (typeof result === 'object' && result !== null && result.constructor === JcPromise) {
result.then(function(data) {
promiseR(data)
}).catch(function(e) {
promiseJ(e)
})
} else {
promiseR(result)
}
} catch (e) {
promiseJ(e)
}
}, 0)
};
this._pushCatchCb(fn);
// 触发promise
return new JcPromise(function(r, j) {
promiseR = r;
promiseJ = j;
});
};
return JcPromise
})();
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。