20
loading...
This website collects cookies to deliver better user experience
Promise
and setTimeout
to simulate the asynchronous job:const buildJob = (jobId, executionTime) => {
return () => {
console.log(`[Job ${jobId}] Start.`)
return new Promise(resolve => {
setTimeout(() => {
console.log(`[Job ${jobId}] End, it takes ${executionTime} ms.`)
resolve();
}, executionTime);
})
}
}
// we expect that each job should output the message like this:
// [Job 1] Start.
// [Job 1] End, it takes 2512 ms.
buildJob()
function will return a function that returns a Promise
after calling it. and then we can use this function to build a series of jobs.const randomExecutionTimes = (new Array(10))
.fill()
.map(() => Math.floor(Math.random() * 2000 + 1000))
const jobs = randomExecutionTimes
.map((executionTime, index) => buildJob(index, executionTime))
const jobsQueue = jobs.map(job => job);
jobsQueue
because we must keep the jobs
unchanged, and we see the start of this newly created array as tail, and the end of the array as head, so only we need to do is pop()
the last element of the array and call the job functions.startJob()
that starts a job at the head of the queue.function startJob() {
const job = jobsQueue.pop();
// start another job after finishing the previous one.
if(job) return job.then(startJob)
}
// We use the variable to define the max number of jobs
const MAX_PARALLEL_NUMBER = 3;
// Then use the for loop to start
for(let i = 0; i < MAX_PARALLEL_NUMBER; i ++) {
startJob();
}
const buildJob = (jobId, executionTime) => {
return () => {
console.log(`[Job ${jobId}] Start.`)
return new Promise(resolve => {
setTimeout(() => {
console.log(`[Job ${jobId}] End, it takes ${executionTime} ms.`)
resolve();
}, executionTime);
})
}
}
const randomExecutionTimes = (new Array(10))
.fill()
.map(() => Math.floor(Math.random() * 2000 + 1000))
const jobs = randomExecutionTimes
.map((executionTime, index) => buildJob(index, executionTime))
const jobsQueue = jobs.map(job => job);
function startJob() {
const job = jobsQueue.pop();
if(job) return job.then(startJob)
}
const MAX_PARALLEL_NUMBER = 3;
for(let i = 0; i < MAX_PARALLEL_NUMBER; i ++) {
startJob();
}
[Job 9] Start.
[Job 8] Start.
[Job 7] Start.
[Job 8] End, it takes 1308 ms.
[Job 6] Start.
[Job 7] End, it takes 1566 ms.
[Job 5] Start.
[Job 9] End, it takes 1806 ms.
[Job 4] Start.
[Job 5] End, it takes 1324 ms.
[Job 3] Start.
[Job 6] End, it takes 1885 ms.
[Job 2] Start.
[Job 4] End, it takes 2289 ms.
[Job 1] Start.
[Job 2] End, it takes 2275 ms.
[Job 0] Start.
[Job 1] End, it takes 1449 ms.
[Job 3] End, it takes 2849 ms.
[Job 0] End, it takes 1981 ms.
const MAX_PARALLEL_NUMBER = 3;
// save the time when starting
const startTime = Date.now();
const executors = [];
for(let i = 0; i < MAX_PARALLEL_NUMBER; i ++) {
executors.push(startJob());
}
// wait for all jobs be done.
Promise.all(executors).then(() => {
const endTime = Date.now();
console.log(`All jobs take ${endTime - startTime} ms running.`)
})
[Job 9] Start.
[Job 8] Start.
[Job 7] Start.
[Job 8] End, it takes 1308 ms.
[Job 6] Start.
[Job 7] End, it takes 1566 ms.
[Job 5] Start.
[Job 9] End, it takes 1806 ms.
[Job 4] Start.
[Job 5] End, it takes 1324 ms.
[Job 3] Start.
[Job 6] End, it takes 1885 ms.
[Job 2] Start.
[Job 4] End, it takes 2289 ms.
[Job 1] Start.
[Job 2] End, it takes 2275 ms.
[Job 0] Start.
[Job 1] End, it takes 1449 ms.
[Job 3] End, it takes 2849 ms.
[Job 0] End, it takes 1981 ms.
All jobs take 7476 ms running.
startJob()
will be called afterward but get nothing to run.addJob()
.function addJob(job) {
jobsQueue.unshift(job);
return startJob();
}
startJob()
after adding a job to the queue. The purpose that calling startJob()
afterward is to make sure that every job has its startJob()
. To put it differently, if there is any job in the queue, then startJob()
call by the previous job, otherwise, the startJob()
is called after adding a job to the queue.startJob()
function, because startJob()
will to run the job after being called.let concurrentJobsCount = 0;
function startJob() {
if(concurrentJobsCount >= MAX_PARALLEL_NUMBER) {
const job = jobsQueue.pop();
if(job) {
concurrentJobsCount ++;
return job.then(startJob).finally(() => {concurrentJobsCount --})
}
}
}
concurrenctJobsCount
as a critical section variable, so just use it directly to count how many jobs are running. // because we have 10 jobs already, so jobId start from 11.
let jobId = 11;
// this function will create a job and append to the queue every 2000ms.
function createRuntimeJob() {
setTimeout(() => {
const job = buildJob(jobId ++, Math.floor(Math.random() * 2000 + 1000));
addJob(job);
createRuntimeJob();
}, 2000)
}
createRuntimeJob();
const buildJob = (jobId, executionTime) => {
return () => {
console.log(`[Job ${jobId}] Start.`)
return new Promise(resolve => {
setTimeout(() => {
console.log(`[Job ${jobId}] End, it takes ${executionTime} ms.`)
resolve();
}, executionTime);
})
}
}
const randomExecutionTimes = (new Array(10))
.fill()
.map(() => Math.floor(Math.random() * 2000 + 1000))
const jobs = randomExecutionTimes
.map((executionTime, index) => buildJob(index, executionTime))
const jobsQueue = jobs.map(job => job);
const MAX_PARALLEL_NUMBER = 3;
let concurrentJobsCount = 0;
function startJob() {
if(concurrentJobsCount < MAX_PARALLEL_NUMBER) {
const job = jobsQueue.pop();
if(job) {
concurrentJobsCount ++;
return job().then(startJob).finally(() => {concurrentJobsCount --})
}
}
}
for(let i = 0; i < MAX_PARALLEL_NUMBER; i ++) {
startJob();
}
function addJob(job) {
jobsQueue.unshift(job);
return startJob();
}
let jobId = 11;
function createRuntimeJob() {
setTimeout(() => {
const job = buildJob(jobId ++, Math.floor(Math.random() * 2000 + 1000));
addJob(job);
createRuntimeJob();
}, 2000)
}
createRuntimeJob();
// jobs varaiable is defined by yourself.
const jobsQueue = jobs.map(job => job);
let concurrentJobsCount = 0;
function startJob() {
if(concurrentJobsCount < MAX_PARALLEL_NUMBER) {
const job = jobsQueue.pop();
if(job) {
concurrentJobsCount ++;
return job().then(startJob).finally(() => {concurrentJobsCount --})
}
}
}
const MAX_PARALLEL_NUMBER = 3;
for(let i = 0; i < MAX_PARALLEL_NUMBER; i ++) {
startJob();
}
function addJob(job) {
jobsQueue.unshift(job);
return startJob();
}
// pretty simple, isn't it?