Javascript 异步性是a)函数还是b)代码行的常量?

Javascript 异步性是a)函数还是b)代码行的常量?,javascript,arrays,node.js,asynchronous,Javascript,Arrays,Node.js,Asynchronous,如果异步是以“函数”为基础的,那么这段代码是100%防弹的。一个房间里不可能有两个以上的用户 如果异步性以“每行”为基础,则此代码可能会失败。为什么?因为如果三个用户同时进入房间,在10毫秒的间隔内可能会发生以下情况: 1ms:房间是空的。让用户A进入,推送到数组 4ms:房间有一个用户 5ms:用户B请求加入 6ms:用户C请求加入 7ms:检查数组的长度1 8ms:检查数组的长度1 9ms:将用户B推送到阵列,因为房间长度为1 10ms:将用户C推送到阵列,因为房间长度为1 15ms:现在房

如果异步是以“函数”为基础的,那么这段代码是100%防弹的。一个房间里不可能有两个以上的用户

如果异步性以“每行”为基础,则此代码可能会失败。为什么?因为如果三个用户同时进入房间,在10毫秒的间隔内可能会发生以下情况:

1ms:房间是空的。让用户A进入,推送到数组

4ms:房间有一个用户

5ms:用户B请求加入

6ms:用户C请求加入

7ms:检查数组的长度1

8ms:检查数组的长度1

9ms:将用户B推送到阵列,因为房间长度为1

10ms:将用户C推送到阵列,因为房间长度为1

15ms:现在房间有3个用户,最多两个

如果异步是以“每行”为基础的,那么如何避免在实际场景中发生前面的示例?很抱歉,如果我没有按事物的名称命名,但我想不出更好的方法来解释这一点

这些评论暗示,但没有明确地说,同一功能的“实例”永远不会相互重叠。指向同一对象/数组的不同函数如何

join(user) {
    if(this.room.length === 2) throw new Error('The room is full');
    this.room.push(user);
};

Javascript是同步的,每个事件的作用域大于一个函数或一行。这不包括您自己启动的任何异步操作。他们将在一段时间后开始并完成自己的活动。请参见下文中的活动讨论。类似于您所展示的事件的同步代码将在运行下一个事件之前完全运行到完成

nodejs中的javascript以单线程和事件驱动的方式运行。这意味着一段Javascript开始执行,它将在处理任何其他事件之前完成。因此,函数在任何人可以再次调用它之前运行并完成,前提是它不调用自身,因此您没有多线程环境中可能存在的典型竞争条件类型

如果异步是以“函数”为基础的,那么这段代码是100%防弹的。一个房间里不可能有两个以上的用户

node.js中的Javascript是单线程的,在运行下一个事件之前,它将运行整个事件处理程序以完成该事件处理程序中的所有功能

如果异步性以“每行”为基础,则此代码可能会失败。为什么?因为如果三个用户同时进入房间,在10毫秒的间隔内可能会发生以下情况:

Javascript的单线程性不是每行或每函数。这是每项活动的费用。因此,在本例中,您可能正在处理传入的socket.io消息。这意味着传入消息事件处理程序中的所有代码将在处理任何其他传入消息之前运行。只有当您的事件处理程序通过从其事件处理程序函数返回控制返回到系统时,NodeJ才会获取事件队列中的下一个事件并调用其事件处理程序

那么,假设三个用户都要求在大约相同的时间加入同一个房间,并检查该场景以进一步解释其工作原理

