0

所以,我正在尝试将我的聊天系统升级到 Node.js,而且我已经好几年没觉得自己像个菜鸟了!

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

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

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

在 Node.js 中,“当你完成了那个”系统并不太难理解(我已经大量使用客户端 JS 和 jQuery),但变量传递肯定是。其中很大一部分是 try/catch 被回调彻底击败。如果房间数据查找查询失败,该函数需要知道它应该将错误发送回哪个连接(到那时可能是过去的两个或三个连接),因为它不会冒泡到多个级别返回. 因此,连接对象需要通过每个回调传递。这在处理异常时只是有点恶心,因为这些可能发生在任何地方,最后一个回调,我的手指拒绝再输入任何内容,直到我调查出了如此严重的错误!

所以我想我想知道的是,是否有任何我不熟悉的“黑客”可能允许变量“跳过”非嵌套回调。无限期地关闭 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 正常工作,则只有第一个和最后一个需要知道连接才能发回信息。

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

4

1 回答 1

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    
};
于 2012-12-12T01:30:42.347 回答