$.Deferred reject已忽略,在特定情况下不会触发任何回调

$.Deferred reject ignored and does not fire any callbacks in a specific situation

本文关键字:回调 任何 在特定情况下 reject Deferred      更新时间:2023-09-26

我正在尝试制作一个淡入,在淡入的位置停止淡入,并从淡入停止时的不透明度开始淡入。目前,当我第一次键入键时,如果我用另一个按键中断淡入,它将导致animOpacityPromise在页面刷新之前永远无法解析。如果我让fadeOut完成,任何后续的animOpacityPromiseCtrl.reject();都将被忽略,直到页面刷新,允许fadeOut结束。例如,在JSFiddle中,如果我键入一个密钥,等待我在日志中看到clearOverlay animate promise completed,然后键入"ABC",等待它开始淡出并用"SS"中断它的淡出,覆盖将立即在第一个s上消失,并在第二个s上重新出现内容"SS"。预期的行为是,在覆盖完成淡出之前,它不会清除searchString和覆盖,而是用淡入来中断淡出,并将键附加到搜索字符串和覆盖上。如果我用键击中断第一个淡出,动画行为就是我想要的淡入,淡入会在它所在的位置停止淡出,并从淡出停止时的不透明度开始淡入,但在页面刷新之前,animOpacityPromise.doneanimOpacityPromise.always永远不会在任何键击中调用。

JSFiddle

function initQuickSearch() {
  var overlay = $('#searchOverlay');
  var overlayIsFadingOut = false;
  var fadeOutTimeOut;
  var searchString = '';
  var animOpacityPromiseCtrl = $.Deferred();
  function showOverlay() {
    var fadeDelay = 200;
    if (overlayIsFadingOut) {
      console.log('clearOverlay animate promise rejected');
      animOpacityPromiseCtrl.reject();
      overlayIsFadingOut = false;
      clearTimeout(fadeOutTimeOut);
      fadeDelay = 100;
    }
    overlay.css({'visibility': 'visible'});
    overlay.stop(true, false).animate({opacity: 1}, {duration: fadeDelay, queue: true}, 'easeOutQuint');
  }
  function clearOverlay(bool) {
    var fadeDelay = 1000;
    var fadeDuration = 400;
    var animOpacityPromise;
    if (bool === true) {
      fadeDelay = 0;
      fadeDuration = 200;
    }
    overlayIsFadingOut = true;
    fadeOutTimeOut = setTimeout(function() {
      console.log('clearOverlay setTimeout called');
      animOpacityPromise = $.when(overlay.animate(
        {opacity: 0},
        {
          duration: fadeDuration,
          queue: true,
          start: function() {
            console.log('Fade out started.');
          },
          done: function() {
            console.log('Fade out done. Resolving promise.');
            animOpacityPromiseCtrl.resolve();
          }
        },
      'easeOutQuint').promise(), animOpacityPromiseCtrl);
      animOpacityPromise.done(function() {
        console.log('clearOverlay animate promise completed');
        overlay.css({'visibility': 'hidden'});
        searchString = '';
        $('#searchOverlay span').html('');
      });
      animOpacityPromise.always(function() {
        console.log('clearOverlay animate promise always');
        overlayIsFadingOut = false;
      });
    }, fadeDelay);
  }
  function addChar(char) {
    searchString = searchString + String.fromCharCode(char.which);
    console.log('Character "' + String.fromCharCode(char.which) + '" added to searchString. searchString is now "' + searchString + '"');
    $('#searchOverlay span').append(String.fromCharCode(char.which));
  }
  function removeChar() {
    searchString = searchString.substring(0, searchString.length - 1);
    $('#searchOverlay span').text(function(iter, txt) {
      return txt.slice(0, -1);
    });
  }
  $(window).keydown(function(key) {
    //If it's not an alphabetical character or the backspace key.
    if (!(key.which > 64 && key.which < 91) && key.which != 8) {
    } else {
      showOverlay();
      clearOverlay();
      if (key.which == 8) {
        removeChar();
      } else if (searchString.length <= 20) {
        addChar(key);
        key.preventDefault();
      } else {
        return false;
      }
    }
  });
  overlay.click(function() {
    clearOverlay(true);
  });
}

错误在于它一直重复使用同一个promise对象。因此,每次调用clearOverlay时,我都会将animOpacityPromiseCtrl分配给一个新的延迟对象,它就解决了这个问题。

更新了JSFiddle。