在Node.js中传递变量?

时间:2012-12-11 20:57:59

标签: javascript node.js

所以,我正在尝试将我的聊天系统升级到Node.js,多年来我一直觉得不像这样的菜鸟!

在PHP中,它效率低下,但它绝对有意义。请求启动,它会计算出用户信息,房间信息,解析消息等等。相当线性。它在不同的地方调用了几个函数,但每次只需要直接向该函数发送所需的信息。当该函数完成后,它将返回,然后使用不同的信息完成更多工作。如果有异常,它(通常)会被捕获到可以提醒用户的级别。

据我所知,Node.js绝对不会像这样工作,而是主要由回调驱动 - 而且我有很多回调正在进行中。它必须处理初始连接,然后它必须检查cookie文件是否存在,然后它必须读取cookie文件,然后它必须从数据库获取一些用户信息,然后它必须得到一些来自数据库的其他用户信息,然后它必须从数据库中获取更多用户信息,然后它必须将用户添加到房间,如果有一段时间没有任何人 - 必须得到来自数据库的房间信息,然后最终响应请求。当我完成时,将至少有两个级别用于权限检查。

它与PHP进程没什么不同,但在PHP中它通过Apache进行多线程处理,因此请求可以坐在那里等待DB调用返回完全没有问题。用户查找,房间订阅,权限,所有这些都是单独处理的。

在Node.js中,“当你完成那个”系统时,难以理解(我已经使用了客户端JS和jQuery),但变量传递当然是。其中很大一部分是try / catch被回调完全击败了。如果房间数据查询查询失败,该函数需要知道它应该将错误发送回哪个连接(此时可能是过去的两三个连接),因为它不会冒泡最多可以追上几个级别。因此,连接对象需要在整个过程中向下传递每个回调。这在处理异常时只是有点恶心,因为那些可能发生在任何地方,但当你到达其他变量必须一直传递到最后的一个回调线时,我的手指拒绝再打字,直到我看到那些非常糟糕的东西!

所以我想我想知道的是,如果有任何“黑客”我不熟悉可能允许变量“跳过”非嵌套回调。无限期地尝试/捕获链条也会很有效。

编辑:我无法轻视数百行代码,所以让我们看看我是否可以通过回调堆栈提供一些视觉帮助。同一行上的任何内容都是直接调用,下一行是回调。

connection.on('messaage') -> controller.validateUser -> fs.exists
 fs.readFile
  function() -> controller.addUser -> factory.user -> user.refreshData -> db.query
   user.refreshChars -> db.query
    user.refreshBlocks -> db.query
     function() -> controller.addRoom -> factory.room -> room.refreshData -> db.query
      room.getRole -> db.query
       function() -> room.getUserList -> connection.sendUTF

如您所见,这些函数主要位于对象中,而不仅仅是嵌套的未命名函数,因为它们通常需要以任意顺序从多个位置访问。问题是,某些级别需要用户对象,而有些级别则不需要。如果try / catch工作正常,只有第一个和最后一个需要知道发送信息的连接。

我需要的是一种为这些不同功能提供不同信息的方法,而不必使用他们不需要的东西来淹没每个功能。 是不受欢迎的做法。我还需要各种用户对象函数以非常不同的方式失败 - 对象不需要关注其自身的方式,因为它是调用函数的责任。

1 个答案:

答案 0 :(得分:0)

initial(); // begins the process


  // this starts things off
function initial() {
    var props = {  // this is the common object
        onerror: function(err) {
                     if (err.msg === "reallyBadError")
                         return false; // false means stop
                     else
                         return true;  // true means we can continue
                 },
        someInitialData: {whatever:"data"}
    };

    doSomethingAsync(getFirstCallback(props));
}


function getFirstCallback(props) {

        // return the actual callback function
    return function(err, info) {
           // if callback was passed an error, handle it
        if (err && props.onerror(err) === false)
            return;

        props.info = info; // add something to props
        doAnotherAsync(getSecondCallack(props));
    };
}


function getSecondCallback(props) {

        // return the actual callback function
    return function(err, foo) {
           // if callback was passed an error, handle it
        if (err && props.onerror(err) === false)
            return;

        // maybe do something with props.info
        props.foo = foo; // add something to props
        doOneMoreAsync(getFinalCallack(props));
    };
}


function getFinalCallback(props) {

        // return the actual callback function
    return function(err, bar) {
           // if callback was passed an error, handle it
        if (err && props.onerror(err) === false)
            return;

        // maybe do something with props.info and props.foo

        // we also have access to the original props.whatever
    };
}

这是一个原型版本:

var r = new Requester(); // begins the process


  // Here's the implementation
function Requester() {
    // "this" is the common object
    this.someInitialData = {whatever:"data"};

    doSomethingAsync(this.firstCallback.bind(this));
}

Requester.prototype.onerror: function(err) {
     if (err.msg === "reallyBadError")
         return false; // false means stop
     else
         return true;  // true means we can continue
 };

Requester.prototype.firstCallback = function(err, info) {
       // if callback was passed an error, handle it
    if (err && this.onerror(err) === false)
        return;

    this.info = info; 
    doAnotherAsync(this.secondCallack.bind(this));
};


Requester.prototype.secondCallback = function(err, foo) {
       // if callback was passed an error, handle it
    if (err && this.onerror(err) === false)
        return;

    this.foo = foo;
    doOneMoreAsync(this.finalCallack.bind(this));
};


Requester.prototype.finalCallback = function(err, bar) {
       // if callback was passed an error, handle it
    if (err && this.onerror(err) === false)
        return;

    // The final code    
};