今天瞅了下ssh大神的《最简实现Promise,支持异步链式调用(20行)》这篇文章 还真的是从进阶到入院(人已疯!!!)
我尝试直接去阅读这20代码 表示根本看不懂
function Promise(fn) {
this.cbs = [];
const resolve = (value) => {
setTimeout(() => {
this.data = value;
this.cbs.forEach((cb) => cb(value));
});
}
fn(resolve.bind(this));
}
Promise.prototype.then = function (onResolved) {
return new Promise((resolve) => {
this.cbs.push(() => {
const res = onResolved(this.data);
if (res instanceof Promise) {
res.then(resolve);
} else {
resolve(res);
}
});
});
};
这就是那20行代码
我承认我是个笨鸟 没那个大局观 所以只能用自己的办法去理解 就是逐行的分析 拿原生js对比对(感觉在作弊)
先上原生js
new Promise((resolve) => {
setTimeout(() => {
resolve(1)
})
})
.then((res) => {
console.log("res", res)
return 2
// return new Promise((resolve) => {
// setTimeout(() => {
// resolve(2)
// })
// })
})
.then((res) => {
console.log("res", res)
})
分析:
1、Promise是个构造函数 传递函数fn 函数fn接收函数resolve
2、函数resolve传递res
3、构造函数Promise的原型上有个函数then 函数then传递函数onResolved
4、函数onResolved接收res
分析后去代码实现
function Promise(fn) {
function resolve(value) {
}
fn(resolve.bind(this))
}
Promise.prototype.then = function (onResolved) {
}
这里有个重点 因为new Promise(() => {})传递的函数fn是直接执行的 所以构造函数Promise的内部直接调用了函数fn
然后考虑如何把resolve(1)和then((res) => {res // 1})串联上
function Promise(fn) {
this.cbs = []
function resolve(value) {
this.cbs.forEach((cb) => {
cb(value)
});
}
fn(resolve.bind(this))
}
Promise.prototype.then = function (onResolved) {
this.cbs.push(onResolved)
}
这里通过定义了一个cbs函数集 通过函数then去收集函数onResolved 然后函数resolve去触发 看似没问题 其实是没效果的 因为还没有来得及收集 就触发了
真正的代码应该这样
function Promise(fn) {
this.cbs = []
function resolve(value) {
setTimeout(() => {
this.cbs.forEach((cb) => {
cb(value)
});
})
}
fn(resolve.bind(this))
}
Promise.prototype.then = function (onResolved) {
this.cbs.push(onResolved)
}
函数resolve的方法体内加了个setTimeout 这个setTimeout的作用有俩 一是确实触发函数resolve是个异步操作 二是保证先收集完再触发 现在就基本成型了
最后就是考虑如果链式调用 .then(() => {}).then(() => {}) 这块属实烧到我了 基本就是靠着比对去理解
首先如果想链式.then(() => {}).then(() => {}) 那么第一个.then(() => {})完后 返回的也应该是一个Promise实例 所以代码应该长成这样
function Promise(fn) {
this.cbs = []
function resolve(value) {
setTimeout(() => {
this.cbs.forEach((cb) => {
cb(value)
});
})
}
fn(resolve.bind(this))
}
Promise.prototype.then = function (onResolved) {
return new Promise((resolve) => {
this.cbs.push(onResolved)
})
}
但是这样.then(() => {}).then(() => {})第二个.then(() = >{})并不会被触发 所以需要手动触发 对了 第二个.then(() => {})是属于return new Promise的 这个很重要
function Promise(fn) {
this.cbs = []
function resolve(value) {
setTimeout(() => {
this.data = value
this.cbs.forEach((cb) => {
cb(value)
});
})
}
fn(resolve.bind(this))
}
Promise.prototype.then = function (onResolved) {
return new Promise((resolve) => {
this.cbs.push(() => {
const res = onResolved(this.data)
resolve(res)
})
})
}
考虑到.then(() => {return 2}).then((res) => {res // 2})会有这样一个效果 所以push函数onResolved就需要包裹一层函数 这样就能够处理函数onResolved的返回值res 然后再触发return new Promise的
resolve(res) 就可以触发第二个.then((res) => {res // 2}) 就可以接受到2了
真真最后还需要考虑到.then(() => {return new Promise((resolve) => {setTimeout(() => {resolve(2)}, 500)})}).then((res) => {res // 2})这种效果 所以继续改造
function Promise(fn) {
this.cbs = []
function resolve(value) {
setTimeout(() => {
this.data = value
this.cbs.forEach((cb) => {
cb(value)
});
})
}
fn(resolve.bind(this))
}
Promise.prototype.then = function (onResolved) {
return new Promise((resolve) => {
this.cbs.push(() => {
const res = onResolved(this.data)
if (res instanceof Promise) {
res.then(resolve)
} else {
resolve(res)
}
})
})
}
解释一下 如果函数onResolved的返回值res是构造函数Promise的实例 那么调用流程是这样的 首先res.then方法会收集return new Promise的resolve 然后.then(() => {return new Promise((resolve) => {setTimeout(() => {resolve(2)}, 500)})})这个resolve(2)就会触发return new Promise的resolve 最后执行return new Promise的.then也就是第二个.then
写的有点乱
客观对付看
skr...