停止 jquery .then 通过用户输入链接
Stoping jquery .then chain via user input
这可能是一个简单的问题,但我完全迷路了。
我有这个功能
m.util.genericSwipeVertFunc = function (
ajaxRequest,
swipeOutTarget,
swipeInTarget
) {
var stage1, stage2, failStage, dfd = $.Deferred(), finalStage, functionPromise;
// Swipe of screen wait for ajax request
stage1 = function () {
return $.when(
ajaxRequest, // Returns $.Deferred()
m.util.animateDeffered(swipeOutTarget, "fadeOutDown", true) // Returns $.Deferred()
);
};
// Swipe and Show
stage2 = function () {
swipeInTarget.show();
return m.util.animateDeffered(swipeInTarget, "fadeInDown"); // Returns $.Deferred()
};
finalStage = function () {
dfd.resolve();
}
failStage = function () {
console.log("fail!");
swipeInTarget.hide();
};
functionPromise = stage1()
.then(stage2)
.then(finalStage);
$.when(functionPromise,dfd)
.fail(failStage);
return dfd;
};
基本上它会做一些花哨的动画来淡入和淡出来自 ajax 函数的不同响应输出。这一切都很好,除非用户试图非常快速地在目标之间切换(在一个链完成之前他们开始另一个)我到处都是疯狂的动画。
我希望能够通过做这样的事情在任何时候拒绝链。
// called on script load.
var currentAction = $.Deferred();
// Called everytime someone starts animation chain.
currentAction.reject();
currentAction = m.util.genericSwipeVertFunc(dfd, swipeOutTarget, swipeInTarget);
);
使用我当前的代码,failFunction 被正确命中,但它不会停止 stage2 的执行。所以它隐藏然后显示它并继续破坏东西。
那么问题来了。我如何将延迟放入链中,我可以在链执行期间随时拒绝? :)
示例fiddle
http://jsfiddle.net/ff3jojbo/
更新说明
我正在为我的动画使用 animate.css。不是 jquery 动画。
我更感兴趣的是如何阻止链在用户输入的任何时候开始下一阶段。
回答fiddle
http://jsfiddle.net/aefkwa8a/
尝试使用 .queue()
, .promise()
// array of functions to add to queue
var arr = [];
var swipeInTarget = $("#stage1");
var swipeOutTarget = $("#stage2");
// pseudo `ajax` call
var ajaxRequest = function ajaxRequest(next) {
return $.Deferred(function(d) {
setTimeout(function() {
d.resolve("ajaxRequest")
}, Math.random() * 5000)
}).promise()
// Note `.then(function() {console.log(this)})` for example ,
// can be removed
.then(function(data) {
console.log(data)
}).then(next)
}
var stage1 = function stage1(next) {
return swipeOutTarget.fadeTo(Math.random() * 5000, Math.random())
.promise()
// Note `.then(function() {console.log(this)})` for example ,
// can be removed
.then(function() {
console.log(this)
})
.then(next)
}
var stage2 = function stage2(next) {
return swipeInTarget
.show(Math.random() * 5000, function() {
return $(this).fadeTo(Math.random() * 2000, Math.random())
})
.promise()
// Note `.then(function() {console.log(this)})` for example ,
// can be removed
.then(function() {
console.log(this)
})
.then(next)
}
// do stuff when queue cleared
var failStage = function failStage() {
return swipeInTarget.hide(Math.random() * 2000)
.promise().then(function() {
console.log("m processes stopped")
})
}
// always do stuff when queue cleared,
// or all functions in queue complete
var finalStage = function finalStage() {
console.log("complete", this)
}
// create jQuery object
var m = $({
m: arr
});
// add function to `"stages"` queue
m.queue("stages", [stage1, stage2, finalStage]);
// do stuff when all functions complete , or queue cleared
m.promise("stages")
.then(finalStage);
// dequque `"stages"` queue
m.dequeue("stages");
// clear `"stages"` queue
$("button").click(function() {
m.queue("stages", [])
.promise("stages").always(failStage)
})
#stage2 {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<button>stop m processes</button>
<div id="stage1">stage1</div>
<div id="stage2">stage2</div>
OP自己的解决方案here点击几次后可能会失败。特别是,如果在某个部分飞入时单击按钮,则最新请求的部分可能会飞入,然后消失。
这个解决方案是完全不同的。
它没有使用 jQuery 的 queue/dequeue,而是使用常规的 stage1().then(stage2)
承诺链,并通过删除 CSS 动画 类 从动画元素中分离它的 animationend
处理程序,从而确保与完成相关的承诺永远不会解析。
正如您将看到的,许多功能都被分解为 jQuery 插件,这使得语法方便、紧凑。
$(function () {
// **************************
// *** Various outer vars ***
// **************************
var $sections = $('#TabSection>div').hide();
var ajaxPromise;
var str = {
//various strings
'animationend': 'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend',
'fadeOutClasses': 'fadeOutDown animated',
'fadeInClasses': 'fadeInDown animated',
'allClasses': 'fadeOutDown fadeInDown animated'
};
// ***********************************************
// *** Utilities in the form of jQuery plugins ***
// ***********************************************
jQuery.fn.killAnim = function(animation) {
/* jQuery plugin :
* Remove all the animation classes from all possible targets, and
* detach any currently attached animationend handlers.
* Depends on: str (object).
*/
return this.off(str.animationend).removeClass(str.allClasses);
};
jQuery.fn.cssAnimate = function (animation) {
/* jQuery plugin :
* Perform CSS animation and return promise.
* Depends on: str (object); killAnim (plugin).
*/
var that = this;
return $.Deferred(function(dfd) {
// if no target or target not visible, resolve;
if(that.length == 0 || !that.is(':visible')) {
dfd.resolve();
}
that.addClass(animation).one(str.animationend, dfd.resolve);
}).then(function() {
that.killAnim();
});
};
jQuery.fn.genericSwipeVertFunc = function () {
/* jQuery plugin :
* Sequence two CSS animations - fadeOut then fadeIn.
* Depends on: str (object); killAnim (plugin); cssAnimate (plugin).
*/
var that = this; // swipeInTarget
var swipeOutTarget = $sections.filter(':visible()').eq(0);
function stage1() {
$sections.killAnim().not(swipeOutTarget).hide();
return swipeOutTarget.cssAnimate(str.fadeOutClasses).then(function() {
swipeOutTarget.hide();
});
};
function stage2() {
$sections.not(that).killAnim().hide();
return that.show().cssAnimate(str.fadeInClasses);
};
return stage1().then(stage2);
};
// **********************
// *** Event handlers ***
// **********************
$('button').on('click', function (event) {
var inTarget = $($(this).data('tar'));
if(ajaxPromise) {
ajaxPromise.abort('aborted');
}
// *** start: emulate AJAX ***
ajaxPromise = $.Deferred(function(dfrd) {
setTimeout(dfrd.resolve, 1000);
});
ajaxPromise.abort = ajaxPromise.reject;
// *** end: emulate AJAX ***
ajaxPromise.then(function() {
return inTarget.genericSwipeVertFunc();
}).fail(function(e) {
$sections.killAnim().hide();
console.log(e);
});
});
});
我相信这个解决方案更可靠。即使有很多疯狂的点击,我也无法击败它。
试一试here
这可能是一个简单的问题,但我完全迷路了。
我有这个功能
m.util.genericSwipeVertFunc = function (
ajaxRequest,
swipeOutTarget,
swipeInTarget
) {
var stage1, stage2, failStage, dfd = $.Deferred(), finalStage, functionPromise;
// Swipe of screen wait for ajax request
stage1 = function () {
return $.when(
ajaxRequest, // Returns $.Deferred()
m.util.animateDeffered(swipeOutTarget, "fadeOutDown", true) // Returns $.Deferred()
);
};
// Swipe and Show
stage2 = function () {
swipeInTarget.show();
return m.util.animateDeffered(swipeInTarget, "fadeInDown"); // Returns $.Deferred()
};
finalStage = function () {
dfd.resolve();
}
failStage = function () {
console.log("fail!");
swipeInTarget.hide();
};
functionPromise = stage1()
.then(stage2)
.then(finalStage);
$.when(functionPromise,dfd)
.fail(failStage);
return dfd;
};
基本上它会做一些花哨的动画来淡入和淡出来自 ajax 函数的不同响应输出。这一切都很好,除非用户试图非常快速地在目标之间切换(在一个链完成之前他们开始另一个)我到处都是疯狂的动画。
我希望能够通过做这样的事情在任何时候拒绝链。
// called on script load.
var currentAction = $.Deferred();
// Called everytime someone starts animation chain.
currentAction.reject();
currentAction = m.util.genericSwipeVertFunc(dfd, swipeOutTarget, swipeInTarget);
);
使用我当前的代码,failFunction 被正确命中,但它不会停止 stage2 的执行。所以它隐藏然后显示它并继续破坏东西。
那么问题来了。我如何将延迟放入链中,我可以在链执行期间随时拒绝? :)
示例fiddle http://jsfiddle.net/ff3jojbo/
更新说明
我正在为我的动画使用 animate.css。不是 jquery 动画。 我更感兴趣的是如何阻止链在用户输入的任何时候开始下一阶段。
回答fiddle http://jsfiddle.net/aefkwa8a/
尝试使用 .queue()
, .promise()
// array of functions to add to queue
var arr = [];
var swipeInTarget = $("#stage1");
var swipeOutTarget = $("#stage2");
// pseudo `ajax` call
var ajaxRequest = function ajaxRequest(next) {
return $.Deferred(function(d) {
setTimeout(function() {
d.resolve("ajaxRequest")
}, Math.random() * 5000)
}).promise()
// Note `.then(function() {console.log(this)})` for example ,
// can be removed
.then(function(data) {
console.log(data)
}).then(next)
}
var stage1 = function stage1(next) {
return swipeOutTarget.fadeTo(Math.random() * 5000, Math.random())
.promise()
// Note `.then(function() {console.log(this)})` for example ,
// can be removed
.then(function() {
console.log(this)
})
.then(next)
}
var stage2 = function stage2(next) {
return swipeInTarget
.show(Math.random() * 5000, function() {
return $(this).fadeTo(Math.random() * 2000, Math.random())
})
.promise()
// Note `.then(function() {console.log(this)})` for example ,
// can be removed
.then(function() {
console.log(this)
})
.then(next)
}
// do stuff when queue cleared
var failStage = function failStage() {
return swipeInTarget.hide(Math.random() * 2000)
.promise().then(function() {
console.log("m processes stopped")
})
}
// always do stuff when queue cleared,
// or all functions in queue complete
var finalStage = function finalStage() {
console.log("complete", this)
}
// create jQuery object
var m = $({
m: arr
});
// add function to `"stages"` queue
m.queue("stages", [stage1, stage2, finalStage]);
// do stuff when all functions complete , or queue cleared
m.promise("stages")
.then(finalStage);
// dequque `"stages"` queue
m.dequeue("stages");
// clear `"stages"` queue
$("button").click(function() {
m.queue("stages", [])
.promise("stages").always(failStage)
})
#stage2 {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<button>stop m processes</button>
<div id="stage1">stage1</div>
<div id="stage2">stage2</div>
OP自己的解决方案here点击几次后可能会失败。特别是,如果在某个部分飞入时单击按钮,则最新请求的部分可能会飞入,然后消失。
这个解决方案是完全不同的。
它没有使用 jQuery 的 queue/dequeue,而是使用常规的 stage1().then(stage2)
承诺链,并通过删除 CSS 动画 类 从动画元素中分离它的 animationend
处理程序,从而确保与完成相关的承诺永远不会解析。
正如您将看到的,许多功能都被分解为 jQuery 插件,这使得语法方便、紧凑。
$(function () {
// **************************
// *** Various outer vars ***
// **************************
var $sections = $('#TabSection>div').hide();
var ajaxPromise;
var str = {
//various strings
'animationend': 'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend',
'fadeOutClasses': 'fadeOutDown animated',
'fadeInClasses': 'fadeInDown animated',
'allClasses': 'fadeOutDown fadeInDown animated'
};
// ***********************************************
// *** Utilities in the form of jQuery plugins ***
// ***********************************************
jQuery.fn.killAnim = function(animation) {
/* jQuery plugin :
* Remove all the animation classes from all possible targets, and
* detach any currently attached animationend handlers.
* Depends on: str (object).
*/
return this.off(str.animationend).removeClass(str.allClasses);
};
jQuery.fn.cssAnimate = function (animation) {
/* jQuery plugin :
* Perform CSS animation and return promise.
* Depends on: str (object); killAnim (plugin).
*/
var that = this;
return $.Deferred(function(dfd) {
// if no target or target not visible, resolve;
if(that.length == 0 || !that.is(':visible')) {
dfd.resolve();
}
that.addClass(animation).one(str.animationend, dfd.resolve);
}).then(function() {
that.killAnim();
});
};
jQuery.fn.genericSwipeVertFunc = function () {
/* jQuery plugin :
* Sequence two CSS animations - fadeOut then fadeIn.
* Depends on: str (object); killAnim (plugin); cssAnimate (plugin).
*/
var that = this; // swipeInTarget
var swipeOutTarget = $sections.filter(':visible()').eq(0);
function stage1() {
$sections.killAnim().not(swipeOutTarget).hide();
return swipeOutTarget.cssAnimate(str.fadeOutClasses).then(function() {
swipeOutTarget.hide();
});
};
function stage2() {
$sections.not(that).killAnim().hide();
return that.show().cssAnimate(str.fadeInClasses);
};
return stage1().then(stage2);
};
// **********************
// *** Event handlers ***
// **********************
$('button').on('click', function (event) {
var inTarget = $($(this).data('tar'));
if(ajaxPromise) {
ajaxPromise.abort('aborted');
}
// *** start: emulate AJAX ***
ajaxPromise = $.Deferred(function(dfrd) {
setTimeout(dfrd.resolve, 1000);
});
ajaxPromise.abort = ajaxPromise.reject;
// *** end: emulate AJAX ***
ajaxPromise.then(function() {
return inTarget.genericSwipeVertFunc();
}).fail(function(e) {
$sections.killAnim().hide();
console.log(e);
});
});
});
我相信这个解决方案更可靠。即使有很多疯狂的点击,我也无法击败它。
试一试here