简体   繁体   English

我想制作自己的事件循环侦听器,但它阻塞了调用堆栈如何像处理任何事件一样处理它

[英]i want to make my own event loop listener but it is blocking the call stack how to handel it like any event

i want my code to chick if a data is changed and then do some thing so i came up with this我希望我的代码检查数据是否发生变化然后做一些事情所以我想出了这个

 function autoRendring(list,unchangedlist){
    while(true){

        while(list==unchangedlist){
         //Busy waiting  
        }
          
        console.log("renderd !")
        render(list)
        unchangedlist=list
    }

how can i execute this fuchion with out blocing the main thread i have read about the event loops and how the browser handel them Separately from the main thead but i still dont know what to do我如何在不阻塞主线程的情况下执行此 fuchion 我已经阅读了有关事件循环以及浏览器如何将它们与主线程分开处理的信息,但我仍然不知道该怎么做

} }

it just block the main thread它只是阻塞主线程

i want to make some thing like this in c#我想在 c# 中做这样的事情

using System.Threading;


int x = 0;
int y = x;

Thread t = new Thread(() => render(ref x,ref y));
Thread t2 = new Thread(() => change(ref x,ref y));


static void render(ref int x,ref int y)
{
    while (true)
    {
      
        while (x == y)
        {
      

        }
        
        Console.WriteLine(" x has changed and renderd !");
        y=x;
    }
}
static void change(ref int x,ref int y)
{
    while (true)
    {


        Console.WriteLine("inter x ");
        Console.WriteLine("x is " + x + "  and y is " + y);
        x = int.Parse(Console.ReadLine());
    }
}

t2.Start();
t.Start();

There are actually multiple issues with the code:代码实际上存在多个问题:

You have two nested while loops, the outer one is an infinite loop, and as you already might have guessed this is blocking main thread since your code does never exit.您有两个嵌套的while循环,外部循环是一个无限循环,您可能已经猜到这是阻塞主线程,因为您的代码永远不会退出。 Thus no other code can be executed which could cause any change and even the UI freezes.因此,无法执行其他可能导致任何更改甚至 UI 冻结的代码。

Since no change can happen while executing the outer loop the condition in the inner loop will not change and so the inner loop is infinite too.由于在执行外循环时不会发生任何变化,因此内循环中的条件不会发生变化,因此内循环也是无限的。

For this to work you actually have to let your code execution end so the event loop can continue, changes can happen, and then your code has to be called again to evaluate the new state.为此,您实际上必须让您的代码执行结束,以便事件循环可以继续,可以发生更改,然后您的代码必须再次调用以评估新的 state。

Second, list (and unchangedList ) are function parameters and so scoped locally to the function .其次, list (和unchangedList )是 function 参数,因此在本地作用域为 function Because of this there is no way of changing their value from outside of the function and code changing them must reside within the function/same scope.因此,无法从 function 外部更改它们的值,并且更改它们的代码必须驻留在函数/相同的 scope 中。

To allow the event loop to continue you need to end your execution and queue the next execution of your code.要允许事件循环继续,您需要结束执行并将下一次代码执行排队。 You could use for example setInterval for this:您可以为此使用例如setInterval

let list;
let unchangedList;

// initialize `list` here

// some example on how `list` could be updated
button.addEventListener('click', () => {
  // update `list`
});

function autoUpdate() {
  if (list !== unchangedList) {
    render(list);
    unchangedList = list;
  }
}

setInterval(autoUpdate, 0);

Using an interval of 0ms means to execute the callback "immediately" - but still asynchronously, ie, only to put it in the queue and continue execution.使用 0ms 的间隔意味着“立即”执行回调——但仍然是异步的,即只将其放入队列并继续执行。 This allows the event loop to execute other queue callbacks if there are any.这允许事件循环执行其他队列回调(如果有的话)。

Instead of executing your callback all the time though, a less CPU-heavy approach would be using requestAnimationFrame .不过,与其一直执行回调,不如使用requestAnimationFrame来减少 CPU 负担。 This will queue your callback only evertime before a new frame is painted which is more efficient since with setInterval you could re-render multiple times before it is actually painted to the screen:这只会在绘制新帧之前对回调进行排队,这样效率更高,因为使用setInterval可以在实际绘制到屏幕之前多次重新渲染:

function autoUpdate() {
  if (list !== unchangedList) {
    render(list);
    unchangedList = list;
  }

  requestAnimationFrame(autoUpdate);
}
requestAnimationFrame(autoUpdate);

Even more efficient would be to call your code only if there actually is any change.更有效的方法是仅在实际发生任何更改时才调用您的代码。 Depending on the source of your change this could be done with appropriate event listeners like the change event of input elements or the click event for buttons and links:根据更改的来源,这可以通过适当的事件侦听器来完成,例如输入元素的change event或按钮和链接的click event

inputElement.addEventListener('change', () => render(inputElement.value));
buttonElement.addEventListener('click', () => {
  let list = getUpdatedList();
  render(list);
});

If you want to observe changes in your code's variables you maybe could use observables such as with RxJS .如果您想观察代码变量的变化,您可以使用RxJS等可观察对象。

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

相关问题 我如何为 forwach 循环中的按钮创建事件侦听器 - how do i make a event listener for a button that is in a forwach loop 如何在JavaScript中的事件监听器中使for循环工作 - how to make a for loop work in an event listener in javascript 如何让循环等待事件监听器? - How to make a loop wait for an event listener? 如何阻止内联onclick事件并稍后在自己的点击监听器中调用它? - How to block inline onclick event and call it later in own click listener? 如何将我自己的事件侦听器添加到我的自定义 React Native 组件中? - How can I add my own event listener to my custom React Native component? 在 Firebase 的实时数据库中,如何将自己的 arguments 传递给事件侦听器的回调? - In Firebase's Realtime Database, how can I pass my own arguments to an event listener's callback? 如何通过ExecuteScript添加我自己的侦听器来捕获“加载”事件? - How can I capture the “load” event by adding my own listener through ExecuteScript? 有没有办法让不同的事件监听器异步? - Is there any way to make different event listener asynchronous? 我的简单计算器无法正常工作。 我想在按钮单击事件上使用事件监听器 - My simple calculator is not working. I want to use event listener on button click event “调用堆栈”和“事件循环”如何交互或协同工作? - How "call stack" and "event loop" interact or work together?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM