我有一個任務串列,只有在為每個任務解決了所有依賴項之后,才需要執行所有這些任務。我正在努力尋找一種在最佳時間完成所有任務的方法。
// Each node is a async job, illustrated by setTimeout.
// A and C can run at the same time.
// D, needs to wait for A and C to be done.
// E needs to wait for A and D to be done.
function runTasks(tasks) {
// run tasks
}
// Sample of tasks
var tasks = {
'a': {
job: function (finish) {
setTimeout(function () {
console.log('a done');
finish();
}, 500);
},
},
'c': {
job: function (finish) {
setTimeout(function () {
console.log('c done');
finish();
}, 200);
},
dependencies: [],
},
'd': {
job: function (finish) {
setTimeout(function () {
console.log('d done');
finish();
}, 100);
},
dependencies: ['a','c'],
},
'e': {
job: function (finish) {
setTimeout(function () {
console.log('e done');
finish();
}, 200);
},
dependencies: ['a', 'd'],
},
};
uj5u.com熱心網友回復:
這樣的事情可能是可能的,我已將作業更改為異步方法,并跟蹤它們是否已解決。
此代碼不檢查作業中的錯誤或回圈依賴關系。
腳本的輸出:
b done
a done
c done
e done
done
代碼:
const runTasks = async tasks => {
const taskArray = Object.entries(tasks)
const resolved = {}
while (taskArray.length) {
const tasksToExecute = []
for (const task of taskArray) {
const dependencies = task[1].dependencies || []
if (dependencies.length === 0 || dependencies.every(dependency => resolved[dependency] || false)) {
tasksToExecute.push(task)
}
}
await Promise.all(tasksToExecute.map(t => t[1].job()))
tasksToExecute.forEach(t => {
resolved[t[0]] = true
taskArray.splice(taskArray.indexOf(t[0]), 1)
})
}
}
const tasks = {
a: {
job: async function () {
return new Promise(resolve => {
setTimeout(() => {
console.log("a done")
resolve()
}, 500)
})
},
},
c: {
job: async function () {
return new Promise(resolve => {
setTimeout(() => {
console.log("c done")
resolve()
}, 200)
})
},
dependencies: ["a", "b"],
},
b: {
job: async function () {
return new Promise(resolve => {
setTimeout(() => {
console.log("b done")
resolve()
}, 100)
})
},
dependencies: [],
},
e: {
job: async function () {
return new Promise(resolve => {
setTimeout(() => {
console.log("e done")
resolve()
}, 200)
})
},
dependencies: ["c", "b"],
},
}
runTasks(tasks).then(r => console.log("done"))
uj5u.com熱心網友回復:
一個簡單的帶有結果快取的遞回依賴評估就可以了。用于Promise.all等待所有依賴項:
function runTasks(tasks) {
const promises = {};
function runTask(name) {
const {dependencies, job} = tasks[name];
return promises[name] ??= Promise.all(dependencies.map(runTask)).then(job);
}
return Promise.all(Object.keys(tasks).map(runTask));
}
也許在最后的陳述中使用Promise.allSettled而不是。Promise.allreturn
如果需要檢測回圈依賴,可以使用
…
const circular = Promise.reject(new Error("circular dependency"));
circular.catch(() => { /* ignore */ }); // prevent unhandled rejection
function runTask(name) {
const {dependencies, job} = tasks[name];
if (promises[name] != null) return promises[name];
promises[name] = circular;
return promises[name] = Promise.all(dependencies.map(runTask)).then(job);
}
…
uj5u.com熱心網友回復:
您可以啟動可以啟動的并行承諾。
- 首先啟動所有沒有依賴關系的獨立任務
- 完成獨立任務后存盤在地圖/集合中
- 然后使用完整的重復步驟過濾一組新任務。
const wait = (ms, task) =>
new Promise((resolve) =>
setTimeout(() => {
console.log(`${task} done`);
resolve();
}, ms)
);
const tasks = {
a: {
job: () => wait(500, "A"),
dependencies: [],
},
c: {
job: () => wait(500, "C"),
dependencies: [],
},
d: {
job: () => wait(500, "D"),
dependencies: ["a", "c"],
},
e: {
job: () => wait(500, "E"),
dependencies: ["a", "d"],
},
};
const run = async () => {
const completed = new Set();
const keys = Object.keys(tasks);
const runTasks = async (pendingTasks) => {
const promises = pendingTasks.map((key) => tasks[key].job());
await Promise.all(promises);
pendingTasks.forEach((key) => completed.add(key));
};
const runner = async () => {
const pendingTasks = keys.filter((key) => {
if (!completed.has(key)) {
const { dependencies } = tasks[key];
return dependencies.every((dependency) => completed.has(dependency));
}
return false;
});
if (pendingTasks.length !== 0) {
await runTasks(pendingTasks);
return runner();
}
};
await runner();
};
run();
uj5u.com熱心網友回復:
這用于Promise.race獨立于其他人處理任務。使用Promise.all不是最佳的,因為它在評估是否可以啟動另一個任務之前等待所有相關任務完成。
我認為這是最佳的時間。它可能具有更高的處理開銷,因為所有作業都保存在單個物件中,并且可能通過將作業移動到已完成的物件來更好地處理以避免重新評估已完成的任務。
注意:這不會評估回圈依賴關系,或者依賴關系實際上是任務。
"use strict";
class Job {
constructor(getJobs, name, task) {
this.getJobs = getJobs;
this.name = name;
this.task = task;
}
isWaiting() {
return this.promise !== undefined;
}
isComplete() {
return 'result' in this;
}
isBlocked() {
return !(this.task.dependencies || []).map(name => this.getJobs()[name]).every(job => job.isComplete()) || false;
}
isElligible() {
return !this.isWaiting() && !this.isComplete() && !this.isBlocked();
}
}
async function runTasks(tasks) {
const jobs = Object.entries(tasks)
.reduce((acc, [name, task]) => {
acc[name] = new Job(() => jobs, name, task);
return acc;
}, {});
while (true) {
Object.keys(jobs).forEach(name => {
if (jobs[name].isElligible()) {
console.log(`${name} elligible`);
jobs[name].promise = new Promise(resolve => {
console.log(`${name} starting`);
jobs[name].task.job(resolve);
}).then(res => {
jobs[name].result = res;
delete jobs[name].promise;
});
}
});
const pending = Object.values(jobs).filter(job => job.isWaiting());
console.log('racing', pending.map(j => j.name));
if (pending.length) {
await Promise.race(pending.map(job => job.promise));
}
else {
break;
}
}
}
var tasks = {
'a': {
job: function (finish) {
setTimeout(function () {
console.log('a done');
finish();
}, 500);
},
},
'c': {
job: function (finish) {
setTimeout(function () {
console.log('c done');
finish();
}, 200);
},
dependencies: [],
},
'd': {
job: function (finish) {
setTimeout(function () {
console.log('d done');
finish();
}, 100);
},
dependencies: ['a', 'c'],
},
'e': {
job: function (finish) {
setTimeout(function () {
console.log('e done');
finish();
}, 200);
},
dependencies: ['a', 'd'],
},
'f': {
job: function (finish) {
setTimeout(function () {
console.log('f done');
finish();
}, 500);
},
dependencies: ['c'],
},
};
runTasks(tasks).then(() => console.log('ALL done'));
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/471671.html
標籤:javascript 异步 异步等待 承诺
