JavaScript或jQuery中的关键部分 [英] Critical Section in JavaScript or jQuery

查看:63
本文介绍了JavaScript或jQuery中的关键部分的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个网页,其中异步触发某个Ajax事件。这个Ajax部分可以被调用一次或多次。我无法控制触发此事件的次数,也无法控制时间。

I have a webpage, in which a certain Ajax event is triggered asynchronously. This Ajax section could be called once or more than once. I do not have control over the number of times this event is triggered, nor the timing.

此外,Ajax部分中的某些代码应该作为临界区,意思是,当它运行时,该代码的其他副本不应该运行。

Also, there is a certain code in that Ajax section that should run as a critical section, meaning, when it is running, no other copy of that code should be running.

这是一个伪代码:


  1. 运行JavaScript或jQuery代码

  2. 输入Ajax的关键部分(当某个进程正在等待响应回调时,则不要再次进入此部分,直到此过程完成)

  3. 运行更多JavaScript或jQuery代码

我的问题是,如何按上述方式运行第2步?如何使用JavaScript或jQuery创建/保证互斥部分。

My question is, how can I run step 2 the way described above? How do I create/guarantee a mutual exclusion section using JavaScript or jQuery.

我理解理论(信号量,锁,等等),但我不能使用JavaScript或jQuery实现解决方案。

I understand the theory (semaphores, locks, ...etc.), but I could not implement a solution using either JavaScript or jQuery.

编辑

如果你建议进入临界区的布尔变量,这不起作用,下面的行将解释原因。

In case you are suggesting a Boolean variable to get into the critical section, this would not work, and the lines below will explain why.

关键部分的代码如下(使用布尔变量建议):

the code for a critical section would be as follows (using the Boolean variable suggestions):

load_data_from_database = function () {

    // Load data from the database. Only load data if we almost reach the end of the page
    if ( jQuery(window).scrollTop() >= jQuery(document).height() - jQuery(window).height() - 300) {

        // Enter critical section
        if (window.lock == false) {

            // Lock the critical section
            window.lock = true;

            // Make Ajax call
            jQuery.ajax({
                type:        'post',
                dataType:    'json',
                url:         path/to/script.php,
                data:        {
                    action:  'action_load_posts'
                },
                success:     function (response) {
                    // First do some stuff when we get a response

                    // Then we unlock the critical section
                    window.lock = false;
                }

            });


            // End of critical section
        }
    }
};

// The jQuery ready function (start code here)
jQuery(document).ready(function() {
    var window.lock = false; // This is a global lock variable

    jQuery(window).on('scroll', load_data_from_database);
});

现在这是使用布尔变量建议的锁定部分的代码。这不会如下所示:

