我正在努力使一组承诺数组工作。这背后的想法是:执行承诺数组的数组并在每个序列之后依次运行验证回调
附表是以下对象的数组:
[
{ priority: 0, actions: [Promise, Promise, Promise, ...] },
{ priority: 1, actions: [Promise, Promise, Promise, ...] }
...
]
的承诺是AJAX调用(在我的例子,我用随机超时后解决假货的承诺嘲笑他们) 。
时间表然后按优先级排序并执行其操作。在下一系列操作的验证回调后,只应运行之后全部回调为当前系列返回true
。如果任何Promise被拒绝或者结果验证失败,则应停止执行。换句话说,我需要它在以下情况下工作:
- progressBar.activate() - 蓝色。
- 所有系列的所有承诺都是异步启动的。
- 当优先级0 Promise的结果到达时,以异步方式验证它们。不要验证以下系列的结果。
- 任何验证失败?任何优先级0的承诺都会被拒绝?
- YES:progressBar.error() - 红色;立即返回。
- ALL验证优先级为0承诺是好的?
- 是:转到下一步。
- 验证结果优先级1分的承诺。
- ...
- ...
- 验证结果优先级2分的承诺。
- ...
- ...
- 全部完成,progressBar.deactivate() - 橙色。
但我不能让它按顺序运行 - 从所有系列中的结果到达时生效,按随机顺序!我想我不能在我的syncRun()
方法中正确链接电话。在进程完成之前progressBar也被异步禁用:
var syncRun = function (schedule) {
var tasks = sortSchedule(schedule);
progressBar.activate();
var chain = $.Deferred().resolve();
tasks.forEach(function (step) {
// increase the total empty width of progressBar
progressBar.totalProgress += step.length;
// chain the next series of promises
chain = chain.then(function() {
return Promise.all(step);
}
);
});
// chain the final action: deactivate progressBar
chain = chain.then(function() {
progressBar.deactivate();
}, function() {});
};
任何建议表示赞赏。下面是完整的代码:
var progressBar = {
activate: function() {
$('#progress-bar').addClass('active');
},
deactivate: function() {
$('#progress-bar').removeClass('active');
},
error: function() {
$('#progress-bar').addClass('error');
},
current: 0,
total: 0,
setWidth: function() {
var widthPercent = 0;
if (this.total !== 0) {
widthPercent = this.current/this.total * 100 + '%';
}
$('#progress-bar').css('width', widthPercent);
},
get totalProgress() {
return this.total;
},
set totalProgress(value) {
this.total = value;
this.setWidth();
},
get currentProgress() {
return this.current;
},
set currentProgress(value) {
this.current = value;
this.setWidth();
}
};
var logger = function(message) {
$('<p></p>').text(message).appendTo($('#logger'));
};
var resolveLimit = 6;
var validatorLimit = 6;
var fakeAjax = function(id) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
if (id <= resolveLimit) {
resolve(id);
} else {
reject(id);
}
}, (Math.random() * 5 | 0) * 1000);
});
};
var action = function(request, callback) {
request.then(function(result) {
progressBar.currentProgress++;
var isValid = callback(result);
if (!isValid) {
throw 'Rejected ' + result;
}
});
};
var validator = function(result) {
if (result <= validatorLimit) {
logger('Series #' + result + ' parsed');
return true;
} else {
logger('Series #' + result + ' rejected');
progressBar.error();
return false;
}
};
// Generate an array of action objects of specified length
var guid = 0;
var generateActions = function(count) {
var result = [];
for (var i = 0; i < count; i++) {
result.push(
action(fakeAjax(guid), validator)
);
}
guid++;
return result;
};
var sortSchedule = function(schedule) {
var tasks = [];
schedule.forEach(function(step) {
if (!tasks[step.priority]) {
tasks[step.priority] = [];
}
tasks[step.priority] = tasks[step.priority].concat(step.actions);
});
return tasks.sort(function(a, b) {
return tasks[b] - tasks[a];
});
};
var syncRun = function(schedule) {
var tasks = sortSchedule(schedule);
progressBar.activate();
var chain = $.Deferred().resolve();
tasks.forEach(function(step) {
// increase the total empty width of progressBar
progressBar.totalProgress += step.length;
// chain the next series of promises
chain = chain.then(function() {
return Promise.all(step);
});
});
// chain the final action: deactivate progressBar
chain = chain.then(function() {
progressBar.deactivate();
}, function() {});
};
var schedule = [{
priority: 0,
actions: generateActions(6)
},
{
priority: 1,
actions: generateActions(5)
},
{
priority: 2,
actions: generateActions(4)
},
{
priority: 3,
actions: generateActions(3)
},
{
priority: 4,
actions: generateActions(2)
},
{
priority: 5,
actions: generateActions(1)
}
];
syncRun(schedule);
.progress-bar-container {
border: #999999 1px solid;
width: 90%;
padding: 5px;
margin-bottom: 10px;
}
@keyframes blinker {
50% {
opacity: 0.5;
}
}
.progress-bar {
background-color: #FF9933;
height: 4px;
animation: blinker 1s linear infinite;
width: 100%;
}
.active {
background-color: #0099FF;
}
.error {
background-color: #FF0000 !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="progress-bar-container">
<div id="progress-bar" class="progress-bar"></div>
</div>
<div id="logger">
</div>
看来,你是在同一时间开始你的所有异步操作,使他们都跑并行并因此以随机顺序完成。如果您希望优先级1操作在优先级0操作完成之前不启动,那么您不需要立即开始优先级1操作,而是等待优先级0承诺数组的“Promise.all()”已经解决。 – jfriend00
承诺是_value_不是行为 - 您需要使用返回承诺而不仅仅是承诺的函数。 –
为什么使用'$ .Deferred'?考虑到你在代码的其他地方使用它,为什么不使用常规的'Promise'呢? –