【问题标题】:Callback or Promise? [duplicate]回调还是承诺? [复制]
【发布时间】:2014-08-08 03:47:57
【问题描述】:

在使用 javascript 异步错误捕获机制时,我最终问自己,使用 Promise 与使用回调有什么区别,而且事实上 Promise 可能更具糖语法。

例如,让我们考虑

        function setPromise() {
            var message = "awesome";
            var deferred = new $.Deferred();
            setTimeout(function(){deferred.resolve(message)},3000);
            return deferred.promise();
        }

        var promise = setPromise();

        promise.done(function (message) {
            console.log("promise done with message : " + message);
        });

        function setCallback(doneCallback) {
            var message = "awesome";
            setTimeout(function(){doneCallback(message)},3000);
        }

        setCallback(callback)

        function callback(message) {
            console.log("callback done with message : " + message);
        }

两者都充当闭包,都允许返回参数等。

那么有什么区别呢?

【问题讨论】:

  • Promise 在自己的实现中使用回调,但也支持更多功能,例如处理程序链接、用于异步完成/错误通知的标准化接口等。这有点像在说函数和 OOP 之间有什么区别,一个是低级构造 - 另一个是使用相同低级构造的更强大的机制,但也支持更多的功能和可扩展性。当您有多个需要排序或协调的异步操作时,promise 的真正威力就出现了。

标签: javascript callback promise


【解决方案1】:

Promise 建立在回调之上。后者更原始、更通用,当你需要做一些复杂的事情时需要更多的工作。

对于您的示例,它们的作用几乎相同。但是,假设您希望同时解决三件事(想象同时通过 AJAX 请求三个资源),并在所有三件事都完成后继续。与承诺无关,因为基本上没有任何变化;但是对于回调,您需要设置一些标志/计数器,并自己识别成功和失败状态 - 更多工作。

【讨论】:

    【解决方案2】:

    从语义上讲,这两段代码之间确实没有真正的区别。消息在调用初始函数后的某个时间提供给回调。

    从设计的角度来看,人们倾向于使用 Promise,因为它们通常会使代码更易于遵循。在回调处理某些长时间运行的函数的结果时尤其如此。考虑以下两个运行缓慢的函数:

    var slowlyReturn1 = function (callback) {
      window.setTimeout(callback.call(1), 1000);
    }
    
    var slowlyReturn2 = function (callback) {
      window.setTimeout(callback.call(2), 1000);
    }
    

    使用这两个长时间运行的函数的结果编写代码非常麻烦:

    slowlyReturn1(function(resultOf1) {
      slowlyReturn2(function(resultOf2) {
        console.log("results were: " + resultOf1 + " and " + resultOf2);
      })
    });
    

    注意长时间运行的函数链中的每个链接如何导致另一个嵌套级别。使用 Promise 代码,您往往不会遇到这个问题:

    var slowlyReturn1 = function () {
      var d = $.Deferred();
      window.setTimeout(function () { d.resolve(1) }, 1000);
      return d.promise();
    }
    
    var slowlyReturn2 = function () {
      var d = $.Deferred();
      window.setTimeout(function () { d.resolve(2) }, 1000);
      return d.promise();
    }
    
    var resultOf1;
    
    slowlyReturn1().then(function(r) {
      resultOf1 = resultOf1;
      return slowlyReturn2();
    }).then(function(resultOf2) {
      console.log("results were: " + resultOf1 + " and " + r);
    });
    

    此外,使用 Promise 代码,关注点的分离往往更清晰。执行缓慢运行操作的代码不知道如何使用结果:它只是返回代表延迟结果的内容并让调用者处理它。

    这个你处理它设计的一个很好的应用程序围绕着异常处理。运行缓慢的操作可以.resolve() 承诺,但它们也可能.reject() 出现问题。可以使用.fail() 处理此拒绝,如下所示:

    slowRunningOperations().then(function () {
      ...
      ...
      ... handle success
      ...
      ...
    }).fail(function() {
      ...
      ... handle failure
      ...
      ...
    })
    

    在这里,慢运行操作的调用者不关心错误,它可以简单地忽略它们。

    promise 编程还有其他几个好处:

    • 大多数支持 Promise 的库都提供了一种方法来处理常规函数和返回 Promise 的函数。他们通常通过提供一个名为when() 的函数来实现这一点。这提供了一种非常好的方法来测试 promise 代码,或者允许将慢速函数更改为不影响调用者的 promise-returning-one。

    • 大多数支持 Promise 的库还提供了使用 Promise 模拟更传统的控制流的函数。例如,Q 库提供了 allSettled(list),它接受一个 Promise 列表并返回一个 Promise,该 Promise 在列表中的所有 Promise 都完成时解析。

    也就是说,正如另一个答案所述,承诺会带来一些开销。如果您没有进行密集的链接或错误处理,或者您将回调严格用于控制流,那么您最好只传递函数。

    【讨论】:

      猜你喜欢
      • 2016-06-15
      • 2020-06-02
      • 2014-04-27
      相关资源
      最近更新 更多