gpt4 book ai didi

javascript - JavaScript 或 jQuery 中的临界区

转载 作者:数据小太阳 更新时间:2023-10-29 04:12:45 26 4
gpt4 key购买 nike

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

此外,该 Ajax 部分中的特定代码应作为关键部分运行,这意味着,当它运行时,该代码的其他副本不应运行。

伪代码如下:

  1. 运行 JavaScript 或 jQuery 代码
  2. 进入Ajax临界区(当某个进程正在等待响应回调时,不要再次进入该段,直到该进程完成)
  3. 运行更多 JavaScript 或 jQuery 代码

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

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

编辑

如果您建议使用 bool 变量进入临界区,这是行不通的,下面几行将解释原因。

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

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);
});

现在这是使用 bool 变量建议的锁定部分的代码。这不会像下面建议的那样工作:

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

  2. 假设两个滚动事件几乎同时触发

  3. 都调用load_data_from_database函数

  4. 第一个事件检查 window.lock 是否为 false(答案为真,因此 if 语句正确)

  5. 第二个事件检查 window.lock 是否为 false(答案为真,因此 if 语句正确)

  6. 第一个事件进入if语句

  7. 第二个事件进入if语句

  8. 第一个语句将 window.lock 设置为 true

  9. 第二条语句将window.lock设置为true

  10. 第一个语句运行 Ajax 临界区

  11. 第二条语句运行 Ajax 临界区。

  12. 都完成代码

正如您所注意到的,这两个事件几乎同时被触发,并且都进入了临界区。所以锁是不可能的。

最佳答案

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

  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.

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

  3. Both call the load_data_from_database function

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

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

这立刻告诉我您遇到了一个常见的(并且非常直观的)误解。

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

像锁和信号量这样的解决方案并不是考虑异步代码的正确方式。 Promises是正确的方法。这就是让网络编程变得有趣和酷的东西。

我不是 promise 大师,但这里有一个 working fiddle这(我认为)证明了一个修复。

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);
});

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

但是,我的回答有一个非常重要的警告:众所周知,jQuery 的 promises 实现是错误的。这不仅仅是人们说的听起来很聪明,它实际上非常重要。我建议使用不同的 promise 库并将其与 jQuery 混合使用。如果您刚刚开始学习 Promise,这一点尤其重要。

编辑:就个人而言,我最近和你处在同一条船上。仅仅 3 个月前,我还认为我使用的一些事件处理程序是交错的。当人们开始告诉我 javascript 是单线程的时,我感到震惊和难以置信。对我有帮助的是了解触发事件时会发生什么。

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

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

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

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

一切都很好,但是当您想要处理异常时,事情开始变得非常糟糕。在您进入异步领域的那一刻,您就留下了“函数应返回或抛出”的美丽誓言。如果你在一个事件处理程序中,你抛出一个异常,它会在哪里被捕获?这,

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 允许您通过将回调链接在一起并控制它们返回的地点和时间来收回这个古老而强大的誓言。因此,使用一个不错的 promises API(而不是 jQuery),您可以将这些回调以一种允许您以您期望的方式冒泡异常并控制执行顺序的方式链接起来。在我看来,这就是 promise 的美丽和魔力。

如果我完全不在,有人会阻止我。

关于javascript - JavaScript 或 jQuery 中的临界区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22150960/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com