从内部回调函数中断父函数的执行

3

我正在为Unity3D创建一个nodejs服务器,使用socketio进行网络通信。我有一个用作匹配房间的函数,当玩家离开游戏时,我希望离开该函数。每次玩家创建新房间时,它应该进入该函数并重新开始。是否可能从子回调中中断父函数的执行?

exports.initGame = function (userdata) {
    //do prematch stuff with userdata and execute game logic on the callbaks

    socket.on("something", function (someNetdata)({
        // how do i stop parent function from here?
    });

    // more socket.on callbacks
}

编辑:忘记提到该函数正在被导出,不知道这会改变什么。

编辑2:鉴于jfriend00回答中讨论的建议,我将更详细地解释问题。

当前流程如下:

用户连接后,在 Io“connected”回调上定义一些函数。其中一个相关函数是startMatchMaker(Io, socket, data)。MatchMaker 为玩家创建房间(如果有可用房间,则加入其中),然后执行之前提到的gameInit(io, socket, room, data)

gameInit(...)函数使用房间作为关键字在全局数组中存储相关数据,例如:Players[room] = {/* player object */}。比赛是1对1的,因此当一名玩家放弃比赛时,我会从数组中删除与房间有关的条目:delete Players[room]。当玩家移动时,我会在全局数组中更新其对象中的玩家位置。这是通过在gameInit(...)中添加的回调函数完成的。

socket.on("move", function(data){
    //do movement logic and update player position, if it is valid. Omitting the rest of the code.
    Players[room].position = data.position;
});

现在假设有两个玩家,player1和player2正在room1中进行游戏。 Player2通过退出服务器来放弃游戏。 Player1仍然连接着,但必须离开当前的游戏。 所有变量都被删除了(如上所述),并且player1加入到room2的新游戏中。 当player1尝试移动时,将调用2个回调函数:第一个是在room =“room1”的first initGame中添加的,另一个是在执行第二次匹配时添加的:room =“room2”。 因为Players中没有具有key = room1的条目,所以会抛出异常。

解决方案是从前一次比赛中删除侦听器


栈溢出网站的设计初衷是,您不应该根据提供的答案进行渐进式发现而保留编辑问题。这意味着这是一个问答网站。您提出一个问题(您可以随时免费编辑以澄清问题),我们提供一个答案。您不应继续根据答案来改进问题。这不是一个讨论演变问题的主题讨论网站。您提出一个明确的问题,我们对该问题提供一个答案。您的问题所询问的内容不应更改。您可以澄清原始问题。 - jfriend00
如果在得到你原始问题的答案后,你有额外的问题涌现出来,那么你需要提出另一个独立的问题。 - jfriend00
此外,所有试图描述代码工作原理的文本都过于复杂,读者难以理解。只需展示实际代码(几行代码胜过一百行文本),然后在文本中描述您的代码目标(您想要实现什么)。 - jfriend00
2个回答

3
不行。您不能在子函数内部停止父函数的执行。您可以从子函数创建一个返回值,该返回值将指示父函数下一步该做什么,然后父函数可以根据返回值自行管理。
但是,在您的示例中,当调用socket.on('something, ...)时,initGame()早已执行完毕,因此您的整个要求都有些错误。事实上,直到initGame()完成执行之前,您的事件处理程序都无法被调用。JS是单线程的,因此必须先执行initGame()才能调用任何事件处理程序。
这里的事件序列如下:
1. initGame()运行。 2. 在运行期间,它设置了各种套接字消息的事件处理程序。这些是响应将来某个时间发生的事件的事件处理程序。 3. 然后,initGame()完成执行。 4. 然后,将来的某个时候,事件发生,其中一个事件处理程序运行。没有正在运行的initGame()甚至尝试中断执行。
如果您想获得更具体的帮助,您需要展示您实际在socket.on('something', ...)事件处理程序中尝试完成的任务。从内部事件处理程序“中断父函数的执行”的整个概念在Javascript中甚至没有意义。在Javascript中永远不可能出现这种情况。父函数已经在事件处理程序被调用之前执行完毕。您将不得不展示您尝试解决的实际问题,以便我们能够更详细地帮助您。
这里有一件事情似乎有点令人不安,那就是您引用了socket,但它并没有传递到initGame()中,但您正在导出initGame()并从某个其他上下文中调用它,因此不清楚socket变量如何可能是正确的变量。

1
@YuriAlmeida - 根据您展示的代码,我已经解释了您当前的情况(并在我的回答中添加了更多内容)。 您需要展示您实际尝试从事件处理程序中完成的任务,以便我们进一步帮助。 目前,您还没有描述真正的问题或以任何方式展示与实际问题相关的代码。 FYI,我认为我已经回答了您字面上提出的问题 - 不,您不能做您所要求的事情,因为该函数已经执行完毕。 - jfriend00
哦,好的,我明白了!让我更详细地解释一下正在发生的事情:玩家加入游戏并在initGame()中存储一个本地字符串room。添加了几个回调函数,这些回调函数使用局部变量room来访问全局数组上的索引。玩家离开游戏并加入另一个游戏。当他加入第二个游戏时,第一和第二个游戏的回调都被调用(并抛出错误,因为全局数组中没有更多具有该“room”名称的索引,因为当玩家离开游戏时,我已经删除了它们)。由于initGame()不再执行,那么我必须删除回调吗?如果是这样,该如何删除? - Yuri Almeida
1
@YuriAlmeida - 你在评论中描述的大部分内容听起来很复杂,而且似乎在你添加到问题中的代码中没有显示出来(我没有看到你谈论的回调函数)。如果您有要为给定用户存储的状态,请将自己的属性添加到该用户的socket对象中并将其存储在那里。这比您当前所做的更清晰,因为状态直接与它所属的socket相关联。您目前的方案实际上可以在您展示的代码中工作,因为它创建了一个持久的函数闭包,但不是最清晰的。 - jfriend00
好的,我认为那可能解决了问题!谢谢您先生!我不太习惯使用JavaScript,几乎所有我的编程经验都是用C#,所以我可以给任何对象添加属性的概念对我来说仍然有点奇怪^^我将编辑问题以更好地说明问题,并稍后尝试您的建议,如果成功了,我会告诉您的!;) - Yuri Almeida
1
@YuriAlmeida - 请看我在答案中添加的最后一段话。我担心 socket 变量可能会含有正确的值。 - jfriend00
抱歉,我的错。我将套接字作为参数传递。当我完成编辑问题时,它会更清晰。再次感谢您的时间,对于没有表达得更清楚,我很抱歉 :) - Yuri Almeida

1
你对“父”函数的概念有些混淆。在Javascript中没有“父”函数。
从你上面的例子可以看出,似乎在socket.on回调函数内部,你想要做一些会影响到该函数外部代码的事情。这里需要注意的重要一点是,这是一个回调函数 - 当socket接收到标识为something的消息时,它会调用回调函数。没有父/子关系涉及其中。
既然现在问题已经清晰了一些,让我们来考虑你的问题。你没有准确地解释你想要在回调之外做什么,因此不清楚你想要停止哪个函数。但这并不是非常重要 - 基本上,你想要做的是:当回调内部发生某些事情时,向回调之外的代码发送信号。有许多方法可以实现这一点,但一个基本技术是使用变量作为信号。 需要注意的是,node.js应用程序(通常)是事件驱动的。这意味着你的代码几乎总是在回调中响应正在发生的事情 - 没有等待发生事件的“主循环”。
因此,你的代码可能看起来像这样:
exports.initGame = function (userdata) {
    // do prematch stuff with userdata and execute game logic on
    // the callbacks

    // set up a variable to signal when something important happens
    var importantSignal = null;

    socket.on("something", function (someNetdata)({
        // something important has happened! let the rest of the application know about it
        importantSignal = someNetdata.message;

        // do some other stuff related to the callback
    });

    // another socket event
    socket.on("another", function (someNetData) {
        // has something important happened?
        if (importantSignal) {
            console.log("I see that 'something' has already happened!");
            console.log("Message = " + importantSignal);
        }
    });
}

这是回调之间简单的消息传递方式 - 注意第二个回调函数可以访问在第一个回调函数中设置的某些状态。但是第一个回调函数并没有以任何方式“控制”第二个回调函数,除非第二个回调函数基于第一个回调函数设置的状态做出决策。

谢谢您的解释!它让我对问题更加清楚了。 - Yuri Almeida

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接