Gar*_*ary 0 javascript node.js
过去两周我一直在学习以下内容:setImmediate、process.nextTick、setTimeout、promises、callbacks、libuv、事件循环、作业/微任务队列、事件循环队列、调用堆栈等。
我真的掉进了一个无法逃脱的兔子洞,虽然我发现自己有更多的见识,但我仍然无法掌握 JavaScript 中的异步代码。
我想采用以下基本场景并了解如何异步实现它:
// does nothing; here to simulate functionality below
var data = new Array(10000000);
const displayTime = desc => {
var time = new Date();
console.log(
("0" + time.getHours()).slice(-2) + ":" +
("0" + time.getMinutes()).slice(-2) + ":" +
("0" + time.getSeconds()).slice(-2) + " " + desc
);
}
displayTime('starting ...');
// --- async/await (a promise):
const processData = async(data) => {
let dataLen = data.length;
let processedData = [];
//console.time('#1');
for (let ctr = 0; ctr < dataLen; ctr++) {
// something happens here; simulating a long task using a for-loop;
// for purposes of this question, let's just assume it's necessary to do this
processedData.push(ctr / 33 * 383739722);
}
//console.timeEnd('#1');
return processedData;
}
(async() => {
result = await processData(data);
// console.log(result);
displayTime('#1 completed ...');
})();
// --- promise:
const processData2 = data => {
return new Promise((resolve, reject) => {
let dataLen = data.length;
let processedData = [];
//console.time('#2');
for (let ctr = 0; ctr < dataLen; ctr++) {
processedData.push(ctr / 33 * 383739722);
}
//console.timeEnd('#2');
resolve(processedData)
});
}
processData2(data).then(data => {
// console.log(data);
displayTime('#2 completed ...');
});
displayTime('end of program ...');Run Code Online (Sandbox Code Playgroud)
输出是:
18:09:48 starting ...
18:09:52 end of program ...
18:09:52 #1 completed ...
18:09:52 #2 completed ...
Run Code Online (Sandbox Code Playgroud)
正如您从输出中看到的那样,直到两个长时间运行的进程完成后(见时间),“程序结束......”才回显到屏幕上。
为什么?
我怎么能在后台运行这两个任务(都使用承诺),这样它们就不会阻止事件循环和我的“程序结束......”字符串立即回显?
JavaScript 始终在单线程中运行。如果您有繁重的同步处理负载,仅仅在异步上下文中删除同步负载是不够的:执行可能会延迟,但是当函数确实需要执行时,其中的所有代码仍然同步执行。
您实际上有两个选择:
clusterapi 生成一个工作线程并让工作线程执行同步处理setImmediate并将处理分成可以一次处理一个的离散块,在某些点手动延迟同步处理。为了您的研究,您可能有兴趣阅读 node.js 本身使用工作线程进行文件系统操作。我认为网络操作是通过轮询处理的。在这两种情况下,所有处理负载都发生在主 node.js 进程之外(在另一个线程或另一台计算机上)。如果您的目标是让同步处理负载无阻塞,您也应该这样做。
我还在 node.js 文档中找到了这个优秀的指南,它基本上涵盖了我上面描述的内容,但使用了更好的术语和更多细节:https : //nodejs.org/en/docs/guides/dont-block-the-event-loop /#complex-calculations-without-blocking-the-event-loop