所有三位客户都要求大约在同一时间加入同一房间。 其中一个请求的到达时间比另一个传入数据包的到达时间稍微早一些,这些数据包在网络电缆上和传入TCP堆栈中被序列化,因此其中一个首先到达。 该数据包由本地TCP堆栈处理,然后nodejs中的侦听套接字收到警报,这将是本机代码,并在与JS引擎不同的线程中运行。 nodejs平台代码获取此套接字通知,并将事件插入nodejs事件队列,以提醒正在侦听该传入消息的nodejs代码。 如果nodejs Javascript引擎目前没有执行任何操作,那么它会立即触发该事件处理程序,并开始运行与该事件处理程序关联的代码。 如果nodejs Javascipt引擎此时正在执行某些操作,那么事件将位于事件队列中,直到JS引擎完成当前正在执行的操作,然后获取事件队列中的下一个事件。 现在,另外两个加入同一房间的请求到达TCP堆栈。 nodejs中为传入的TCP数据包提供服务的本机代码,可以看到这两个请求中的每一个都到达了。它们被插入到nodejs事件队列中,就像第一个一样。因为JS解释器正忙于处理第一条到达的消息,所以现在这些消息只是在事件队列中。 当第一条消息完成处理后,nodejs解释器从事件队列中获取下一个事件,第二条到达的消息现在将被处理。它的事件处理程序将被调用,并将在处理第三个事件之前运行到完成。 希望通过对事情处理过程的描述,您可以看到您对房间长度的检查没有任何可能的比赛条件。将用户添加到文件室是单线程的,因此它将启动,prog 在处理任何其他加入房间的请求之前,请重新注册并完成。这种单线程的特性虽然有时是一种限制性的特性,但却极大地简化了nodejs编程,因为它消除了多线程编程中可能出现的争用情况的许多原因

让我们看一下您的顺序以及我对每个步骤的评论:

1ms:房间是空的。让用户A进入,推送到数组

4ms:房间有一个用户

5ms:用户B请求加入

如果第一个请求尚未完成处理,则此请求将放入事件队列中,直到第一个请求完成。如果第一个请求完成,则此请求将开始处理

6ms:用户C请求加入

假设第二个请求的处理时间超过1ms,因此尚未完成,则此请求将进入事件队列,并且在前两个请求都完成之前不会被处理

7ms:检查数组的长度1

我不明白这一步是什么意思。如果这是处理第二个请求的一部分,则第二个和第三个请求仍在事件队列中,并且在第一个请求完成之前无法运行

8ms:检查数组的长度1

与前面的评论相同

9ms:将用户B推送到阵列,因为房间长度为1

10ms:将用户C推送到阵列,因为房间长度为1

15ms:现在房间有3个用户,最多两个


这是有缺陷的逻辑。由于事件队列和nodejs Javascript的单线程特性,在完成userA请求之前,userB和userC请求不会运行。因此,当任何请求运行时,房间长度总是准确的。像这样的多个请求不会同时运行。

因为您提到了node.js,它使用了单线程模型,这意味着您的函数将在再次调用同一个函数之前全部执行,前提是this.room.push不会以某种方式被重写以对join进行递归调用。一般来说,JavaScript不像其他语言那样需要锁/semapohres/etc来避免您所描述的情况,它没有很多并发性挑战。相反,JavaScript环境通常是事件驱动和单线程的。这有帮助吗?这对当前调用堆栈是有保证的。@needitohelp-这解释了吗?这回答了你的问题吗?老实说,没有。这么多的段落中有我没有要求的信息,这些信息可能会让其他人感到困惑,而不是把事情弄清楚。我昨天又补充了一个问题:指向同一对象/数组的不同函数如何?根据您的回答,如果它们是不同事件的一部分,它们可能会相互碰撞,对吗?@needitohelp-事件一次运行一个。再简单不过了。没有两个函数可以同时运行。Lol,它们称nodejs为“非阻塞”。非阻塞我的屁股。现在我明白了,谢谢你,先生。@needitohelp-nodejs使用非阻塞I/O。所有网络都是非阻塞的。大多数文件访问都是非阻塞的。但是,它是单线程的,所以它仍然是一次一个事件。它实际上扩展得非常非常好——在许多情况下比多线程I/O更好。而且,与Java等语言中的多线程I/O相比,它需要担心的并发性问题要少得多。
join(user) {
    if(GLOBAL.room1.length === 2) throw new Error('The room is full');
    GLOBAL.room1.push(user);
};

join2(user) {
    if(GLOBAL.room1.length === 2) throw new Error('The room is full');
    GLOBAL.room1.push(user);
};