首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >延迟链崩溃浏览器

延迟链崩溃浏览器
EN

Stack Overflow用户
提问于 2015-08-30 19:46:48
回答 3查看 175关注 0票数 1

这是一个小功能,应该能够打开和关闭一个盒子。打开和关闭需要考虑一些CSS转换,所以我想我可以使用$.Deferred

以下是相关代码:

代码语言:javascript
复制
function Test(){

  // these are assigned Deferred objects during transitions
  this.opening = this.closing = false;

  this.isOpen = false;
  this.x = $('<div />').appendTo('body');
  this.x.width();
}

Test.prototype.open = function(){

  // box is already opening: return opening deferred
  if(this.opening)    
    return this.opening;

  // box is closing: this is the chain
  // that is supposed to wait for the box to close,
  // then open it again 
  if(this.closing)
    return this.closing.then((function(){
      return this.open();
    }).bind(this));

  // box is already open, resolve immediately
  if(this.isOpen)
    return $.when();    

  console.log('opening');
  this.opening = new $.Deferred();
  this.x.addClass('open');
  setTimeout((function(){
    this.opening.resolve();
    this.opening = false;
    this.isOpen = true;      
  }).bind(this), 1000);

  return this.opening;
};

函数的open()相反。

当我试图关闭正在打开的盒子时,问题就会出现,反之亦然。例如:

代码语言:javascript
复制
var t = new Test();

t.open(); // takes 1 second

// call close() after 0.05s
setTimeout(function(){
  t.close();
}, 50);

似乎发生了堆栈溢出之类的事情。有人知道是什么导致的吗?

整个测试代码是这里,但具有更高的超时值,因此不会使Chrome崩溃。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-08-30 21:11:24

我注意到代码中的几个问题:

  • 返回延迟对象而不是承诺,只能根据承诺执行.then()
  • 使用bool值重写延迟变量,我将使用deferred.state()代替

这是您的代码的更新版本:

代码语言:javascript
复制
function Test(){
  this.opening = this.closing = false;
  this.isOpen = false;
  this.x = $('<div />').appendTo('body');
  this.x.width();
}

Test.prototype.open = function(){
  if(this.opening && this.opening.state() == 'pending')    
    return this.opening.promise();

  if(this.closing && this.closing.state() == 'pending')
    return this.closing.promise().then((function(){
      return this.open();
    }).bind(this));

  if(this.isOpen)
    return $.when();    

  console.log('opening');
  this.opening = new $.Deferred();
  this.x.addClass('open');
  setTimeout((function(){
    this.isOpen = true;    
    this.opening.resolve();
  }).bind(this), 1000);

  return this.opening.promise();
};

Test.prototype.close = function(){
  if(this.opening && this.opening.state() == 'pending') {
    console.log('opening is pending');
    return this.opening.promise().then((function(){
      console.log('opening is resolved');
      return this.close();
    }).bind(this));
  }

  if(this.closing && this.closing.state() == 'pending'){    
    console.log('closing is pending');
    return this.closing.promise();
  }

  if(!this.isOpen)
    return $.when();    

  console.log('closing');
  this.closing = new $.Deferred();
  this.x.removeClass('open');
  setTimeout((function(){
    console.log('closing resolved');
    this.closing.resolve();
    this.isOpen = false;
  }).bind(this), 1000);

  return this.closing.promise();  
};

var t = new Test();

t.open();

setTimeout(function(){
  t.close();
}, 15);

产出:

代码语言:javascript
复制
"opening"
"opening is pending"
"opening is resolved"
"closing"
"closing resolved"
票数 2
EN

Stack Overflow用户

发布于 2015-08-30 21:40:05

这里有一个小小的时间问题。当您在.closing承诺之后或在.opening承诺之后链接打开或关闭时,将在删除承诺之前执行这些回调:

this.opening.resolve();this.opening = false;

问题是,jQuery确实在resolve内部同步执行,因此在关闭后被链接的“重试”this.open().closing允诺仍然存在时被调用,并将自己一次又一次地链接起来,然后再进行…。

你应该可以通过这样做来避免

代码语言:javascript
复制
var def = this.opening;
this.opening = false;
this.isOpen = true;
def.resolve(); // trigger those who are waiting to immediately close it again
票数 3
EN

Stack Overflow用户

发布于 2015-08-31 12:32:42

我无法克服Bergi对“堆栈溢出”问题的解释,但是我不禁认为您最好不要尝试管理自己的动画队列,这既困难又不必要。

通过明智地使用jQuery的内置.queue().dequeue()一()方法,您可以使CSS转换完全像jQuery动画一样集成到元素的标准"fx“队列中,并完成由.promise()方法返回的承诺。

代码语言:javascript
复制
function Test() {
    this.x = $('<div/>').appendTo('body');
    this.x.width();
    this.transitionEndString = 'webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend'; // cross-browser "transitionend" event names.
}

Test.prototype.open = function() {
    var that = this,
        x = this.x;
    x.queue('fx', function(next) {
        if(!x.hasClass('open')) {
            x.addClass('open').one(that.transitionEndString, next);
        } else {
            x.dequeue();
        }
    });
    return x.promise();
};
Test.prototype.close = function() {
    var that = this,
        x = this.x;
    x.queue('fx', function(next) {
        if(x.hasClass('open')) {
            x.removeClass('open').one(that.transitionEndString, next);
        } else {
            x.dequeue();
        }
    });
    return x.promise();
};

else { x.dequeue(); }子句是强制承诺在没有调用转换时作出响应的必要条件。

演示

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32300472

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档