Node.js 如何加入同步和异步世界?

Node.js 如何加入同步和异步世界?,node.js,mongoose,Node.js,Mongoose,我从NodeJs开始,我面临一个问题,我相信很多人可能已经解决了 我有一个基本的NodeJs web服务器,在找到文件时提供文件服务,或者404: var http = require('http'), url = require('url'), fs = require('fs'), mongoose = require('mongoose'), fileSystem = require('fs'), path = require('path'),

我从NodeJs开始,我面临一个问题,我相信很多人可能已经解决了

我有一个基本的NodeJs web服务器,在找到文件时提供文件服务,或者404:

var http = require('http'),
    url = require('url'),
    fs = require('fs'),
    mongoose = require('mongoose'),
    fileSystem = require('fs'),
    path = require('path'),
    util = require('util'),
    EventEmitter = require('events').EventEmitter;
var mimeTypes = {
    "html": "text/html",
    "jpeg": "image/jpeg",
    "jpg": "image/jpeg",
    "png": "image/png",
    "js": "text/javascript",
    "css": "text/css"};
var server;
var Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/test');
var db = mongoose.connection;

var personneSchema = new Schema({
    nom: String,
    prenom: String
});
var Personne = db.model('Personne', personneSchema);

var personneAdresseSchema = new Schema({
    idPersonne: String,
    idAdresse: String
});
var PersonneAdresse = db.model('PersonneAdresse', personneAdresseSchema);

var adresseSchema = new Schema({
    ligne1: String,
    ligne2: String,
    codePostal: String,
    ville: String
});
var Adresse = db.model('Adresse', adresseSchema);
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function () {
    server = http.createServer(function (request, response) {
        if (request.url=='/persons') {
            console.log('> Persons request');
            /* IMPLEMENTATION PROBLEM HERE */
            var retour='[]';
            retour=retour.substr(0, retour.length-1)+']';
            response.writeHead(200, {
                'Cache-Control': 'no-cache, must-revalidate',
                'Expires': 'Mon, 26 Jul 1997 05:00:00 GMT',
                'Content-type': 'application/json'
            });
            response.end(retour);
            console.log('> end of main function');
            return;
        }
        var uri = url.parse(request.url).pathname;
        var filename = path.join(process.cwd(), uri);
        console.log("> " + filename);
        fs.exists(filename, function(exists) {
            if ((!exists) || (fs.lstatSync(filename).isDirectory())) {
                console.log(">> fichier inexistant : " + filename);
                response.writeHead(200, {'Content-Type': 'text/plain'});
                response.write('404 Not Found\n');
                response.end();
                // Stopper tout traitement :
                return;
            }
            var mimeType = mimeTypes[path.extname(filename).split(".")[1]];
            response.writeHead(200, {'Content-Type':mimeType});

            var fileStream = fs.createReadStream(filename);
            fileStream.pipe(response);
        });
    });
    // Listen on port 8000, IP defaults to 127.0.0.1
    server.listen(8000);
    // Put a friendly message on the terminal
    console.log("Server running at http://127.0.0.1:8000/");
});
问题是:Web服务器需要在“main”函数结束之前准备好要发送的响应。但是如果你试着打猫鼬的电话,它是不同步的。如果在主函数中输入以下代码:

Personne.find({}).select('nom prenom').exec(function (err, p) {
    console.log('> Persons request finished');
});
日志显示如下内容:

> Persons request
> end of main function
> Persons request finished

因此,需要填写“response”的主函数不能用
Personne.find({})
填充,因为
Personne.find({})
之后完成。处理这个问题的方法是什么?我在网上找不到一个非常简单、自我解释的例子(nodejs+mongoose总是给我单独使用nodejs、mongoose或使用完整的Web框架的解决方案,而我只需要一个简单的工作示例).

要在数据库调用完成后执行的任何代码都必须位于数据库调用的回调函数中。因此,您不能只将数据库调用放在主函数中——您必须将数据库调用后需要执行的主函数中的所有代码移到回调函数中。

如果您希望在mongo查询完成后启动服务器,您可以使用回调:

db.once('open', function () {
     server = http.createServer(function (request, response) {
        Personne.find({}).select('nom prenom').exec(function (err, persons) {
            // Log the result of the query
            console.log(persons) 
            // After the query is executed, you can use the results anywhere else inside your logic
            if (request.url=='/persons') {
                console.log('> Persons request');
                /* IMPLEMENTATION PROBLEM HERE */
                var retour='[]';
                retour=retour.substr(0, retour.length-1)+']';
                response.writeHead(200, {
                    'Cache-Control': 'no-cache, must-revalidate',
                    'Expires': 'Mon, 26 Jul 1997 05:00:00 GMT',
                    'Content-type': 'application/json'
                });
                response.end(retour);
                console.log('> end of main function');
                return;
            }
            var uri = url.parse(request.url).pathname;
            var filename = path.join(process.cwd(), uri);
            console.log("> " + filename);
            fs.exists(filename, function(exists) {
                if ((!exists) || (fs.lstatSync(filename).isDirectory())) {
                    console.log(">> fichier inexistant : " + filename);
                    response.writeHead(200, {'Content-Type': 'text/plain'});
                    response.write('404 Not Found\n');
                    response.end();
                    // Stopper tout traitement :
                    return;
                }
                var mimeType = mimeTypes[path.extname(filename).split(".")[1]];
                response.writeHead(200, {'Content-Type':mimeType});

                var fileStream = fs.createReadStream(filename);
                fileStream.pipe(response);
            });
        });

    });
    // Listen on port 8000, IP defaults to 127.0.0.1
    server.listen(8000);
    // Put a friendly message on the terminal
    console.log("Server running at http://127.0.0.1:8000/");

});

你在错误的假设下运作。在完成主功能之前,服务器不需要提供响应。您可以将响应作为稍后出现的异步响应的一部分提供—事实上,许多nodejs服务器都会这样做(几乎所有使用数据库的服务器都会这样做)。在回答您最初的问题时,您不能让同步操作等待完成,直到异步操作完成。JS不是这样工作的。如果有异步操作,则需要以异步方式编程。这意味着在调用异步回调时使用回调并完成您的工作,然后让原始的sync函数完成。非常感谢您的建议,但是我可以请您给我一个处理异步数据库调用并返回它的工作示例吗?非常感谢您的回答,但我可以请您添加一个处理异步数据库调用并返回它的工作示例吗?@OlivierPons-您一直要求返回异步数据。这不是它的工作原理。阅读迈克的答案。你就是这样做的。任何使用异步结果的代码都会进入异步完成回调本身。你没有返回结果。嗨,如果我没有解释我自己,我很抱歉:我只想看到婚姻的(工作+非常基本)版本:mongoose/nodejs。似乎使用你的代码,当Web服务器启动后有新的人添加到数据库中时,它在Web中不可见,因为查询是在Web服务器启动之前完成的。。。除非我遗漏了什么?不知道你的意思。执行查询后,服务器启动。如果在服务器启动后添加了新的人员,如果您重新运行相同的查询,它将显示新的人员。是的,您是对的,但在您的代码中,您何时重新运行相同的查询?好像。。。从未。似乎您在服务器开始时只运行一次(这是一个无止境的循环,在这个无止境的循环中,您似乎无法重新运行查询)…我明白您的意思,我对您的预期用途感到困惑。我会修改我的答案。我已经修改了我的答案,如果这是你想要的,请告诉我。