Now this is the code for the lock section as suggested using a Boolean variable. This would not work as suggested below:


  1. 用户向下滚动,(并基于关联 jQuery(window).on('scroll',load_data_from_database); 触发多个滚动事件。

假设两个滚动事件几乎在同一时刻被触发

Assume two scroll events are triggered right at almost the same moment

两者都调用 load_data_from_database 函数

第一个事件检查 window.lock false (答案是真的,所以如果声明是正确的)

The first event checks if window.lock is false (answer is true, so if statement is correct)

第二个事件检查 window.lock 是否 false (答案是真的,所以如果陈述是正确的)

The second event checks if window.lock is false (answer is true, so if statement is correct)

第一个事件进入if语句

The first event enters the if statement

第二个事件进入if语句

The second event enters the if statement

第一个语句设置 window.lock true

第二个语句将 window.lock 设置为<强>吨rue

第一个语句运行Ajax关键部分

The first statement runs the Ajax critical section

第二个语句运行Ajax关键部分。

The second statement runs the Ajax critical section.

两者都完成代码

正如您所注意到的,两个事件几乎同时被触发,并且都进入临界区。因此无法锁定。

As you notice, both events are triggered almost at the same time, and both enter the critical section. So a lock is not possible.

推荐答案

我认为您在上面提供的最有用的信息是您对锁定的分析。

I think the most helpful information you provided above was your analysis of the locking.



  1. 用户向下滚动,(并基于关联 jQuery (窗口).on('scroll',load_data_from_database); 触发多个
    滚动事件。

  1. The user scrolls down, (and based on the association jQuery(window).on('scroll', load_data_from_database); more than one scroll event is triggered.

假设几乎在同一时刻触发两个滚动事件

Assume two scroll events are triggered right at almost the same moment

两者都调用 load_data_from_database 函数

第一个事件检查 window.lock false (答案为真,所以如果陈述是正确的话)

The first event checks if window.lock is false (answer is true, so if statement is correct)

第二个事件检查 window.lock 是否 false (答案是真的,所以如果陈述是正确的)

The second event checks if window.lock is false (answer is true, so if statement is correct)


马上告诉我你已经遇到了一个共同的(而且非常直观)的误解。

Right away this tells me that you have come to a common (and quite intuitive) misunderstanding.

Javascript是异步的,但是异步代码与并发代码不同据我了解,异步是指一个函数的子程序不一定按照我们在同步代码中所期望的深度优先顺序进行探索。一些函数调用(你称之为ajax的函数)将被放入队列并稍后执行。这可能会导致一些令人困惑的代码,但没有什么比认为您的异步代码同时运行更令人困惑。 并发(如您所知)是来自不同函数的语句可以相互交错的时候。

Javascript is asynchronous, but asynchronous code is not the same thing as concurrent code. As far as I understand, "asynchronous" means that a function's subroutines aren't necessarily explored in depth-first order as we would expect in synchronous code. Some function calls (the ones you are calling "ajax") will be put in a queue and executed later. This can lead to some confusing code, but nothing is as confusing as thinking that your async code is running concurrently. "Concurrency" (as you know) is when statements from different functions can interleave with one another.

锁和信号量等解决方案不是考虑异步代码的正确方法。 承诺是正确的方法。这就是让网络上的编程变得有趣和酷炫的东西。

Solutions like locks and semaphores are not the right way to think about async code. Promises are the right way. This is the stuff that makes programming on the web fun and cool.

我不是承诺大师,但这里有一个工作小提琴(我认为)演示了修复。

I'm no promise guru, but here is a working fiddle that (I think) demonstrates a fix.

load_data_from_database = function () {

    // Load data from the database. Only load data if we almost reach the end of the page
    if ( jQuery(window).scrollTop() >= jQuery(document).height() - jQuery(window).height() - 300) {

        console.log(promise.state());
        if (promise.state() !== "pending") {
            promise = jQuery.ajax({
                type:        'post',
                url:         '/echo/json/',
                data: {
                    json: { name: "BOB" },
                    delay: Math.random() * 10
                },
                success:     function (response) {

                    console.log("DONE");
                }
            });
        }
    }
};

var promise = new $.Deferred().resolve();

// The jQuery ready function (start code here)
jQuery(document).ready(function() {

    jQuery(window).on('scroll', load_data_from_database);
});

我正在使用全局承诺来确保只调用一次事件处理程序的ajax部分。如果您在小提琴中向上和向下滚动,您将看到在处理ajax请求时,将不会发出新请求。 ajax请求完成后,可以再次发出新请求。运气好的话,这就是你要找的行为。

I'm using a global promise to ensure that the ajax part of your event handler is only called once. If you scroll up and down in the fiddle, you will see that while the ajax request is processing, new requests won't be made. Once the ajax request is finished, new requests can be made again. With any luck, this is the behaviour you were looking for.

然而,我的回答有一个非常重要的警告:jQuery的承诺实施是众所周知的。这不仅仅是人们所说的听起来很聪明的东西,它实际上非常重要。我建议使用不同的promise库并将其与jQuery混合使用。如果你刚刚开始了解承诺,这一点尤其重要。

However, there is a pretty important caveats to my answer: jQuery's implementation of promises is notoriously broken. This isn't just something that people say to sound smart, it is actually pretty important. I would suggest using a different promise library and mixing it with jQuery. This is especially important if you are just starting to learn about promises.

编辑:就个人而言,我最近在同一条船上像你一样差不多3个月前,我认为我使用的一些事件处理程序是交错的。当人们开始告诉我javascript是单线程时,我感到恍惚和不信。帮助我的是了解事件发生时会发生什么。

EDIT: On a personal note, I was recently in the same boat as you. As little as 3 months ago, I thought that some event handlers I was using were interleaving. I was stupefied and unbelieving when people started to tell me that javascript is single-threaded. What helped me is understanding what happens when an event is fired.

在同步编码中,我们习惯于帧的堆栈,每个帧代表一个函数的上下文。在javascript和其他异步编程环境中,堆栈由队列扩充。当您在代码中触发事件或使用类似 $ .ajax 调用的异步请求时,您将事件推送到此队列。该事件将在下次清除堆栈时处理。例如,如果你有这个代码:

In syncronous coding, we are used to the idea of a "stack" of "frames" each representing the context of a function. In javascript, and other asynchronous programming environments, the stack is augmented by a queue. When you trigger an event in your code, or use an asynchronous request like that $.ajax call, you push an event to this queue. The event will be handled the next time that the stack is clear. So for example, if you have this code:

function () {
    this.on("bob", function () { console.log("hello"); })

    this.do_some_work();
    this.trigger("bob");
    this.do_more_work();
}

两个函数 do_some_work do_more_work 将立即一个接一个地开火。然后该函数将结束,您排队的事件将启动一个新的函数调用(在堆栈上),并且hello将出现在控制台中。如果您在处理程序中触发事件,或者在子例程中触发事件,事情会变得更复杂。

The two functions do_some_work and do_more_work will fire one after the other, immediately. Then the function will end and the event you enqueued will start a new function call, (on the stack) and "hello" will appear in the console. Things get more complicated if you trigger an event in your handler, or if you trigger and event in a subroutine.

这一切都很好,但事情开始时当你想要处理异常时,真的很糟糕。当你进入异步土地的那一刻,你留下了一个功能应该返回或抛出的美丽誓言。如果您在事件处理程序中,并且抛出异常,它将被捕获到哪里?这个,

This is all well and good, but where things start to get really crappy is when you want to handle an exception. The moment you enter asynchronous land, you leave behind the beautiful oath of "a function shall return or throw". If you are in an event handler, and you throw an exception, where will it be caught? This,

function () {

    try {
        $.get("stuff", function (data) {
            // uh, now call that other API
            $.get("more-stuff", function (data) {
                // hope that worked...
            };
        });
    } catch (e) {
        console.log("pardon me?");
    }
}

现在不会救你。承诺允许你通过给你一个回归这个古老而强大的誓言将回调链接在一起并控制它们返回的位置和方式的方法。所以使用一个很好的promises API(而不是jQuery),你可以用一种方式链接这些回调,让你以你期望的方式冒泡,并控制执行的顺序。根据我的理解,这是承诺的美丽和魔力。

won't save you now. Promises allow you to take back this ancient and powerful oath by giving you a way to chain your callbacks together and control where and when they return. So with a nice promises API (not jQuery) you chain those callbacks in a way that lets you bubble exceptions in the way you expect, and to control the order of execution. This, in my understanding, is the beauty and magic of promises.

如果我完全离开,有人会阻止我。

Someone stop me if I'm totally off.

这篇关于JavaScript或jQuery中的关键部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