有没有原子级的JavaScript操作来处理Ajax的异步特性?

17

我正在从服务器动态加载代码(函数),并将其作为javascript代码执行,然后将其存储在数组中以便执行。所有这些代码片段必须精确地执行一次。伪代码如下:

function fetch(foo){
    if (foo in fooArray){
          //Do Nothing
    else{
          //Fetch foo via Ajax and execute foo()
    }
}

问题实际上更加复杂,但基本上如果我发出以下命令

fetch('someFunctionName');
fetch('someFunctionName');
fetch('someFunctionName');
fetch('someFunctionName');

这四个代码片段都会执行 if (foo in fooArray) 并且假设它不在数组中,然后继续获取并执行代码。我记得以前学过信号量和互斥量,JavaScript 中是否也有这样的东西。


1
显然这是可能的,因为jQuery可以做到这一点:https://dev59.com/6Gw05IYBdhLWcg3wnjHC - Mchl
我已经写了一篇博客为什么JavaScript中没有并发控制工具 - Uzair Farooq
1
链接已经失效,正确的链接应该是:http://blog.uzairfarooq.com/why-no-concurrency-control-tool-in-javascript。 - pixel 67
2个回答

37

JavaScript是一种很好的语言,非常适合使用异步回调函数、超时、间隔和用户事件,但没有任何并发问题。这是因为JavaScript本质上是单线程的 - 给定的代码块总是以原子方式执行,从不被运行JavaScript的另一个线程中断。

您的fetch()函数将始终在没有任何干扰的情况下执行。如果它作为AJAX回调的一部分执行,并且如果有多个待处理的AJAX回调,则它们将排队等待执行。

另一个例子:如果您为输入元素分配了事件处理程序,并且您同时多次触发该事件,事件处理程序不会并发执行。而是将它们排队并依次执行。这也适用于由setTimeout()/setInterval()触发的多个事件。

附注:这是为什么node.js如此强大的原因之一:它仅使用单个线程,永远不会在I/O上阻塞,而是在数据准备好/事件发生时使用回调。


6
严格来说,Web Workers 允许 JS 并发执行,但由于 Web Workers 和“普通”的 JS 之间的唯一交互是通过消息进行的,因此您仍然没有任何并发问题。 - Joachim Sauer
Tomasz,我明白你的意思了,谢谢。 - puk
@Tomasz,如果AJAX调用时间太长,也许我们不想有太多(取决于浏览器的2或6个)挂起的请求,因此我在下面提供了一个缓存解决方案..你觉得呢? - Ustaman Sangat
异步,非并发。 - Ziggy
JavaScript是并发的,但不是并行的。https://blog.golang.org/concurrency-is-not-parallelism - kristianp

0
JavaScript 基本上是单线程的,所以你不需要互斥锁。你的 fetch 可以设置标志,使得后续的 fetch 调用可以避免进行 ajax 调用,例如:
var beingFetched = {};//map onflight -> callbacks
function fetch(foo){
  if (foo in fooArray){
      //Do Nothing
  } else {
      if (beingFetched.foo) { //note empty array is truthy
          //register a callback
          var callback = function(r){
             //anything you need to do wit the return object r
             //maybe even eval it.
          };
          //the callback would more likely be an argument to fetch itself
          //or you could use a promise API instead so that you can at your will
          //register multiple callbacks - for error, for success etc.
          beingFetched.foo.push(callback); 
      } else {
          beingFetched.foo = [];//truthy
          //Fetch foo via Ajax and execute
          $.ajax("getFoo/"+foo).done(function() {
              _.each(beingFetched.foo, function(cb){
                  cb.apply(cb,arguments);
              });
              delete beingFetched.foo;
          });
      }
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接