关于Nodejs中方法声明和调用的参数不一致的困惑

关于Nodejs中方法声明和调用的参数不一致的困惑

Hi everyone 我在看Ghost的server.js时看到这样一个函数声明:

function initViews(req, res, next) {
var hbsOptions;

if (!res.isAdmin) {
    // self.globals is a hack til we have a better way of getting combined settings & config
    hbsOptions = {templateOptions: {data: {blog: ghost.blogGlobals()}}};

    if (ghost.themeDirectories[ghost.settings('activeTheme')].hasOwnProperty('partials')) {
        // Check that the theme has a partials directory before trying to use it
        hbsOptions.partialsDir = path.join(ghost.paths().activeTheme, 'partials');
    }

    server.engine('hbs', hbs.express3(hbsOptions));
    server.set('views', ghost.paths().activeTheme);
} else {
    server.engine('hbs', hbs.express3({partialsDir: ghost.paths().adminViews + 'partials'}));
    server.set('views', ghost.paths().adminViews);
}

next();

}

而他的调用方式是 server = express(); server.use(initViews);

不明白req, res, next这三个参数如何传进来,传进来的参数究竟是什么?

十分感谢!


5 回复

当然可以。让我们详细解释一下这段代码中的参数传递机制以及这些参数的具体含义。

关于 Node.js 中方法声明和调用的参数不一致的困惑

在你提到的 initViews 函数中,参数 req, res, 和 next 是典型的中间件函数(middleware function)的参数。在 Express.js 框架中,中间件函数通常会接收三个参数:请求对象 (req)、响应对象 (res) 和下一个中间件函数 (next)。

示例代码解释

function initViews(req, res, next) {
    var hbsOptions;

    if (!res.isAdmin) {
        // 自定义选项
        hbsOptions = { templateOptions: { data: { blog: ghost.blogGlobals() } } };

        if (ghost.themeDirectories[ghost.settings('activeTheme')].hasOwnProperty('partials')) {
            // 如果主题有部分目录,则使用它
            hbsOptions.partialsDir = path.join(ghost.paths().activeTheme, 'partials');
        }

        server.engine('hbs', hbs.express3(hbsOptions));
        server.set('views', ghost.paths().activeTheme);
    } else {
        // 管理员视图
        server.engine('hbs', hbs.express3({ partialsDir: ghost.paths().adminViews + 'partials' }));
        server.set('views', ghost.paths().adminViews);
    }

    next();  // 调用下一个中间件
}

参数解释

  • req: 请求对象,包含了客户端发送的所有数据。
  • res: 响应对象,用于向客户端发送数据或响应。
  • next: 下一个中间件函数的回调,用于链式调用多个中间件。

调用方式

当你将 initViews 作为中间件添加到 Express 应用程序时,Express 会在请求到达该中间件时自动传递这三个参数。

const express = require('express');
const server = express();

// 将中间件添加到应用程序
server.use(initViews);

// 启动服务器
server.listen(3000, () => {
    console.log('Server running on port 3000');
});

在这个例子中,server.use(initViews) 实际上是在告诉 Express 在处理请求时调用 initViews 函数,并且会自动将 req, res, 和 next 作为参数传递给 initViews

总结

通过这种方式,你可以理解为什么 initViews 函数在声明时需要三个参数,但在调用时并不需要显式地传递这些参数。这是因为 Express 框架会自动处理参数的传递。希望这能帮助你理解这种机制。


看来你还很不了解回调的机制, initViews是一个函数, 回调这个函数的时候会传给他3个参数, req, res, next 其实你也可以arguments[0], arguments[1]… 这样

initViews function is a express framework middleware.

req,res and next arguments is provided by the express framework.


签名 《Node.js 服务器框架开发实战》 http://url.cn/Pn07N3

function initViews(req, res, next) {
  // ...
  next();
}

server.use(initViews);

简化一下代码可能容易理解一些。

initViews(req, res, next) 是你声明的一个函数,它接受 req res next 三个参数。

调用 server.use(initViews) 的时候,initViews 传给了 serverserver 会在内部执行 initViews(req, res, next),其中 nextserver 内部的另一个函数。

在Node.js中,当你使用中间件(middleware)时,通常会遇到类似req, res, next这样的参数。这些参数分别代表请求对象(request)、响应对象(response)和下一个中间件函数(next middleware function)。在Express框架中,这些参数是由Express框架自动注入的。

对于你的例子,initViews函数作为中间件被注册到Express应用中,因此它会在每个HTTP请求到达服务器时被调用,并且Express会自动提供reqresnext这三个参数。

示例代码

假设你有一个简单的Express应用:

const express = require('express');
const path = require('path');

const app = express();

// 假设你有一个initViews中间件
function initViews(req, res, next) {
    console.log('Request Type:', req.method);

    if (req.url === '/') {
        res.send('Hello, this is the homepage!');
    } else {
        next();  // 调用下一个中间件或路由处理程序
    }
}

// 注册中间件
app.use(initViews);

// 路由处理程序
app.get('/', (req, res) => {
    res.send('Hello World!');
});

app.listen(3000, () => {
    console.log('Server running on http://localhost:3000');
});

解释

  1. req: 这是请求对象,包含了客户端发送的所有信息,如请求方法、URL、头部信息等。
  2. res: 这是响应对象,用于向客户端发送响应数据,如HTML页面、JSON数据等。
  3. next: 这是一个函数,用于调用下一个中间件或路由处理程序。如果当前中间件没有完成请求-响应循环,需要调用next()来传递控制权给下一个中间件或路由处理程序。

在你的initViews函数中,reqres会被Express自动注入,你可以在函数内部访问它们。next用于确保在处理完特定逻辑后,可以继续执行其他中间件或路由处理程序。

回到顶部