共计 3245 个字符,预计需要花费 9 分钟才能阅读完成。
今天瞅了下 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…