Nodejs 请教深入浅出书里的一个例子

Nodejs 请教深入浅出书里的一个例子

例子是这样的,第一段代码里如果连续调用select的话,只有第一次生效。 第二段代码可以把多次调用排在时间队列里。 我不懂的是第二段里,虽然是每次调用会增加一个事件监听,但是如果在查询状态是状态不是ready,程序不会运行到proxy触发selected事件吧?如果没有触发,只是添加了事件监听有什么用呢? 我强烈觉得我哪里没理解正确,请指教。谢谢!

var status = "ready";
var select = function(callback) {
  if (status === "ready"){
    status = 'pending';
    db.select("SQL", function (results){
      callback(results);
      status = "ready";
    });
  }
}
var proxy = new EventProxy();

var status = “ready”; var select = function(callback) { proxy.once(“selected”, callback); if (status === “ready”){ status = ‘pending’; db.select(“SQL”, function (results){ proxy.emit(“selected”, results) status = “ready”; }); } }


10 回复

当然可以。让我们来分析一下这两个代码片段,并解释为什么它们的工作方式不同。

第一段代码

var status = "ready";
var select = function(callback) {
  if (status === "ready"){
    status = 'pending';
    db.select("SQL", function (results){
      callback(results);
      status = "ready";
    });
  }
}

在这段代码中,select 函数只会执行一次 db.select 操作,因为 status 只会在 ready 状态下才会执行该操作。一旦 status 被设置为 pending,后续的 select 调用将被忽略,直到 status 变回 ready 状态。

第二段代码

var proxy = new EventProxy();
var status = "ready";
var select = function(callback) {
  proxy.once("selected", callback);
  if (status === "ready"){
    status = 'pending';
    db.select("SQL", function (results){
      proxy.emit("selected", results)
      status = "ready";
    });
  }
}

在这段代码中,我们使用了一个 EventProxy 对象来管理事件监听。无论 status 是否为 ready,每次调用 select 都会注册一个新的事件监听器。然而,只有当 db.select 完成并触发 selected 事件时,监听器才会被执行。

解释

  1. 事件监听器:即使 status 不是 readyselect 函数也会注册一个新的事件监听器。这意味着每个 select 调用都会增加一个监听器。
  2. 事件触发:当 db.select 完成时,它会触发 selected 事件,并调用所有已注册的监听器(通过 proxy.emit)。因此,即使 status 不是 ready,只要之前有注册过监听器,它最终会被触发。

示例

假设我们有多个异步请求需要处理:

// 假设 EventProxy 是一个自定义库
const EventProxy = require('eventproxy');

var proxy = new EventProxy();

var status = "ready";

var select = function(callback) {
  proxy.once("selected", callback);
  if (status === "ready"){
    status = 'pending';
    db.select("SQL", function (results){
      proxy.emit("selected", results);
      status = "ready";
    });
  }
}

// 模拟多个 select 调用
for (let i = 0; i < 5; i++) {
  select(function(results) {
    console.log(`Query result: ${results}`);
  });
}

在这个例子中,尽管我们连续调用了 select 函数,但只有当 db.select 完成后,结果才会被传递给回调函数。这样可以确保所有的查询都能得到处理,而不会被遗漏。

希望这能帮助你理解这段代码的工作原理。如果你有任何进一步的问题,请随时提问。


第二段代码和第一段代码一样的效果啊。作者只是想引入Eventproxy

如果是单层的callback我还挺喜欢的。如果多了就要用链式的

单层的嵌套还体现不出 eventproxy 的威力

书上明明是说因为段1的残次品,所以引入段2代码啊。我表示十分不解。 2楼,3楼又是几个意思。。

第一段代码是错误的,因为if (status === "ready"){不能阻止多个进程读db,status重新复制是有时差的。 第二段代码的意思是即使发生这种极限情况,回调也只执行一次。 还有evnetproxy并没有真的注册事件,看看源码就知道了,只是保存了回调函数和计数器,其实就是个双重保险, 可是话又说回来,极限情况下,proxy.emit又怎么能保证只执行一次回调呢。。呵呵

这里应该是一个module的部分代码片段,select是导出的一个方法:

module.exports.select = select;

然后在使用时,比如:

var db = require('./db')
function(req, res) {
  db.select(function(results)) {
    res.send(results);
  }
}

第一种写法,除了第一次请求,后续请求都会超时 第二种写法,所有请求都会获得结果

两段代码都是正确的,只是第二种更好一些

第二种写法,所有请求还是会运行到if(status == 'ready')这里。如果status不是ready,就不会触发任何事件。为什么所有请求会获得结果呢?

你的问题在于对事件驱动机制的理解。在Node.js中,事件监听器会在特定事件发生时被触发执行。让我们先看下两个代码片段的区别:

第一段代码

var status = "ready";
var select = function(callback) {
  if (status === "ready"){
    status = 'pending';
    db.select("SQL", function (results){
      callback(results);
      status = "ready";
    });
  }
}

在这段代码中,select函数只会执行一次数据库查询,因为它检查了status是否为"ready"。如果状态已经是"pending",则不会再次执行数据库查询。

第二段代码

var proxy = new EventProxy();
var status = "ready";
var select = function(callback) {
  proxy.once("selected", callback);
  if (status === "ready"){
    status = 'pending';
    db.select("SQL", function (results){
      proxy.emit("selected", results)
      status = "ready";
    });
  }
}

这段代码使用了EventProxy库来管理事件监听器。这里的关键点在于:

  1. proxy.once("selected", callback);:这行代码为"selected"事件注册了一个只执行一次的监听器。
  2. proxy.emit("selected", results):当数据库查询完成时,通过emit方法触发"selected"事件,并将查询结果传递给所有注册过的监听器(在这个例子中只有一个)。

即使select函数被多次调用,只有第一个查询的结果会被传递给回调函数,因为once方法保证事件处理函数只执行一次。

解释

  • 第一次调用:当状态为"ready"时,db.select会被调用,并且事件监听器会被注册。
  • 后续调用:如果status已经是"pending",则不会重复执行db.select。然而,每次调用都会注册一个新的监听器,但由于once的特性,这些监听器实际上不会被执行,除非它们注册后立即触发。

这样可以确保即使多次调用select,只有首次查询的结果会被处理。这种方式适用于需要串行处理的场景,如异步操作依赖于前一个操作的结果。

回到顶部