有人可以从howtonode解释一个包装成语的函数吗?

Posted

技术标签:

【中文标题】有人可以从howtonode解释一个包装成语的函数吗?【英文标题】:Could someone explain a function wrapping idiom from howtonode? 【发布时间】:2013-02-24 14:43:57 【问题描述】:

我最近开始使用 node.js、express 和 mongodb。由于 express 使用 connect 来提供中间件支持,我开始阅读中间件和连接。

我在howtonode.org 上遇到了以下示例:

return function logItHandle(req, res, next) 
 var writeHead = res.writeHead; // Store the original function

 counter++;

 // Log the incoming request
 console.log("Request " + counter + " " + req.method + " " + req.url);

 // Wrap writeHead to hook into the exit path through the layers.
 res.writeHead = function (code, headers) 
   res.writeHead = writeHead; // Put the original back

   // Log the outgoing response
   console.log("Response " + counter + " " + code + " " + JSON.stringify(headers));

   res.writeHead(code, headers); // Call the original
 ;

 // Pass through to the next layer
 next(); 
;

有人可以向我解释一下这次关闭中发生了什么吗?作者称之为

包装成语以挂钩到 writeHead 的调用

这是什么意思?

【问题讨论】:

【参考方案1】:

它正在拦截对res.writeHead 的调用,添加一些日志记录,然后将调用委托给原始res.writeHead

这就像一个超级简单的 AOP 方法拦截。

【讨论】:

谢谢两位!我接受@matt 的回答只是因为它不仅解释了正在发生的事情,而且还引导我进入 AOP,因此现在我有了一些新的材料可以研究。【参考方案2】:

让我们分解这里发生的事情

wrapping idiom to hook into the call to writeHead

在标准 express 流程中,接收请求 (req) 并准备响应 (res)。 (req, res) 对可以通过一系列过滤器级联,这些过滤器可以修改 req 并准备 res强>.

在流程中的某一时刻,res 将被视为已准备就绪,可以将响应的标头发送到客户端。将为此目的调用函数 res.writeHead*。

这个函数的原型是function(code, headers),为了记录要发送的headers,你需要在这个时候hook代码并做一个

console.log("Response " + code + " " + JSON.stringify(headers));

在某种程度上,如果代码中的原始函数是

res.writeHead = function(code, headers) 
    // original code

您想将此代码替换为

res.writeHead = function(code, headers) 
    console.log("Response " + code + " " + JSON.stringify(headers));
    // original code

在某种程度上,您希望在 writeHead 函数的开头“插入”一段代码。

但是您不应该尝试修改原始 writeHead 代码,因为您可能甚至不知道这段代码是在哪里编写的,并且您不想开始查找。所以你想劫持这个函数:当一段代码调用 res.writeHead 时,你希望你的函数被调用。

解决方法很简单

return function logItHandle(req, res, next) 
   res.writeHead = function (code, headers) 
       console.log("Response " + code + " " + JSON.stringify(headers));
   
   next(); 

但是如果你只这样做,你会遇到一些麻烦,因为原始的 writeHead 代码会丢失并且不会被调用。因此,标头将被记录但不会发送到客户端!

您需要一种方法来“记住”原始代码并在 writeHead 变体的末尾调用它:

return function logItHandle(req, res, next) 

   // save the original writeHead function so that it can be referenced in the closure
   var originalWriteHead = res.writeHead; 

   res.writeHead = function (code, headers) 

       // log the response headers
       console.log("Response " + code + " " + JSON.stringify(headers));

       // make as if our hook never existed in the flow
       res.writeHead = originalWriteHead ;

       // call the original writeHead because otherwise the external code
       // called our implementation of writeHead instead of the original code
       res.writeHead(code, headers);

   
   next(); 

【讨论】:

以上是关于有人可以从howtonode解释一个包装成语的函数吗?的主要内容,如果未能解决你的问题,请参考以下文章

jquery .val() += 成语

压倒一切四字成语解释

成语接龙敢玩嘛:—偷偷学成语,然后惊艳所有人!龙腾虎跃,该你了?评论区见

什么是特征选择的前馈包装方法?

有一个成语,就是事实不是这样的,但是多的人说了,也就成了这样?

有人可以解释这个递归函数吗? [关闭]