我努力制作一系列承诺数组。这背后的想法如下:
计划是以下对象的数组:
psql
承诺是AJAX调用(在我的例子中,我用随机超时后解析的假承诺模拟它们)。
然后按优先级对计划进行排序,并执行其操作。在下一系列操作的验证回调之后,应在所有回调之后 运行当前系列返回[
{ priority: 0, actions: [Promise, Promise, Promise, ...] },
{ priority: 1, actions: [Promise, Promise, Promise, ...] }
...
]
。如果任何Promise被拒绝或验证结果失败,则执行应该停止。换句话说,我需要它在以下场景中工作:
- progressBar.activate() - 蓝色。
- 所有系列的所有承诺都是异步启动的。
- 当优先级为0的结果到达时,请异步验证它们。不要验证以下系列的结果。
- 任何验证失败?任何优先级为0的承诺都会被拒绝?
- YES:progressBar.error() - 红色;马上回来。
- 优先级为0的所有验证Promise都可以吗?
- 是:转到下一步。
- 验证优先级为1的结果。
- ...
- ...
- 验证优先级为2的承诺的结果。
- ...
- ...
- 全部完成,progressBar.deactivate() - 橙色。
醇>
但是我不能按顺序运行 - 所有系列的结果都是在到达时以随机顺序验证的!我想我无法在我的true
方法中正确链接调用。并且在进程完成之前,progressBar也会异步停用:
syncRun()
任何建议表示赞赏。这是完整的代码:
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);
&#13;
.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;
}
&#13;
答案 0 :(得分:0)
好的,所以我不完全确定这是否是一个很好的解决方案,但是如果可以从中派生出任何值,我将一个在构造函数中承诺的类汇集在一起,当强制a时在最终返回累积结果之前等待每个分辨率的承诺序列:
class ChainRequest {
constructor(promise) {
this.promise = promise;
this.nextPromise = null;
}
appendNextPromise (nextPromise) {
this.nextPromise = nextPromise;
}
execute (prevResults) {
this.results = prevResults;
return this.promise()
.then(result => {
this.results.push(result);
if (this.nextPromise !== null) {
return this.nextPromise.execute(this.results);
}
else {
return Promise.resolve(this.results);
}
});
}
}
let chainPromises = [promise1, promise2, promise3...];
let currentPromise = new ChainRequest(promise1);
let headPromise = currentPromise;
for (let i = 1; i < chainPromises.length; i++) {
let nextPromise = new ChainRequest(chainPromises[i));
currentPromise.appendNextPromise(nextPromise);
currentPromise = nextPromise;
}
return headPromise
.then(results => {
console.log(results);
});
答案 1 :(得分:0)
首先,更改您的计划,以便列出操作而不是立即调用它们:
var schedule = [{
priority: 0,
actions: 6 // instead of generateActions(6)
},
{
priority: 1,
actions: 5
},
{
priority: 2,
actions: 4
},
{
priority: 3,
actions: 3
},
{
priority: 4,
actions: 2
},
{
priority: 5,
actions: 1
}
];
然后在你真正想要这样做的地方调用它们:
var chain = Promise.resolve(); // <- No need to use $.Deferred here
tasks.forEach(function(stepLength) {
// increase the total empty width of progressBar
progressBar.totalProgress += stepLength;
// chain the next series of promises
chain = chain.then(function() {
return Promise.all(generateActions(stepLength));
});
});