我读到了节点的事件循环阶段,并说
所以这里我有一个简单的代码来测试上面的一些阶段。当您执行代码时,您将得到以下输出:
但是套接字回调(如doc )是最后一个阶段。为什么要先执行?
let socket = require("net").createServer();
socket.on("data", function (data) {
console.log(data.toString());
});
socket.on("close", function (data) {
console.log("close");
});
socket.listen(8080);
const fs = require("fs");
fs.readFile("readme.txt", () => {
socket.close();
setTimeout(() => {
console.log("timeout");
}, 0);
setImmediate(() => {
console.log("immediate");
});
});发布于 2020-04-11 20:31:19
首先,请记住,本地关闭套接字触发的close事件不是网络操作。它不是由传入的网络事件触发的。它是由本地套接字实现触发的,该实现决定何时触发关闭事件,以通知监视本地套接字的其他任何人它现在已关闭。它甚至可以同步触发(如果实现它的net库选择这样做)。因此,您所读到的任何关于如何在事件循环中对网络事件进行排序或排序的内容都不适用于这里。此事件不是由传入的网络操作触发的,也不像传入的网络操作那样通过事件循环。
我在调试器中遍历了您的代码,并深入到socket.close()中,试图查看实现做了什么。它到达这一行这里,其中is调用this._handle.close()。这将进入用C++编写的一些TCP包装层,调试器将不让您进一步跟踪它。
然后,该函数继续调用emitCloseIfDrained(),后者调用defaultTriggerAsyncIdScope(),并将process.nextTick()作为异步机制使用。
因此,本地调用socket.close()似乎会导致套接字库在调用close事件之前使用process.nextTick(),这将使其在其他事情之前得到处理具有相当高的优先级,但将在事件循环的未来滴答中进行处理。
但是,我希望您现在可以看到这是如何依赖于超级实现(取决于在任何库中触发事件的方式),而不是文档化的,因此不应该依赖于您的实现。出于对知识的好奇,想尽可能多地理解这一点是可以的,但您不应该设计依赖于这种实现细节级别的代码。一个特殊的特性,比如当close事件在套接字上触发时,没有文档记录,也没有承诺它将来不会改变。如果您的代码需要对异步事件进行特定的排序,则需要编写代码来管理该序列,以确保无论实现细节的级别如何,都会发生这种情况。
https://stackoverflow.com/questions/61162869
复制相似问题