Javascript 为什么要使用process.nextTick来确保异步任务的正确执行?

Javascript 为什么要使用process.nextTick来确保异步任务的正确执行?,javascript,node.js,promise,es6-promise,Javascript,Node.js,Promise,Es6 Promise,下面是一本书()的示例,用Javascript在Node.js中实现了一个有限并行执行算法 首先,我编写了一个TaskQueue类来处理任务的所有限制和执行 class TaskQueue { constructor(concurrency) { this.concurrency = concurrency; this.running = 0; this.queue = []; } runTask(task) {

下面是一本书()的示例,用Javascript在Node.js中实现了一个有限并行执行算法

首先,我编写了一个TaskQueue类来处理任务的所有限制和执行

class TaskQueue {
    constructor(concurrency) {
        this.concurrency = concurrency;
        this.running = 0;
        this.queue = [];
    }
    runTask(task) {
        return new Promise((resolve, reject) => {
            this.queue.push(() => {
                return task().then(resolve, reject);
            });
            process.nextTick(this.next.bind(this));
        });
    }
    next() {
        while (this.running < this.concurrency && this.queue.length) {
            const task = this.queue.shift();
            task().finally(() => {
                this.running--;
                this.next();
            });
            this.running++;
        }
    }
}
最后,我使用了一个映射在一个由十个数字组成的数组上执行函数,这将帮助我们跟踪每个承诺

const queue = new TaskQueue(2);
const array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
const promises = array.map((number) => {
    return promiseResolveRandomValue(number, queue);
});

Promise.all(promises)
    .then(() => console.log('Finished'));
到目前为止还不错。问题是,作者建议使用process.nextTick执行这行代码,以避免任何Zalgo类型的情况,但我不明白为什么,因为这段代码只调用类的下一个方法执行完全相同的代码

runTask(task) {
        return new Promise((resolve, reject) => {
            this.queue.push(() => {
                return task().then(resolve, reject);
            });
            process.nextTick(this.next.bind(this)); // <-------------------------------- WHY?
        });
    }
runTask(任务){
返回新承诺((解决、拒绝)=>{
this.queue.push(()=>{
返回任务()。然后(解决、拒绝);
});
process.nextTick(this.next.bind(this));//作者所指的

console.log("Before scheduling the task")
queue.runTask(() => {
    console.log("The task actually starts");
    return new Promise(resolve => {
        // doesn't really matter:
        setTimeout(resolve, Math.random()*1000);
    });
});
console.log("Scheduled the task");
如果未使用
nextTick
,日志可能会以不同的顺序出现-任务可能会在
runTask()
函数返回之前启动,具体取决于队列中已有多少日志

这可能不是出乎意料的——毕竟,我们希望<>代码> RunTebug < /代码>运行这个任务——但是,如果任务实际上以一些副作用同步启动,那可能是意外的。这样一个副作用的例子是 NeX//Cuth>方法本身——考虑以下内容:

queue.runTask(() => …);
console.log(`Scheduled the task, there are now ${queue.queue.length} tasks in the queue`);
您是否希望长度始终至少为1?Zalgo可以提供这样的保证


(另一方面,如果我们确实记录了
队列。相反,在调用
runTask
后立即运行
,期望它>=1对我来说似乎同样合理,并且需要同步启动
下一个
。清晰的文档胜过任何直觉。)

这个解释正是我想要的。坦率地说,我不知道代码的意外行为是从哪里来的,这基本上是因为Zalgo的情况发生在runTask方法之间。这很有帮助。非常感谢!!
queue.runTask(() => …);
console.log(`Scheduled the task, there are now ${queue.queue.length} tasks in the queue`);