【问题标题】:Javascript / JQuery handling of concurrent / asynchronous calls and data raceJavascript / JQuery 处理并发/异步调用和数据竞争
【发布时间】:2015-03-19 02:47:18
【问题描述】:

我目前正在尝试搜索一下 Javascript 如何处理并行或异步调用中的数据竞争。就我而言,在我的代码上进行异步处理的唯一方法是通过 AJAX 调用(如果我错了,请纠正!),但我想如果有其他方法,它也会被同样处理。

所以,作为一个例子,假设我有这个 AJAX 调用:

jQuery.ajax({
    //stuff
    success: function (data) {
        //do some fancy things with some DOM elements
    },
    //possibly more stuff
});

现在假设在该调用之外我正在运行其他事情,并且我最终使用我的成功回调在我的 AJAX 调用中处理的相同 DOM 元素执行某些操作(即在我的成功回调的同时将元素附加到表上尝试做同样的事情)。换句话说,我的配置以某种数据竞争告终。

Javascript 如何处理这个问题?当我的 AJAX 响应返回时,我当前正在运行的函数是否会被抢占以便执行 AJAX 调用?有什么东西可以保证我对 DOM 元素(或 javascript 变量)所做的事情是某种原子操作吗?所以如果我需要运行一个必须是原子的函数,我怎么能告诉解释器呢?

另外,是否对 Javascript 进行了一些屏蔽以防止死锁?比如说,如果我运行两个并行的 AJAX 调用并且每个调用都依赖于另一个的完成。

【问题讨论】:

标签: javascript jquery ajax multithreading asynchronous


【解决方案1】:

JavaScript 没有任何内置的保护措施。作为代码设计的一部分,您需要确保不会陷入不知道两个冲突函数中的哪一个将首先执行的情况。

这需要一些计划。您可以将一个 Ajax 调用放在另一个的回调中,或者使用事件和属性让其他函数知道某事是否已准备好进行处理,或者是否正在使用某个对象,因此不应触及它,等等。

【讨论】:

  • 嗯,这更好地回答了有关死锁的问题,但是如果 Javascript 似乎无法处理原子功能,我如何保证给定的 AJAX 调用不会使用属性触及我的对象?
  • 例如,这将是对对象的原子访问:var = 0;函数(obj){ a = 1; //访问obj a = 0;但这显然不是真的,因为对 a = 0 和 a = 1 的调用不是原子的。
  • 我不是 100% 确定我理解,但我认为你的问题的答案是 JavaScript 不是原子的。如果出现故障,则没有内置的方法来撤消部分调用。你必须使用 try catch 等来做到这一点。
  • Ops,我现在看到我搞砸了那个“原子访问函数”,因为它不检查“var”的状态。无论如何,其他人发布了一个链接,描述我的成功函数将被推送到事件队列中,因此它将在所有事件完成后运行。因此,我相信不可能有直接的数据竞赛。
  • 对。只要您在回调中,那就是唯一正在运行的 javascript。只有一个线程。当异步操作完成时,它会将回调添加到堆栈中。因此,如果您必须同时运行异步调用,您将不知道哪个回调将首先进入堆栈,但一次只会运行一个。
【解决方案2】:

所以对于第一个问题:

现在假设在该调用之外我正在运行其他事情,并且我最终使用我的成功回调在我的 AJAX 调用中处理的相同 DOM 元素执行某些操作(即在我的成功回调的同时将元素附加到表上尝试做同样的事情)。换句话说,我的配置以某种数据竞争告终。

为此,您可以简单地使用 jQuery 的 $.Deferred 功能。所有$.ajax 调用都返回一个延迟对象,jquery 调用的对象。也称为承诺对象。在其他语言中也称为未来。这允许您在请求完成后执行功能。

var req = $.get(url, successFunc);
req.done(someOtherFunc);

第二个问题:

假设我运行两个并行的 AJAX 调用并且每个调用都依赖于另一个的完成。

我认为您在这里寻找的是 $.when,它允许您仅在请求列表已解决时运行功能。

$.when([req1, req2, req3], function (res1, res2, res3) {});

【讨论】:

  • 我明白了,这很酷。但是,如果想要将东西附加到我的表中,我必须等待 AJAX 调用返回,以避免数据竞争?如果一种语言不能处理数据竞争而不使事情变得有点同步,我不明白为什么它会实现异步调用。事实上,我看不出做 req.done(someOtherFunc); 和简单地在我的成功回调中调用这个 someOtherFunc 之间的区别(当然,假设我的 AJAX 调用会成功)
  • 我想我会说: 1. 你的数据不应该存在于 DOM 中。你应该让你的数据(模型、存储、集合等)存在于 DOM 之外。 2. 你必须用任何语言来处理这个问题,无论是异步的(通过回调或承诺)还是通过线程。如果您想处理最新的数据,您需要:
  • 你还有什么要说的吗?因为你在最后一句话的末尾留下了一个“:”。
【解决方案3】:

浏览器 - 通过扩展,javascript(打开页面的位置)像单线程应用程序一样运行,一次只能做一件事。

这意味着在任何时候,浏览器都可以运行 javascript/监听事件或运行 reflow/repait 活动。

由于在任何时候都是这种情况,浏览器窗口只能执行 1 个函数,这意味着当 ajax 响应返回时,如果有一个函数正在运行,那么 ajax 回调将被添加到执行队列中,这将在当前函数完成时执行。

您也可以通过使用 setTimeout/setInterval 来实现异步操作,即使他们不保证回调将在 1000 毫秒或任何延迟后执行,他们只是说它将在最近的可用槽中执行

【讨论】:

  • 你确定ajax回调会在当前函数完成后运行吗?如果我进行嵌套函数调用,如下所示:a = function () { b = function() { c = function() { // ... }; c(); }; b(); }; a() 如果我现在正在运行函数 c(),在它结束后,回调会运行吗?还是会等到 a() 完成?我问你是因为我想知道 Javascript 是否会在我处于归因或总和之类的中间时抢占我的程序:x = 5 + y 如果不是这种情况,那么这个函数:跨度>
  • (超过最大字符数,继续...) var k = 0; function(obj) { if(k == 0) { k = 1; //access obj k = 0; return true; } else { return false; } }; 在某种意义上对我来说是原子的,因为它可以在 pthread.h (C) 上作为“trylock”工作。
  • @GuilhermeCaminha 一个函数的执行不会因为另一个函数的执行而被中断......假设第一个函数中没有异步调用
  • 是的,现在我明白了。别人发了这个链接:stackoverflow.com/questions/7575589/…你的第二个链接也很有意思。谢谢。
【解决方案4】:

尝试使用Promise.race()

var request = function(url) {
  return new Promise(function(resolve, reject) {
    var res = $.ajax({
        url: url,
        type: "GET"
    });
    res.then(function success(data) {
      resolve(data)
    }, function error(jqxhr, textStatus, errorThrown) {
      reject([textStatus, errorThrown])
    })
  })  
};

var promises = Promise.race([
  request("https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js")
, request("https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js")
]);

promises.then(function(response) {
 console.log(response)
}, function(error) {
  console.log(error)
});

【讨论】:

    猜你喜欢
    • 2020-07-12
    • 2010-11-27
    • 1970-01-01
    • 2014-02-23
    • 1970-01-01
    • 1970-01-01
    • 2012-01-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多