A prioritized asynchronous (or synchronous) queue for node.js. Browsers are currently supported!
$ npm install priority-async-queue --save
Or
$ yarn add priority-async-queue
<script src="/dist/priority-async-queue.js"></script>
<script>
const paq = new PAQ();
paq.addTask(() => console.log('browser task'));
</script>
For convenience, priority-async-queue
referred to as paq
.
1. addTask
Create a task and join in the paq
queue.
paq.addTask([options, ]callback);
options
is an optional object that contains the following attributes:
{
id: undefined, // task id
priority: 'normal', // task priority, such as: low, normal, mid, high, urgent
context: null, // task executing context
createTime: 0, // task create time, unit: ms, paq auto setup
startTime: 0, // task start time, unit: ms, paq auto setup
endTime: 0, // task end time, unit: ms, paq auto setup
start: (ctx, options) => {}, // task execution will start callback
completed: (ctx, res) => {}, // task execution completed callback
failed: (ctx, err) => {}, // task execution failed callback
remove: (ctx, options) => {} // task execution will remove callback
}
callback
is a function that describes the logic to execute the task, and it contains two parameters: ctx
and options
:
ctx
is the paq instance to which the task belongs.options
is the final value of the options parameter for this task.
paq.addTask((ctx, options) => {
console.log(ctx === paq); // true
});
2. removeTask
Remove a task by taskId.
paq.removeTask(taskId)
taskId
is the id of the task. If remove task successfully, it will return true
. Otherwise, it will return false
.
3. pause
Pause queue execution task.
paq.pause();
Note: However, you cannot suspend the currently executing task because the progress of the asynchronous task cannot be detected temporarily.
4. isPause
Returns whether the current queue is in a paused state.
paq.isPause; // return true or false.
5. resume
Restart the asynchronous queue execution task.
paq.resume();
6. clearTask
Clear all tasks in the queue.
paq.clearTask();
7. setExcutingLimit
Number of concurrent,Default: 1.
paq.setExcutingLimit(2);
As long as you add a task to paq
, this task will be executed automatically.
const PAQ = require('priority-async-queue');
const paq = new PAQ();
// const paq = new PAQ(2);
paq.addTask((ctx, options) => {
console.log('This is a simple task!');
});
// This is a simple task!
The constructor accepts one parameter, which represents the maximum number of concurrency, the default value is 1.
You can execute a series of synchronization tasks with paq
. For Example:
const syncTask = (n) => {
for (let i = 0; i < n; i++) {
paq.addTask(() => {
console.log('Step', i, 'sync');
return i;
});
}
};
syncTask(3);
// Step 0 sync
// Step 1 sync
// Step 2 sync
You can also execute a series of asynchronization tasks with paq
. For Example:
const asyncTask = (n) => {
for (let i = 0; i < n; i++) {
paq.addTask(() => {
return new Promise(resolve => {
setTimeout(() => {
console.log('Step', i, 'async');
resolve(i);
}, i * 1000);
});
});
}
};
asyncTask(3);
// Step 0 async
// Step 1 async
// Step 2 async
You can also execute a series of synchronous and asynchronous interleaved tasks with paq
. for example:
const mixTask = (n) => {
asyncTask(n);
syncTask(n);
asyncTask(n);
};
mixTask(2);
// Step 0 async
// Step 1 async
// Step 0 sync
// Step 1 sync
// Step 0 async
// Step 1 async
If sometimes you need to specify a context to execute the task. For example:
const contextTask = (n) => {
var testObj = {
name: 'foo',
sayName: (name) => {
console.log(name);
}
};
for (let i = 0; i < n; i++) {
paq.addTask({ context: testObj }, function () {
this.sayName(this.name + i);
});
}
};
contextTask(3);
// foo0
// foo1
// foo2
Note: this does not exist in the arrow function.
paq
also support delay task. For example:
const delayTask = (n) => {
for (let i = 0; i < n; i++) {
paq.addTask({ delay: 1000 * i }, () => {
console.log('Step', i, 'sync');
return i;
});
}
};
delayTask(3);
// Step 0 sync
// Step 1 sync
// Step 2 sync
If the task being executed has priority. For example:
const priorityTask = (n) => {
for (let i = 0; i < n; i++) {
paq.addTask({ priority: i === n - 1 ? 'high' : 'normal' }, () => {
return new Promise(resolve => {
setTimeout(() => {
console.log('Step', i, 'async');
resolve(i);
}, i * 1000);
});
});
}
};
priorityTask(5);
// Step 0 async
// Step 4 async
// Step 1 async
// Step 2 async
// Step 3 async
The default priority map is as follows:
{
"low": 1,
"normal": 0, // default
"mid": -1,
"high": -2,
"urgent": -3
}
Sometimes, you want to be able to control the completion or failure of the task. For Example
const callbackTask = (n) => {
for (let i = 0; i < n; i++) {
paq.addTask({
id: i,
start: (ctx, options) => {
console.log('start running task id is', options.id);
},
completed: (ctx, res) => {
console.log('complete, result is', res);
},
failed: (ctx, err) => {
console.log(err);
}
}, () => {
if (i < n / 2) {
throw new Error(i + ' is too small!');
}
return i;
});
}
};
callbackTask(5);
// start running task id is 0
// Error: 0 is too small!
// start running task id is 1
// Error: 1 is too small!
// start running task id is 2
// Error: 2 is too small!
// start running task id is 3
// complete, result is 3
// start running task id is 4
// complete, result is 4
If you need to delete some tasks in time, you can:
const removeTask = (n) => {
for (let i = 0; i < n; i++) {
paq.addTask({
id: i,
remove: (ctx, options) => {
console.log('remove task id is', options.id);
}
}, () => {
return new Promise(resolve => {
setTimeout(() => {
console.log('Step', i, 'async');
resolve(i);
}, i * 1000);
});
});
}
console.log(paq.removeTask(3));
console.log(paq.removeTask(5));
};
removeTask(5);
// remove task id is 3
// true
// false
// Step 0 async
// Step 1 async
// Step 2 async
// Step 4 async
Note: You must assign an id when creating a task, and delete the task based on the id.
If you have concurrent requirements, you can try to set the maximum concurrent number when instantiating paq
.
const paq = new PAQ(2);
const sleep = (ms, order) => {
return paq.sleep(ms).then(() => {
console.log(order);
});
}
paq.addTask(() => sleep(1000, 1));
paq.addTask(() => sleep(500, 2));
paq.addTask(() => sleep(300, 3));
paq.addTask(() => sleep(400, 4));
// 2
// 3
// 1
// 4
If you need to calculate the task time, you can use createTime
, startTime
, endTime
.
paq.addTask(() => paq.sleep(1000)).on('completed', (options) => {
console.log(`The task waiting time is ${options.startTime - options.createTime}ms`);
console.log(`The task execution time is ${options.endTime - options.startTime}ms`);
});
// The task waiting time is 0ms
// The task execution time is 1002ms
If you need to monitor the state of the queue, paq
provides the following event listeners.
1. addTask
paq.on('addTask', (options) => {
// Triggered when the queue adds a task.
});
2. startTask
paq.on('startTask', (options) => {
// Triggered when a task in the queue is about to execute.
});
3. changeTask
paq.on('changeTask', (options) => {
// Triggered when a task in the queue changes.
});
4. removeTask
paq.on('removeTask', (options) => {
// Triggered when the queue remove a task.
});
5. completed
paq.on('completed', (options, result) => {
// Triggered when the task execution in the queue is complete.
});
6. failed
paq.on('failed', (options, err) => {
// Triggered when a task in the queue fails to execute.
});
MIT