Javascript 或 jQuery 中的线程安全队列

Posted

技术标签:

【中文标题】Javascript 或 jQuery 中的线程安全队列【英文标题】:Thread-safe queue in Javascript or jQuery 【发布时间】:2011-06-10 07:57:45 【问题描述】:

我有许多异步 AJAX 调用,其结果将得到处理。处理发生的顺序无关紧要,但结果需要一次处理一个。所以我想简单地做我的 AJAX 调用,他们都只是把他们的结果放在一个队列中。然后应该在单个线程上处理该队列。这样,结果会尽快一次处理一个。

最好的方法是什么?我正在使用 jQuery,很高兴能够利用它为此提供的任何功能。

【问题讨论】:

你可以使用 $.when(promiseArray).done(function (result1, result2, etc..) all calls complete, process all it now ); 【参考方案1】:

异步并不意味着“多线程”。在处理第一个单击处理程序之前,请考虑连续触发的许多单击事件。一次只能处理一个操作,其他操作将等待执行。

javascript 这样的事件驱动语言是在队列的基础上运行的。后台的 Javascript 基本上有一个巨大的队列,事件和异步响应被推送到其中。一旦完成特定的处理,队列中的下一个项目就会开始处理。

这些队列有时被称为“运行循环”。 Javascript 将无限循环,从队列中检索事件,对其进行处理,然后返回队列进行另一项工作。

可以使用Web Workers 在(较新)版本的 Javascript 中实现多线程,但这些都是明确的选择。如果您有兴趣,请查找它们。

那么要回答您的问题,只需将回调附加到您的异步请求,即使中途返回另一个响应,它也会完成处理。另一个响应将“等待”直到处理当前事件。

【讨论】:

我认为每个人都在过度复杂化这个问题,因为它使用了“线程”这个词。我相信 OP 只是意味着他需要在下一个回调开始之前完全完成每个回调。我假设因为涉及 jQuery,这是因为某种动画正在发生,它将使用计时器,因此出现多线程(两个回调似乎同时运行)。 @beeglebug - 我不相信你是对的。 OP 明确声明“处理发生的顺序无关紧要”。异步意味着多线程是一个常见的误解,我相信 OP 也有同样的印象。 @Josh Smeaton - 可能,但我们可以让 OP 自己回来并揭示一些信息。这一切都归结为“处理”是指原始数字运算还是更多基于 UI 的东西。并且涉及到 jQuery(并且从 OP 的问题历史来看)我认为它是 UI/动画。 我真的不相信这两种方式都重要。一旦第一个响应返回,它就可以将动画事件添加到队列中。第二个响应,并将其动画事件添加到队列中。然后第一个动画事件触发,然后是第二个。处理无关紧要。了解 Javascript 中基于事件的编程对 IMO 来说很重要。 @beeglebug:进一步阅读您的答案后,我明白您所说的重叠是什么意思。所以忽略我上面的cmets。尽管如此,OP 没有提到天气,或者他不在乎是否有任何动画并行运行。他只是担心是否需要使用互斥锁或信号量,并且可能无法在 javascript 中找到它们。【参考方案2】:

如果您唯一关心的是浏览器(因为您提到了 jQuery,我认为这是真的),您应该知道 Javascript is single-threaded in browsers。

【讨论】:

哇,我没有意识到这一点,看起来很奇怪......所以我可以发出 100 个 AJAX 请求,而且这些请求似乎是异步的并且在不同的线程上,并且会调用回调函数一次一个? @dorktitude - 实际上,由于 WebWorkers,JavaScript 现在是多线程的:developer.mozilla.org/En/Using_web_workers @jmort253 现在可以在某些浏览器中有意完成多线程的工作是正确的,但据我所知,这并不是偶然发生的(即在 OP 的问题中,不需要采取特殊的预防措施来使队列线程安全) jQuery 中的异步查询意味着您的代码在调用查询后不会暂停,但 XmlHttpRequest 将一个接一个地处理每个请求,检查***.com/questions/1060539/… 人们试图强制执行真正的并行化,这意味着默认情况下你的查询是排队的(但你可以尝试使用 jQuery.queue 如果你担心它不会总是这样)。 应该注意的是,即使使用 web worker 也不必担心代码并行运行,因为 web worker 不能与主线程或彼此共享变量。每个 Web Worker 本质上都是一个单线程事件循环,您可以通过类似于 ajax 调用的方式与它们进行通信。将它们视为服务器 - 在浏览器上运行。它们不是您的传统线程。【参考方案3】:

你可能想看看Event messaging between JavaScript objects.

我使用了一个类似于博客文章的实现,带有一个名为 ajaxMonitor 的 jQuery 插件。

一旦调用来自 AJAX 请求的任何回调,它的工作方式就会更新 html 表。回调异步发生。

AJAX 的本质意味着异步。因此,在您的 AJAX 请求的成功回调中处理您的 QUEUE,我相信会完成您所寻找的。​​strong>

【讨论】:

【参考方案4】:

最简单的方法是为回调实现您自己的队列系统(使用 push/pop 来模拟堆栈)。

当每个异步请求返回时,将数据添加到数组的末尾并触发某种queue.process() 命令,该命令将处理数组中的第一个元素。

最后,将if(alreadyRunning) return; 之类的内容添加到该函数的顶部以阻止它同时执行多个操作,这样就得到了单线程队列。

编辑:删除了代码,有些人挂断了它而不是原来的问题

【讨论】:

只有当this.handler(item) 将另一个工作项推入堆栈时,队列中才会出现多个项目。完全没有必要这样做,因为大多数异步调用都能够在完成时接受回调。 我认为这个想法是一些外部代码会触发 ajax 调用,并使用 queue.add 作为回调。这样,返回的数据将被添加到队列中,如果在处理第一个数据时返回了第二个数据,一旦第一个数据完成,它将被添加到要处理的队列中。 不可能。当第一个仍在处理时,不能执行另一条返回的数据。它将等到唯一的线程变得“空闲”才能完成工作。 queue.add 是多余的。只需将处理程序直接附加到每个异步请求即可。 有可能! :) 这完全取决于您所说的“已处理”是什么意思。如果涉及到动画(淡入某些文本,展开隐藏元素),并且两个回调彼此靠近,则动画很容易重叠。 @beeglebug:不可能。运行 ajax 回调时,任何动画代码都不会运行。同样,在动画补间函数运行时,任何 ajax 回调都不会运行。 setTimeout 和 setInterval 并不神奇。它们不会产生线程。他们只是排队事件。

以上是关于Javascript 或 jQuery 中的线程安全队列的主要内容,如果未能解决你的问题,请参考以下文章

Jquery——简介于安

jquery 或 vanilla javascript 自动加载(jquery 加载)页面中的所有链接内容

无法使用Javascript或JQuery修剪对象属性

表单标签中的按钮不会提交或响应 Javascript/Jquery

JavaScript 或 jQuery 中的 HTML 表单验证逻辑

如何处理 JavaScript 或 jQuery 中的 CORS 错误?