丁老师学习名言
你用你会的知识去解释他, => 解释通了, 你就明白了
=> 解释不通, 该学习了!!
继续..
step1
constructor () {
...
用来存放then中的回调
this.resoveCB = null;
this.rejectCB = null;
}
...
then (resolveFn,rejectFn) {
...
if (this.state == "pending") {
return new myPromise((resolve, reject) => {
this.resolveCB = ((resolveFn)=>{
return () => {
var res = resolveFn(this.data);
}
})(resolveFn);
})
}
}
从这里开始就烧脑了,,,
首先我们需要在 'pending' 时先返回一个对象,
我们需要在 this.resolveCB中存一下函数resolveFn
但我们还需要把相应的参数也放进去 所以套了一层 函数绑定参数.
step2
if (this.state == "pending") {
return new myPromise((resolve, reject) => {
this.resolveCB = ((resolveFn)=>{
return () => {
var res = resolveFn(this.data);
if (res instanceof myPromise) {
res.then(resolve,reject);
} else{
resolve(res)
}
}
})(resolveFn);
})
}
刚开始确实是没看懂,
跟着执行顺序捋了一遍, 为什么这个逻辑成立是理解了.
因为pending 所以我们用this.resolveCB 来存了一下 函数,
返回了一个新的中间promise对象, 当前一个promise对象有了状态的变化时,
这个对象也要跟着改变对象,
如果有new了一个新的 new Promise对象, 就需要在这个new Promise对象的
状态改变时, 把中间的promise状态改变, 这样才能触发 保存的函数?
这里回头再思考
step3 补齐一下rejiect 这边
if (this.state == "pending") {
return new myPromise((resolve, reject) => {
this.resolveCB = ((resolveFn)=>{
return () => {
var res = resolveFn(this.data);
if (res instanceof myPromise) {
res.then(resolve,reject);
} else{
resolve(res)
}
}
})(resolveFn);
this.rejectCB = ((rejectFn)=>{
return () => {
var res = rejectFn(this.data);
if (res instanceof myPromise) {
res.then(resolve,reject);
} else{
resolve(res)
}
}
})(rejectFn);
})
}
有一个地方我有点懵逼, 或者之前我理解有错误.
我以为promise 的后序then中 只要有一次进入 resolve 之后的都会进入resolve
有一次进入 reject 之后的都会进入rejiect
但老师写的reject 里 向下传递的状态是 resolve
也就是说 reject 线路还会回到 resolve?
测试
let P = new Promise((res,rej) => {
rej(123)
}).then(null,(data) => {
console.log(data);
return 223
}).then(null,(data) => {
console.log(data);
})// 按我之前的理解, 应该是返回223 但没有
let P = new Promise((res,rej) => {
rej(123)
}).then(null,(data) => {
console.log(data);
return 223
}).then((data) => {
console.log(data);
})// 返回了223
这要怎么理解呢?
也就是说默认then 执行过后返回的promise对象的状态都是 resolved
除非回调中返回的是新的 promise 对象.
step4
为了以下这种情况
let p = new myPromise((res,rej) => {
rej(123)
})
p.then(null,(data) => {console.log(data + 200)});
p.then(null,(data) => {console.log(data)});
constructor(){
...
this.resolveCB = [];
this.rejectCB = [];
let resolve = (data) => {
if (this.state == "pending") {
this.state = "resolved"
this.data = data;
this.resolveCB.forEach(fn => fn());
}
}
let reject = (data) => {
if (this.state == "pending") {
this.state = "rejected"
this.data = data;
this.rejectCB.forEach(fn => fn());
}
}
}
...
then(resolveFn,rejectFn){
...
if (this.state == "pending") {
return new myPromise((resolve, reject) => {
this.resolveCB.push((resolveFn)=>{
return () => {
var res = resolveFn(this.data);
if (res instanceof myPromise) {
res.then(resolve,reject);
} else{
resolve(res)
}
}
})(resolveFn);
this.rejectCB.push((rejectFn)=>{
return () => {
var res = rejectFn(this.data);
if (res instanceof myPromise) {
res.then(resolve,reject);
} else{
resolve(res)
}
}
})(rejectFn);
})
}
}
step5
让所有同步操作都变成异步?
let resolve = (data) => {
if (this.state == "pending") {
setTimeout(() => {
this.state = "resolved"
this.data = data;
this.resolveCB.forEach(fn => fn());
},0)
}
}
let reject = (data) => {
if (this.state == "pending") {
setTimeout(() => {
this.state = "rejected"
this.data = data;
this.rejectCB.forEach(fn => fn());
},0)
}
}
贴一下完整版
class myPromise {
constructor (fn) {
if (typeof fn !== "function") {
throw TypeError(`myPromise resolver ${fn} is not a function`)
}
this.state = "pending";
this.data = undefined;
this.resolveCB = [];
this.rejectCB = [];
let resolve = (data) => {
if (this.state == "pending") {
setTimeout(() => {
this.state = "resolved"
this.data = data;
this.resolveCB.forEach(fn => fn());
},0)
}
}
let reject = (data) => {
if (this.state == "pending") {
setTimeout(() => {
this.state = "rejected"
this.data = data;
this.rejectCB.forEach(fn => fn());
},0)
}
}
fn(resolve,reject);
}
then (resolveFn, rejectFn) {
if (this.state == "resolved") {
let rus = resolveFn(this.data);
if (rus instanceof myPromise) {
return rus
}else{
return myPromise.resolve(rus);
}
}
if (this.state == "rejected") {
let rus = rejectFn(this.data);
if (rus instanceof myPromise) {
return rus
}else{
return myPromise.resolve(rus);
}
}
if (this.state == "pending") {
return new myPromise((resolve, reject) => {
console.log(this.resolveCB);
this.resolveCB.push(((resolveFn)=>{
return () => {
var res = resolveFn(this.data);
if (res instanceof myPromise) {
res.then(resolve,reject);
} else{
resolve(res)
}
}
})(resolveFn));
this.rejectCB.push(((rejectFn)=>{
return () => {
var res = rejectFn(this.data);
if (res instanceof myPromise) {
res.then(resolve,reject);
} else{
resolve(res)
}
}
})(rejectFn));
})
}
}
static resolve (data) {
return new myPromise((suc) => {
suc(data);
})
}
static reject (data) {
return new myPromise((suc,err) => {
err(data);
})
}
}
思考
实际上到昨天的同步处理为止,都是比较简单的.
到了要解决异步问题的时候,
我们发现必须要先返回一个对象, 并且要把函数先保存下来.
问题还在于, 我们要进行链式调用, 在明确每次then返回的对象都不相同时,
我们要解决一个问题就是,对象间的传递.
传递状态, 传递数据, 传递函数?
昨天我写得异常暴力版本,主要就是想不通怎么传递,
因为传递状态和数据的接口已经写好了, 理论上就应该用这两个接口
但这两个接口貌似只能在 new 新对象的时候才能传.
我们看一下就会发现, 丁老师的版本是怎么传的呢?
他确实是先返回了一个对象, 也是存了函数,
最核心的就是开篇讲的, 他在存函数的时候, 用函数的多层嵌套的方式,
把数据和函数一起绑定之后的函数放进了数组里.
然后在这个函数中调用各个接口,完成三个对象之间的状态,数据的传递.
当然我觉得我还是很难想到,但比刚开始好多了.
这应该是最近看到的代码中最漂亮的代码了.
发现可以简化一下, 如果把所有同步任务改成异步执行,
那then 可以不用判断 状态, 直接就是返回新对象
class myPromise {
constructor (fn) {
this.state = "pending";
this.data = null;
this.rejectCB = [];
this.resolveCB = [];
let resolve = (data) => {
if (this.state == "pending") {
// 让同步任务变成异步执行
setTimeout(() => {
this.state = "resolved";
this.data = data;
this.resolveCB.forEach(item => {
item();
})
},0)
}
}
let reject = (data) => {
if (this.state == "pending") {
// 让同步任务变成异步执行
setTimeout(() => {
this.state = "rejected";
this.data = data;
this.rejectCB.forEach(item => {
item();
})
},0)
}
}
fn(resolve,reject);
}
static resolve (data) {
return new myPromise((suc) => {
suc(data);
})
}
static reject (data) {
return new myPromise((suc,fail) => {
fail(data);
})
}
then (resolveFn,rejectFn) {
// 只需要保证 上面的异步执行晚于这个操作
// 那么这里可以不用判断状态, 统一返回中间对象
return new myPromise((res,rej) => {
this.resolveCB.push(() => {
let rus = resolveFn(this.data);
if (rus instanceof myPromise) {
rus.then(res,rej);
} else{
res(rus);
}
});
this.rejectCB.push(() => {
let rus = rejectFn(this.data);
if (rus instanceof myPromise) {
rus.then(res,rej);
} else{
res(rus);
}
});
})
}
}
这里有个主意的地方,
我刚开始想, 如果要把同步改成异步执行,可以这样
class myPromise {
constructor (fn) {
this.state = "pending";
this.data = null;
this.rejectCB = [];
this.resolveCB = [];
let resolve = (data) => {
if (this.state == "pending") {
this.state = "resolved";
this.data = data;
this.resolveCB.forEach(item => {
item();
})
}
}
let reject = (data) => {
if (this.state == "pending") {
this.state = "rejected";
this.data = data;
this.rejectCB.forEach(item => {
item();
})
}
}
我刚开始以为,只要在这里改成异步,不是更简洁?
> setTimeout(() => {
> fn(resolve,reject);
> },0)
}
但这是不行的, 之我们要改成异步的核心原因是,
resolveCB.push() 要比 resolveCB.forEach() 先执行.
如果改成上面这个样子.
resolveCB.push() 也会变成一个异步行为,
当执行异步任务的时候,
同为异步任务, resolveCB.forEach() 必然先执行.
想了大半天才理解这个道理.
总归来讲, promise 即使勉强会模拟了,
还是有很多地方不太理解.
你会发现整个接口都是提供回调函数的方式进行的.
如果按照我现在的思维方式,
我肯定下意识的想要提供一个mypromise.resolve() 这样对象调用接口.而不是回调的方式提供接口.
看来对函数应用的理解还是不够.
大牛们真是会玩.