什么时候需要创建一个延迟?

IT技术 javascript promise ecmascript-6 bluebird es6-promise
2021-02-28 02:54:09

现在似乎普遍不鼓励创建延迟对象,而赞成使用 ES6 风格的 Promise 构造函数。是否存在需要(或更好地)使用延迟的情况?

例如,在此页面上,给出了以下示例作为使用延迟的理由:

function delay(ms) {
    var deferred = Promise.pending();
    setTimeout(function(){
        deferred.resolve();
    }, ms);
    return deferred.promise;
}

然而,这也可以用 Promise 构造函数来完成:

function delay(ms) {
    return new Promise(function(resolve, reject){
        setTimeout(function(){
            resolve();
        }, ms);
    });
}
2个回答

是否存在需要(或更好地)使用延迟的情况?

没有这种情况需要延期。“更好”是一个见仁见智的问题,所以我不会在这里解决这个问题。

ES6 Promise规范没有延迟对象是有原因的。 你根本不需要一个。 人们过去使用延迟对象的任何事情可以用另一种不使用延迟对象的方式来完成。

首先,大多数用途非常适合Promise构造函数模型。其次,任何其他不完全适合该模型的情况仍然可以使用 promise 构造函数或从已解决的 promise 开始并链接到它来完成。

我见过的 deferred 的主要用例是,当您想要将功能传递给resolve()reject()关闭除创建Promise的代码之外的其他代码段时。Deferred 使这变得非常容易,因为您可以只传递 deferred 对象,并且它具有用于解决或拒绝它的公共方法。但是,有了Promise,您也可以通过resolve和/或reject方法。由于它们自动绑定到特定对象,因此您只需传递函数引用即可。而且,在其他情况下,您可以让其他代码创建自己的Promise并自行解决/拒绝它,并将该操作链接到您的操作,而不是让他们解决/拒绝您的Promise。所有这一切都和传递一个延迟对象一样干净吗?主要是见仁见智,但都不是很常见的用例,所有这些都可以在没有单独的延迟对象的情况下完成。

而且,正如 torazaburo 指出的那样,让一些外部代码解决或拒绝您的Promise本身就是一种反模式。您创建了Promise - 您解决/拒绝了它。如果您想使用外部事件来决定何时解决/拒绝它,那么让他们通知您(通过他们自己的Promise或回调),您可以解决/拒绝您自己的Promise。或者,让他们创建自己可以使用的Promise。这才是真正想要的模型。或者,让他们链接到您的Promise上,以便在他们的操作完成时控制最终结果。

如果人们习惯于使用延迟对象进行编码(比如使用 jQuery 延迟),可能需要一点时间来适应没有它的编码,但是过了一会儿,您就会开始不同的思考,并且开始变得自然而然就可以使用Promise构造函数。

一旦您Promise了您在任何给定应用程序中使用的异步操作领域,您甚至不再需要创建自己的Promise就非常罕见了,因为您大多只是构建您调用的异步函数已经创建或使用的Promise流控制操作,例如Promise.all()为您创建超级Promise。

这是反模式的要点。 使用已经为您创建的Promise,而不是手动创建更多Promise。 把它们锁起来。.then()处理程序返回Promise以在逻辑控制下链接异步操作。

当然,现有的异步操作不会返回需要有人为其创建Promise的Promise,但这应该在主要编码逻辑范围之外的某个地方的Promise层中完成,并且只为该操作完成一次,然后调用异步操作的代码应该能够只使用返回的Promise。

@torazaburo - 我同意。由于我已经摆脱了 jQuery Deferred 对象,只是习惯了一种不同的编码方式,我从来没有找到使用或需要这种编码模式的理由。如果您使用外部事物来触发解决您创建的Promise,您可以随时让他们以其他方式通知您(通过他们自己的Promise或通过回调),然后您就可以解决您自己的Promise。但是,似乎我们都不愿明确地说从来没有这样一个有效的案例(我们真的无法证明没有这样的案例),因此我提供了一个解决方法以防万一。
2021-04-15 02:54:09
@mderk - 如果你描述一个现实世界的问题,那么我可以尝试一下如何在不使用延迟的情况下解决它。我个人从未遇到需要Promise的Promise(无法使用链接的地方),所以我不知道现实世界的情况会是什么,因此无法真正为您提供合适的替代方案。我可以为您的理论问题提出一个理论上的解决方案,但这似乎没有用,因为到目前为止您对代码的描述假设了很多实现,如果知道整个问题,则可能不必以这种方式完成.
2021-04-19 02:54:09
@jfriend00 对尚未创建的Promise的Promise如何?例如,应该在未来某个时刻触发的“罐头”网络请求:/* in a function that prepares the request */ var deferred = Promise.defer(); function makeRequest() { doMakeRequest().then(function(data) {deferred.resolve(data)}) .catch(function(e) {deferred.reject(e)}); } queue.push(request); return deferred.promise; ..... /* at some point later in another galaxy */ makeRequest = queue.shift(); makeRequest(); 同步 Promise 构造函数怎么可能?
2021-04-25 02:54:09
是的,很好的解释。但是,关于将resolve() 或 reject() 的能力传递给创建 promise 的代码以外的其他代码片段,值得指出的是,这本身就是一种反模式。Promise 构造函数的设计旨在促进在回调中封装所有 Promise 逻辑,至少在可能的范围内,这几乎是所有时间。
2021-04-29 02:54:09
@mderk - 另外,如果你想讨论一个特定的问题以及如何在没有延迟的情况下解决它,那么我建议你发布一个描述你的问题的新问题,然后给我留言,通知我新问题,因为我认为您无法在这里仅通过评论来完全描述您想要做什么。
2021-05-11 02:54:09

Native Promises 并没有 deferred 开箱即用的所有内置方法,例如在其构造函数范围之外解析 promise 的方法(尽管使用 native Promise 很容易实现),以及能够查看 Promise 的状态(尽管它可以在开发工具中检查,但它对原生 Promise 的常规 JavaScript 是隐藏的)。

今天使用 deferred 的主要原因是与依赖于这些额外方法的代码向后兼容。在不涉足意见领域的情况下,很难对您的问题给出明确的答案。