使用asynchronousNode.JS来服务HTTP请求

我已经成功地编写了几个nodejs HTTP处理程序来响应HTTP请求来提供数据。 但是,我写的所有内容都使用了* Sync函数版本。 我现在很快遇到了这种方法的局限性。

但是,我不知道如何在HTTP请求上下文中正确使用asynchronous函数。 如果我尝试一个asynchronous调用,处理迅速通过并返回,而不给代码处理数据的机会。

什么是正确的方法? 我还没有find任何好的例子,所以任何指向文学的指针都是值得赞赏的。 简言之,GET请求的处理程序的例子是扫描本地目录,例如返回一个json的文件名列表和相应的行数(或者真正的上面的任何存根代码,显示正确的技术) 。

这是一个简单的例子:

 var http = require('http') var fs = require('fs') function dir (req, res) { fs.readdir('.', function (error, files) { if (error) { res.writeHead(500) res.end(error.message) return } files.forEach(function (file) { res.write(file + '\n') }) res.end() }) } var server = http.createServer(dir) server.listen(7000) 

使用node server.js运行并使用curl :7000testing。

是的,请求处理程序在执行readdircallback之前返回。 这是devise。 这就是asynchronous编程的工作原理。 没关系。 当文件系统IO完成时,callback将被执行并且响应将被发送。

彼得里昂的答案是伟大的/正确的。 我将稍微扩展一下,并提出使用promise和co以及嵌套/循环asynchronous性的不同方法。

 /* Script to count all lines of a file */ const co = require("co"); // Promisifed fs -- eventually node will support this on its own const fs = require("mz/fs"); const rootDir = 'files/'; // Recursivey count the lines of all files in the given directory and sum them function countLines(directory) { // We can only use `yield` inside a generator block // `co` allows us to do this and walks through the generator on its own // `yield` will not move to the next line until the promise resolves // // This is still asynchronous code but it is written in a way // that makes it look synchronized. This entire block is asynchronous, so we // can `countLines` of multiple directories simultaneously return co(function* () { // `files` will be an array of files in the given directory const files = yield fs.readdir(directory); // `.map` will create an array of promises. `yield` only completes when // *all* promises in the array have resolved const lines = yield files.map(file => countFileLines(file, directory)); // Sum the lines of all files in this directory return lines.reduce((a, b) => a + b, 0); }); } function countFileLines(file, directory) { // We need the full path to read the file const fullPath = `${directory}/${file}`; // `co` returns a promise, so `co` itself can be yielded // This entire block is asynchronous so we should be able to count lines // of files without waiting for each file to be read return co(function* () { // Used to check whether this file is a directory const stats = yield fs.stat(fullPath); if (stats.isDirectory()) { // If it is, recursively count lines of this directory return countLines(fullPath); } // Otherwise just get the line count of the file const contents = yield fs.readFile(fullPath, "utf8"); return contents.split("\n").length - 1; }); } co(function* () { console.log(yield countLines(rootDir)); }) // All errors propagate here .catch(err => console.error(err.stack)); 

请注意,这只是一个例子。 可能已经有库来计算目录中的文件行数,并且肯定有一些库可以简化文件的recursion读取/匹配。