控制流程和承诺
control flow and promises
我在 html 中有很多 div。每个 div 包含动画或一些 js 代码,只有在它可见时才会调用此 div:
<button id='start' class='start'>Start</button>
<div class="step1 later">
<div class='red later'>Show first</div>
<div class='aqua later'>Show later</div>
</div>
<div class="step2 later">
<div class='green later'>Show together</div>
<div class='yellow later'>Show together</div>
</div>
我的目标是用 step1
class 显示 div
并调用一些 js
,然后显示 step2
等等。它看起来像滑块。对于这个例子,我想显示 step1
,然后显示 div
和 red
class,延迟后我想显示 aqua
。接下来,我们转到 step2
并立即显示两个 div:yellow
、green
。为此,我决定使用 promises (Q.js)。这是我的代码:
$(function () {
var currentStep = 1,
handlers = {};
$('#start').click(function() {
for(var i = 0; i < 2; i++) {
showStep(currentStep + i);
}
});
function showStep(step) {
var name = 'step' + step;
$('.' + name).show();
handlers[name]();
}
handlers.step1 = function() {
Q().then(function() {
$('.notification').html('Step1 started');
})
.delay(2000)
.then(function() {
showElem('red');
})
.delay(2000)
.then(function() {
showElem('aqua');
});
};
handlers.step2 = function() {
Q().then(function() {
$('.notification').append('Step2 started');
})
.delay(2000)
.then(function() {
showElem('green');
showElem('yellow');
});
};
function showElem(classSelector) {
$('.' + classSelector).fadeIn(100);
}
});
所有的动画和延迟作品都发现除了一件事。当一个步骤完成时,我的代码不会等待,处理程序几乎同时启动。
演示:JSBIN
问题出在您的初始 "for" 循环中,您在其中一次执行所有 "showStep",而无需等待承诺。
你也可以这样做:
$('#start').click(function() {
showStep(1);
});
function showStep(step) {
var name = 'step' + step;
$('.' + name).show();
handlers[name]().then(function() {
if (step < 2) {
showStep(step+1);
}
});
}
并让你成为处理者 return 的承诺。
使用 Q 来安排 jQuery 动作是相当不寻常的。通过明智地使用其 .delay() and .promise() 方法,jQuery 完全有能力可靠地完成这项工作 - 靠自己。
在下面重写代码:
- 从各种函数返回承诺以允许链接
- 主(开始)例程是一个简单的两步
.then()
链
showElem()
和 showStep()
是不必要的并且消失了
handlers
写成对象字面量。
jQuery(function ($) {
var handlers = {
'step1': function() {
$('.notification').html('<div>Step1 started</div>');
return $(".step1").show(0).delay(2000).promise().then(function() {
return $('.red').fadeIn(100).delay(2000).promise();
}).then(function() {
return $('.aqua').fadeIn(100).promise();
});
},
'step2': function() {
$('.notification').append('<div>Step2 started</div>');
return $(".step2").show(0).delay(2000).promise().then(function() {
return $('.green, .yellow').fadeIn(100);
});
}
};
$('#start').click(function() {
handlers.step1().then(handlers.step2);
});
});
编辑
对于大量的处理程序,您可以按如下方式手写 "start" 例程:
$('#start').click(function() {
handlers.step1()
.then(handlers.step2)
.then(handlers.step3)
.then(handlers.step4)
.then(handlers.step5)
.then(handlers.step6)
...
;
});
但是,这可能需要大量输入,并且无法满足可变数量的处理程序的需求。
解决方案相当简单。
首先,将handlers
写成数组,而不是对象。
var handlers = [
//step 0
function() {
$('.notification').html('<div>Step1 started</div>');
return $(".step1").show(0).delay(2000).promise().then(function() {
return $('.red').fadeIn(100).delay(2000).promise();
}).then(function() {
return $('.aqua').fadeIn(100).promise();
});
},
//step 1
function() {
$('.notification').append('<div>Step2 started</div>');
return $(".step2").show(0).delay(2000).promise().then(function() {
return $('.green, .yellow').fadeIn(100);
});
},
//step 2,
...
//step 3,
...
];
现在,您可以使用 Array 方法 .reduce()
扫描数组,构建一个 promise 链:
$('#start').click(function() {
handlers.reduce(function(promise, handler) {
return promise.then(handler);
}, $.when());
});
在这里,$.when()
是一个已解决的 "seed" 承诺,它启动了链。
我在 html 中有很多 div。每个 div 包含动画或一些 js 代码,只有在它可见时才会调用此 div:
<button id='start' class='start'>Start</button>
<div class="step1 later">
<div class='red later'>Show first</div>
<div class='aqua later'>Show later</div>
</div>
<div class="step2 later">
<div class='green later'>Show together</div>
<div class='yellow later'>Show together</div>
</div>
我的目标是用 step1
class 显示 div
并调用一些 js
,然后显示 step2
等等。它看起来像滑块。对于这个例子,我想显示 step1
,然后显示 div
和 red
class,延迟后我想显示 aqua
。接下来,我们转到 step2
并立即显示两个 div:yellow
、green
。为此,我决定使用 promises (Q.js)。这是我的代码:
$(function () {
var currentStep = 1,
handlers = {};
$('#start').click(function() {
for(var i = 0; i < 2; i++) {
showStep(currentStep + i);
}
});
function showStep(step) {
var name = 'step' + step;
$('.' + name).show();
handlers[name]();
}
handlers.step1 = function() {
Q().then(function() {
$('.notification').html('Step1 started');
})
.delay(2000)
.then(function() {
showElem('red');
})
.delay(2000)
.then(function() {
showElem('aqua');
});
};
handlers.step2 = function() {
Q().then(function() {
$('.notification').append('Step2 started');
})
.delay(2000)
.then(function() {
showElem('green');
showElem('yellow');
});
};
function showElem(classSelector) {
$('.' + classSelector).fadeIn(100);
}
});
所有的动画和延迟作品都发现除了一件事。当一个步骤完成时,我的代码不会等待,处理程序几乎同时启动。
演示:JSBIN
问题出在您的初始 "for" 循环中,您在其中一次执行所有 "showStep",而无需等待承诺。
你也可以这样做:
$('#start').click(function() {
showStep(1);
});
function showStep(step) {
var name = 'step' + step;
$('.' + name).show();
handlers[name]().then(function() {
if (step < 2) {
showStep(step+1);
}
});
}
并让你成为处理者 return 的承诺。
使用 Q 来安排 jQuery 动作是相当不寻常的。通过明智地使用其 .delay() and .promise() 方法,jQuery 完全有能力可靠地完成这项工作 - 靠自己。
在下面重写代码:
- 从各种函数返回承诺以允许链接
- 主(开始)例程是一个简单的两步
.then()
链 showElem()
和showStep()
是不必要的并且消失了handlers
写成对象字面量。
jQuery(function ($) {
var handlers = {
'step1': function() {
$('.notification').html('<div>Step1 started</div>');
return $(".step1").show(0).delay(2000).promise().then(function() {
return $('.red').fadeIn(100).delay(2000).promise();
}).then(function() {
return $('.aqua').fadeIn(100).promise();
});
},
'step2': function() {
$('.notification').append('<div>Step2 started</div>');
return $(".step2").show(0).delay(2000).promise().then(function() {
return $('.green, .yellow').fadeIn(100);
});
}
};
$('#start').click(function() {
handlers.step1().then(handlers.step2);
});
});
编辑
对于大量的处理程序,您可以按如下方式手写 "start" 例程:
$('#start').click(function() {
handlers.step1()
.then(handlers.step2)
.then(handlers.step3)
.then(handlers.step4)
.then(handlers.step5)
.then(handlers.step6)
...
;
});
但是,这可能需要大量输入,并且无法满足可变数量的处理程序的需求。
解决方案相当简单。
首先,将handlers
写成数组,而不是对象。
var handlers = [
//step 0
function() {
$('.notification').html('<div>Step1 started</div>');
return $(".step1").show(0).delay(2000).promise().then(function() {
return $('.red').fadeIn(100).delay(2000).promise();
}).then(function() {
return $('.aqua').fadeIn(100).promise();
});
},
//step 1
function() {
$('.notification').append('<div>Step2 started</div>');
return $(".step2").show(0).delay(2000).promise().then(function() {
return $('.green, .yellow').fadeIn(100);
});
},
//step 2,
...
//step 3,
...
];
现在,您可以使用 Array 方法 .reduce()
扫描数组,构建一个 promise 链:
$('#start').click(function() {
handlers.reduce(function(promise, handler) {
return promise.then(handler);
}, $.when());
});
在这里,$.when()
是一个已解决的 "seed" 承诺,它启动了链。