为什么我的请求和响应消息不按顺序?

我正在通过一本教你了解Node.JS基础知识的书,并创build了几个程序 – 一个响应者和一个请求者。

回应者:

"use strict"; const fs = require("fs"); const zmq = require("zmq"); const responder = zmq.socket("rep"); // Create socket to reply to client requests // Handle incoming requests responder.on("message", function(data) { // Parse incoming message let request = JSON.parse(data); console.log("Received request to get: " + request.path); // Read file and reply with content fs.readFile(request.path, function(err, content) { console.log("Sending response content"); responder.send(JSON.stringify({ content: content.toString(), timestamp: Date.now(), pid: process.pid })); }); }); // Listen on TCP port 5433 responder.bind("tcp://127.0.0.1:5433", function(err) { console.log("Listening for zmq requesters..."); }); // Close the responder when the Node process ends process.on("SIGINT", function() { console.log("Shutting down..."); responder.close(); }); 

请求者:

 "use strict"; const zmq = require("zmq"); const filename = process.argv[2]; const requester = zmq.socket("req"); // Create request endpoint // Handle replies from responder requester.on("message", function(data) { let response = JSON.parse(data); console.log("Received response:", response); }); requester.connect("tcp://localhost:5433"); // Send request for content for (let i=1; i <= 3; i++) { console.log("Sending request " + i + " for " + filename); requester.send(JSON.stringify({ path: filename })); } 

所以我运行启动的响应程序,然后运行请求程序( target.txt已经存在于文件系统中):

 > node requester.js target.txt 

奇怪的是,给定Node.js的单线程,我希望输出总是

 Sending request 1 for target.txt Sending request 2 for target.txt Sending request 3 for target.txt Received response: { ... 

但是,有时候我明白了,但是有时我会得到:

 Sending request 1 for target.txt Sending request 2 for target.txt Received response: { ... Sending request 3 for target.txt 

怎么会这样? 事件循环正在执行我for循环,这应该意味着“发送请求”行输出,然后有机会调用响应处理程序。 为什么我有时会在第三个请求被logging之前得到一个响应?

很明显,只有在send实现中调用了提供的callback时,才能看到您所看到的行为。

zmq模块包含本地代码。 它以本地代码接收响应,然后使其可用于JavaScript主机。 它的回应没有和JavaScript事件循环绑定在一起。 看来在send实现中,如果响应可用,则调用提供给的callback。 据推测,没有传递给send调用中的callback的任何响应在下一个回合通过事件循环传递。

在读取函数中的文件时,使用fs.readFile ,它是一个asynchronous的非阻塞函数(它将在新线程中读取文件)。 这意味着在接受新的请求之前,它不会等待文件被读取。

如果你想使用同步function,你可以使用

 fs.readFileSync 

这将等待文件被完全读取,然后发送响应。