如果在延迟回调中调用jQuery.hide(),则不会触发回调

时间:2014-08-12 22:09:35

标签: javascript jquery callback jquery-deferred deferred

我正在[{3}}的[分叉],添加支持以允许事件处理程序返回jWizard

以下代码按预期工作:

  1. 调用元素的“stephide”事件。
  2. 如果未取消该活动,请隐藏该元素。
  3. 隐藏元素时,调用其stephidden事件。
  4. (针对此问题进行了简化; Promise objects

    /** Invokes the `stephide` event for the current element and hides
     *   it if the event handler doesn't prevent it.
     *
     * @param $el {jQuery} Element that will be hidden.
     */
    _leave: function ($el) {
      var event = $.Event("stephide"),
          dfd = $.Deferred(),
          effect = { effect: "blind", direction: "left", duration: 250 };
    
      $el.trigger(event);
    
      if(event.isDefaultPrevented()) {
        dfd.reject();
      } else {
        $el.hide(effect, function() {
          $el.trigger("stephidden");
          dfd.resolve();
        });
      }
    
      return dfd.promise();
    }
    

    但是,当我修改代码以期望Promise时,传递给$el.hide()的回调不会触发。元素隐藏,但回调不会被调用。

    _leave: function ($el) {
      var event = $.Event("stephide"),
          dfd = $.Deferred(),
          effect = { effect: "blind", direction: "left", duration: 250 };
    
      $el.trigger(event);
    
      // event.returnValue is a Promise object; see below.
      $.when(event.returnValue).then(
        function() {
          // $el.hide DOES run...
          $el.hide(effect, function() {
    
            // ... but this code never does!
            console.log("stephidden");
            $el.trigger("stephidden");
            dfd.resolve();
    
          });
        },
        dfd.reject
      );
    
      return dfd.promise();
    }
    
    /** Event handler for the stephide event.
     */
    $("...").on("stephide", function(event) {
      var dfd = $.Deferred();
    
      // ...
    
      event.returnValue = dfd.promise();
    });
    

    我做错了什么?

1 个答案:

答案 0 :(得分:0)

我看到以下可能的问题:

  1. 如果hide.returnValue是一个承诺而且当你认为它没有得到解决时,则可能会导致问题(我们看不到该代码)。

  2. 如果某些内容中断了隐藏动画(例如动画完成前的.hide()),则不会调用.stop()的回调。您可以使用.promise()而不是回调来解决中断的问题,因为即使动画停止也会一直解决。

  3. 如果在动画完成之前从DOM中删除了对象(使用类似jQuery .remove().empty().html()的父级,那么它将不会调用这是回调。

  4. 如果你要返回一个承诺,它通常也是一个更简单的界面,总是返回一个承诺(在hide.returnValue中)。如果没有什么可以等待,那么只需返回已经解决的承诺。这使得调用代码变得更加简单,因为他们可以假设那里有一个承诺并编写一组代码。你觉得它听起来有时只是一个承诺,这是一个很难编码的。

    我建议简化你的承诺代码,你可以使用现有的承诺。


    我认为你可以用这个简化的代码做你想做的一切:

    _leave: function ($el) {
      var event = $.Event("stephide"),
          effect = { effect: "blind", direction: "left", duration: 250 };
    
        $el.trigger(event);
    
        return $.when(event.returnValue).then(function() {
            return $el.hide(effect).promise().then(function() {
                console.log('stephidden');
                $el.trigger("stephidden");
            });
        });
    }
    

    如果hide.returnValue始终是承诺,则您不需要$.when(),因为您可以直接在承诺上致电.then()。围绕它使用$.when()即使.then()不是承诺,hide.returnValue也会执行。

    这也使用内置的.promise()函数来隐藏动画而不是回调,以提高其可靠性和使用promises的一致性。


    如果event.returnValue始终是承诺对象,则可以使用此缩短版本:

    _leave: function ($el) {
      var event = $.Event("stephide"),
          effect = { effect: "blind", direction: "left", duration: 250 };
    
        $el.trigger(event);
    
        return event.returnValue.then(function() {
            return $el.hide(effect).promise().then(function() {
                console.log('stephidden');
                $el.trigger("stephidden");
            });
        });
    }