简体   繁体   English

在Node.js中传递变量?

[英]Variable passing in Node.js?

So, I'm trying to upgrade a chat system of mine to Node.js, and I haven't felt like such a noob in years! 因此,我正在尝试将我的聊天系统升级到Node.js,而且多年来我一直没有这种感觉!

In PHP, it's inefficient, but it definitely makes sense. 在PHP中,它效率低下,但绝对有道理。 Request starts up, it figures out the user information, room information, parses the message, and so on. 请求启动,它找出用户信息,房间信息,解析消息等。 Quite linear. 相当线性。 It calls several functions in various places, but each time, it only ever has to send that function the information it needs directly. 它在不同的地方调用了几个函数,但是每次都只需要直接向该函数发送所需的信息即可。 When that function is done, it returns, and then more work is done with something else using different information. 完成该功能后,它将返回,然后使用其他信息使用其他信息完成更多工作。 If there's an exception, it (usually) gets caught at a level where the user can be alerted. 如果存在异常,通常会在可以向用户发出警报的级别捕获异常。

As I understand it, Node.js absolutely does not work like this, instead being powered largely by callbacks - and I have a great many callbacks going on. 据我了解,Node.js绝对不能像这样工作,而是主要由回调提供支持-而且我正在进行很多回调。 It has to handle the initial connection, and then it has to check if the cookie file exists, and then it has to read the cookie file, and then it has to get some user info from the database, and then it has to get some other user info from the database, and then it has to get some more user info from the database, and then it has to add the user to the room, which - if there hasn't been anyone there in a while - has to get the room info from the database, and then finally respond to the request. 它必须处理初始连接,然后必须检查cookie文件是否存在,然后必须读取cookie文件,然后必须从数据库中获取一些用户信息,然后必须获取一些用户信息。数据库中的其他用户信息,然后它必须从数据库中获取更多用户信息,然后它必须将用户添加到房间中,如果一段时间没有人在场,则必须获取该用户来自数据库的房间信息,然后最终响应该请求。 And there will be at least two more levels for permission checking when I'm done. 完成后,至少还会有两个级别用于权限检查。

It's not much different from the PHP process, but in PHP it's multi-threaded through Apache, and so the request can sit there and wait for DB calls to return with no issue at all. 它与PHP流程没有太大不同,但是在PHP中它是通过Apache多线程的,因此请求可以放在那儿,等待DB调用完全返回。 User lookup, room subscriptions, permissions, all handled separately. 用户查找,会议室订阅,权限均单独处理。

In Node.js, the "when you're done with that" system isn't too difficult to wrap my head around (I've used client-side JS and jQuery plenty), but variable passing certainly is. 在Node.js的,系统的“当你做完这些”不太难绕到我的头(我使用的客户端JS和jQuery很多),但变量传递肯定是。 A big part of this is that try/catch is soundly defeated by callbacks. 其中很大的一部分是try / catch被回调打败了。 If the room data lookup query fails, that function needs to know what connection it should send the error back to (which could be two or three connections in the past by then), because it won't bubble up to a catch several levels back. 如果房间数据查找查询失败,则该函数需要知道应将错误发送回哪个连接(到那时可能是过去的两个或三个连接),因为它不会冒充回溯到多个级别。 So that connection object needs to be passed down through every single callback along the way. 因此,在此过程中,需要通过每个回调直接传递该连接对象。 Which is only mildly disgusting when handling exceptions, since those could probably happen anywhere, but when you get to the point where other variables have to be passed all the way down the line for one callback at the end, my fingers refuse to type any further until I look into what has gone so terribly awry! 在处理异常时,这只是轻微的令人作呕,因为异常可能在任何地方发生,但是当您到达必须将其他变量一直传递到最后一个回调的行的地步时,我的手指拒绝进一步键入直到我研究出如此严重的错误!

So I guess what I'm wondering, is if there's any "hack" I'm unfamiliar with that could allow variables to "jump" over non-nested callbacks. 因此,我想我想知道的是,是否存在我不熟悉的任何“ hack”,可能会导致变量“跳过”非嵌套的回调。 Having try/catch chain down indefinitely would be nifty, too. 无限期地尝试/捕获链也是很不错的。

EDIT: I'm having trouble trivializing hundreds of lines of code, so let's see if I can give some visual aid with the callback stack. 编辑:我在琐碎数百行代码时遇到了麻烦,所以让我们看看我是否可以通过回调堆栈提供一些视觉帮助。 Anything on the same line is a direct call, next line is a callback. 同一行上的任何内容都是直接调用,下一行是回调。

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

As you can see, the functions are mostly located in objects rather than just nested unnamed functions, because they will often need to be accessed from multiple locations in arbitrary order. 如您所见,这些函数大多位于对象中,而不仅仅是嵌套的未命名函数,因为它们通常需要以任意顺序从多个位置进行访问。 The problem is, some levels need the user object, and some don't. 问题是,某些级别需要用户对象,而有些则不需要。 If try/catch were working properly, only the first and last would need to be aware of the connection to send information back. 如果try / catch正常工作,则仅第一个和最后一个需要知道连接才能将信息发送回去。

What I need is a way to give these different functions different information, without having to flood every function before it with things they don't need. 我需要的是一种为这些不同功能提供不同信息的方法,而不必在每个功能之前都添加不需要的功能。 That is undesirable practice. 是不受欢迎的做法。 I also need various user object functions to fail in very different ways - ways that object should not need to concern its self with, as it is the responsibility of the calling function. 我还需要各种用户对象函数以非常不同的方式失败-该对象不需要关心自身的方式,因为这是调用函数的责任。

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
    };
}

Here's a prototypal version: 这是一个原型版本:

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    
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM