我尝试用javascript实现一个简单的promise类,它具有可链接的.then()
功能。
class APromise {
constructor(Fn) {
this.value = null;
Fn(resolved => { this.value = resolved; });
}
then(fn) {
fn(this.value);
return this;
}
}
function myFun() {
return new APromise(resolve => {
// just resolve('Hello'); works but this doesn't
setTimeout(() => { resolve('Hello'); }, 2000);
});
}
const log = v => { console.log(v); };
myFun().then(log).then(log);
它输出-
null
null
而不是'Hello'
2次。我认为它目前正在忽略setTimeout()
调用,我应该如何使此工作?
3条答案
按热度按时间bfnvny8b1#
问题是
您的代码没有按您希望的方式工作,因为您将异步流与同步流混合在一起。
当你调用
.then()
时,它会同步返回this
,因为setTimeout()
是一个异步函数,在一段时间(2秒)后调用,所以this.value
仍然是null
。如果你想了解更多关于JS的异步流程,我推荐你看this video,它有点长,但是非常有帮助。
让您的代码工作
由于我们无法知道
setTimeout()
何时调用传递给它的函数,因此我们无法调用和回调依赖于它的操作的函数,我们将这些回调存储在一个数组中以供以后使用。当
setTimeout()
函数被调用(promise resolves)时,我们得到了promise resolves的结果,因此,我们现在调用所有绑定的回调函数。链接问题
上面的代码部分地解决了这个问题。
当一个回调函数的结果传递给下一个回调函数时,就实现了真正的链接。在我们当前的代码中,情况并非如此。要实现这一点,每个
.then(cb)
必须返回一个新的APromise
,该APromise
在cb
函数被调用时解析。一个完整且符合Promises/A+的实现远远超出了单个SO答案的范围,但这不应该给人一种它不可行的印象。
富勒实现
让我们从头开始,我们需要一个类
Promise
,它实现了一个方法then
,该方法也返回一个允许链接的承诺。在这里,
main
是一个函数,它 * 将一个函数作为参数 *,并在承诺得到解决/实现时调用它-我们将此方法称为resolve()
。上述函数resolve()
由我们的Promise
类实现和提供。then()
方法的基本特性是,一旦承诺实现,就用承诺值触发/激活提供的回调函数cb()
。考虑到这两点,我们可以重新连接
Promise
类。我们可以使用
tester()
函数测试当前代码。这就结束了我们的基础。现在我们可以实现链接。我们面临的最大问题是
then()
方法必须返回一个承诺同步,而这个承诺将被异步解决。我们需要等待解析 * parent promise *,然后才能解析 * next promise *。这意味着我们必须添加 * next promise * 的
resolve()
方法,而不是将cb()
添加到 * parent promise *,该方法使用cb()
的返回值作为其resolveValue
。如果这最后一点让你感到困惑,这里有一些提示:
Promise
构造函数接受函数main()
作为参数main()
将函数resolve()
作为参数resolve()
由Promise
构造函数提供resolve()
采用 * any * 类型的参数作为resolveValue
演示
r1wp621o2#
在Promise中调用同步时解决此问题:
或链条:
试验:
mftmpeh83#
我自己写了一个简单的承诺
为旧的僵尸浏览器(ES3以上版本)实现
我使用的
Promise
发现在旧的浏览器中这个类是不存在的,所以我为他们实现了一个有resolve
和reject
方法的类,这个方法是用babel传递的: