深入浅出 Node.js - 利用事件队列解决雪崩问题
发布于 8 年前 作者 IvanYoung-GitHub 4628 次浏览 来自 问答
var proxy = new events.EventEmitter();
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(callback){}中的db.select(“SQL”, function(results)…)函数在后台子线程(底层)要执行一个小时才返回结果,那在此期间,第二次调用select(callback)的时候,也就进不了if (status === “ready”){}这段代码了,也就缺少了“selected”事件的emit,会导致listener内存泄漏吧?

书上只简单说明Node单线程执行,无需担心状态同步问题,这个好像说不过去啊。(异步I/O操作实际在底层还是以子线程形式执行的啊)

2 回复

疑问:就是假定db.select()耗时1个小时,在这1小时内所有的select()调用里的(status === “pending”),即1小时内的所有select()调用均无法执行完整。 (求教,在线等…这个理解哪出问题了…)

假设有十个查询几乎同时出现。 第一个查询不用多说,从上往下每一行都执行。但是这时其他九个查询也在调用这个函数(第一个查询正在数据库select) 从第二到第十的每次查询,都会通过 once 方法订阅 selected 事件。这是 status=== ‘pending’,所以在订阅了 selected 事件后什么都不做,只有回调函数 callback 被压入事件队列中。 当第一个查询结束后,执行 emit 方法发布 selected 事件并更新状态。此时,第二到十个订阅了 selected 事件的请求的 callback 函数被依次调用,并传入查询结果 results 作为参数。 这时,status 就会变为 ready,又可以响应其他的查询了。 整个过程中,其实只查询了数据库一次,第二到第十个查询只是利用了第一次查询的结果执行了回调而已。 emit 这件事其实是第一个查询做的,而且做完 listener 就回收,从第二个到第十个查询的 callback 函数在第一个函数 emit 以后执行,所以不存在内存泄漏。

回到顶部