Javascript Nodejs异步循环正在阻止React UI呈现

Javascript Nodejs异步循环正在阻止React UI呈现,javascript,node.js,reactjs,asynchronous,electron,Javascript,Node.js,Reactjs,Asynchronous,Electron,我有一个电子应用程序,需要通过UDP发送大量数据。这个过程是通过点击我的React UI中的一个按钮开始的,这个例子简化了我的问题。我的反应按钮: <button onClick={() => { foo(); }} > Run foo </button>; 虽然foo是异步的,但它仍然冻结了React UI 由于JavaScript是单线程的,所以只要调用无限while循环异步函数,它就会阻塞线程。您可以通过在while循环中引入wait来解

我有一个电子应用程序,需要通过UDP发送大量数据。这个过程是通过点击我的React UI中的一个按钮开始的,这个例子简化了我的问题。我的反应按钮:

<button
  onClick={() => {
    foo();
  }}
>
  Run foo
</button>;

虽然foo是异步的,但它仍然冻结了React UI

由于JavaScript是单线程的,所以只要调用无限while循环异步函数,它就会阻塞线程。您可以通过在while循环中引入
wait
来解决这个问题,这将允许您的程序返回到执行代码的其他部分

export const foo = async () => {
  while (true) {
    await new Promise(resolve => {
      resolve();
    });
  }
};

async
函数在执行时仍然会阻塞主(也是唯一)线程<代码>异步函数通常会有所帮助,因为它们调用的库函数实际上释放了主线程

例如,如果您没有执行简单的无限循环,而是执行以下操作:

function timeout(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

function yieldThread() {
  return new Promise(resolve => resolve());
}

export const foo = async () => {
  while (true) {
    console.log("hello");
    await timeout(2000);
    //or
    await yieldThread();
  }
};
export const foo = async () => {
  while (true) {
    const packet = getPacket();
    await new Promise(resolve => {
        sendUdp(packet, resolve);
    });
  }
};
你的主线程不会被阻塞

当然,
timeout
或简单的
yield
通常不是处理这种情况的正确方法,但它应该举例说明典型的结构

假设您有一个函数
sendUdp(packet,callback)
,该函数的第一个参数是数据包 当完成发送后,您需要发送并作为第二个不带参数的回调, 你可以这样做:

function timeout(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

function yieldThread() {
  return new Promise(resolve => resolve());
}

export const foo = async () => {
  while (true) {
    console.log("hello");
    await timeout(2000);
    //or
    await yieldThread();
  }
};
export const foo = async () => {
  while (true) {
    const packet = getPacket();
    await new Promise(resolve => {
        sendUdp(packet, resolve);
    });
  }
};

JavaScript在单个线程中运行。即使函数是异步的,如果应用程序运行无限while循环,它仍然会阻止应用程序。异步函数只是一个返回承诺的函数。它没有说明您在函数中或承诺中所做的事情是异步的。您编写了一个spinloop,无论线程在哪里运行,它都会阻塞线程。
异步函数
(或通常的承诺)不会使事情在不同的线程中运行。要做到这一点,您需要使用一个worker。是的@Bergi,我一直在考虑使用一个worker,因为这将允许我创建一个新线程,这将是我在任何其他语言中的解决方案。虽然Nodejs的工人让我很困惑。。。不是说nodejs作为一个整体不会让我感到困惑,你能分享更多关于“我需要通过UDP发送大量数据”的细节(也许还有代码)吗?一般来说,解决方案不是在同步
while(true)
循环中这样做,而是成批地对它们进行批处理,以使它们之间存在延迟,和/或使用异步操作系统功能等待网络缓冲区实际发送数据包。使用
foo
的示例定义仍然会阻止UI。尝试您的示例,使用
yieldThread
,仍然会冻结UI。@asd12tgzxvbgt是否完全冻结?例如,如果您尝试使用超时示例,它是否有效?在这种情况下,很简单,您触发了很多请求,这导致主线程过载,您应该对请求进行速率限制。请注意,在节点中,API支持同时发送多个数据包YUP完全冻结。有趣的是,我创建了一个名为
foo
的函数,它记录控制台,然后调用
setTimeout(foo,0)。这在没有冻结UI的情况下工作了一段时间。后来,我将代码实现为
foo
,它再次冻结。为了找到问题,我删除了越来越多的代码,但当我回到使用
setTimeout(foo,0)
的示例时,它仍然冻结了!这不是很疯狂吗?@asd12tgzxvbgt如果没有手动尝试的代码,我猜您正在淹没事件循环;虽然您确实没有从技术上阻塞主线程,但您仍然将几乎所有的时间都花在
foo
函数上,UI冻结。你应该增加一些延迟;例如,在测试中,不是
setTimeout(foo,0)
而是
setTimeout(foo,delay)
其中
delay
有时至少大于0