为什么回调比承诺更“紧密耦合”?

时间:2014-01-15 15:43:29

标签: javascript jquery callback promise

您能解释一下以下短语(取自an answer to Stack Overflow question What are the differences between Deferred, Promise and Future in Javascript?)吗?

使用jQuery承诺反对使用以前的jQuery回调有什么优点?

  

而不是直接将回调传递给函数,而不是   可以导致紧密耦合的接口,使用promises允许一个   对同步或异步代码的单独关注。

5 个答案:

答案 0 :(得分:49)

A promise is an object that represents the result of an asynchronous operation,因此你可以传递它,这会给你更大的灵活性。

如果使用回调,则在调用异步操作时必须指定如何处理,因此需要耦合。有了承诺,您可以指定以后如何处理。

以下是一个示例,假设您想通过ajax加载一些数据,并且在执行此操作时您希望显示加载页面。

使用回调:

void loadData = function(){
  showLoadingScreen();
  $.ajax("http://someurl.com", {
    complete: function(data){
      hideLoadingScreen();
      //do something with the data
    }
  });
};

处理返回数据的回调必须调用hideLoadingScreen。

使用promises,您可以重写上面的代码段,使其更具可读性,并且您不必将hideLoadingScreen置于完整的回调中。

承诺

var getData = function(){
  showLoadingScreen();
  return $.ajax("http://someurl.com").promise().always(hideLoadingScreen);
};

var loadData = function(){
  var gettingData = getData();
  gettingData.done(doSomethingWithTheData);
}

var doSomethingWithTheData = function(data){
 //do something with data
};

更新:我已经写了blog post,提供了额外的示例,并提供了明确说明什么是承诺以及如何将其使用与使用回调进行比较。< / p>

答案 1 :(得分:27)

耦合对承诺更宽松,因为操作不必“知道”它是如何继续的,它只需要知道它何时准备就绪。

当你使用回调时,异步操作实际上引用了它的继续,这不是它的业务。

使用promises,您可以在决定如何解决之前,轻松地在异步操作上创建表达式。

因此,承诺有助于将链接事件与实际工作的关注分开。

答案 2 :(得分:12)

我不认为承诺比回调更多或更少耦合,差不多。

然而,承诺还有其他好处:

  • 如果你公开一个回调,你必须记录它是否会被调用一次(比如在jQuery.ajax中)或者不止一次(比如在Array.map中)。承诺总是被召唤一次。

  • 无法在其上调用回调抛出和异常,因此您必须为错误情况提供另一个回调。

  • 只有一个回调可以注册,多个用于承诺,你可以在事件发生后注册它们,无论如何你都会被调用。

  • 在类型化声明(Typescript)中,Promise使签名更容易阅读。

  • 将来,您可以利用async / yield语法。

  • 因为它们是标准的,所以你可以像这样制作可重复使用的组件:

     disableScreen<T>(promiseGenerator: () => Promise<T>) : Promise<T>
     {
         //create transparent div
         return promiseGenerator.then(val=>
         {
            //remove transparent div
            return val;
         }, error=>{
             //remove transparent div
             throw error;
         });
     }
    
     disableScreen(()=>$.ajax(....));
    

更多相关内容:http://www.html5rocks.com/en/tutorials/es6/promises/

编辑:

  • 另一个好处是编写一系列N个异步调用,没有N级缩进。

此外,虽然我仍然认为这不是主要观点,但现在我认为它们因为这个原因而松散耦合:

  • 它们是标准的(或者至少是尝试):使用字符串的C#或Java中的代码比C ++中的类似代码更加糟糕,因为字符串的不同实现使其更具可重用性。有一个标准的承诺,调用者和实现彼此之间的耦合较少,因为他们不必同意自定义参数命令,名称等的(一对)自定义回调...事实上有很多不同承诺的味道无济于事。

  • 他们推广更多基于表达式的编程,更容易编写,缓存等。:

      var cache: { [key: string] : Promise<any> };
    
      function getData(key: string): Promise<any> {
          return cache[key] || (cache[key] = getFromServer(key)); 
      }
    

你可以说基于表达式的编程比基于命令/回调的编程更松散耦合,或者至少他们追求相同的目标:可组合性。

答案 3 :(得分:5)

Promise将延迟回应的概念归结为某种东西。 他们使异步计算成为一流的公民,因为你可以传递它。它们允许您根据需要定义结构 - 一元结构 - 您可以在其上构建更高阶的组合器,从而大大简化代码。

例如,你可以有一个函数,它接受一个promises数组并返回一个数组的promise(通常称为sequence)。回调很难做到甚至不可能做到这一点。这样的组合器不仅使代码更容易编写,而且使它更容易阅读。

现在考虑另一种方式来回答你的问题。回调是一种特殊的解决方案,承诺允许更清晰的结构和可重用性。

答案 4 :(得分:4)

他们不是,这只是一种合理化,完全忽略了承诺点的人用来证明编写比使用回调编写的代码更多的代码。鉴于这样做显然没有任何好处,你至少可以告诉自己代码不那么耦合或者什么。

请参阅what are promises and why should I use them了解实际的具体好处。