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”;
});
}
}
当然可以。让我们来分析一下这两个代码片段,并解释为什么它们的工作方式不同。
第一段代码
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
事件时,监听器才会被执行。
解释
- 事件监听器:即使
status
不是ready
,select
函数也会注册一个新的事件监听器。这意味着每个select
调用都会增加一个监听器。 - 事件触发:当
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
库来管理事件监听器。这里的关键点在于:
proxy.once("selected", callback);
:这行代码为"selected"
事件注册了一个只执行一次的监听器。proxy.emit("selected", results)
:当数据库查询完成时,通过emit
方法触发"selected"
事件,并将查询结果传递给所有注册过的监听器(在这个例子中只有一个)。
即使select
函数被多次调用,只有第一个查询的结果会被传递给回调函数,因为once
方法保证事件处理函数只执行一次。
解释
- 第一次调用:当状态为
"ready"
时,db.select
会被调用,并且事件监听器会被注册。 - 后续调用:如果
status
已经是"pending"
,则不会重复执行db.select
。然而,每次调用都会注册一个新的监听器,但由于once
的特性,这些监听器实际上不会被执行,除非它们注册后立即触发。
这样可以确保即使多次调用select
,只有首次查询的结果会被处理。这种方式适用于需要串行处理的场景,如异步操作依赖于前一个操作的结果。