Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/432.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaScript双空检查和锁定_Javascript_Multithreading_Asynchronous_Locking - Fatal编程技术网

JavaScript双空检查和锁定

JavaScript双空检查和锁定,javascript,multithreading,asynchronous,locking,Javascript,Multithreading,Asynchronous,Locking,在具有线程和锁的语言中,通过检查变量的值很容易实现延迟加载,如果为null,则锁定下一段代码,再次检查值,然后加载资源并分配。这可以防止多次加载,并导致第一个线程之后的线程等待第一个线程完成所需的操作 Psuedo代码: if(myvar == null) { lock(obj) { if(myvar == null) { myvar = getData(); } } } return myvar; JavaScript在单个

在具有线程和锁的语言中,通过检查变量的值很容易实现延迟加载,如果为null,则锁定下一段代码,再次检查值,然后加载资源并分配。这可以防止多次加载,并导致第一个线程之后的线程等待第一个线程完成所需的操作

Psuedo代码:

  if(myvar == null) {
    lock(obj) {
      if(myvar == null) {
        myvar = getData();
      }
    }
  }
  return myvar;
JavaScript在单个线程中运行,但是,它仍然存在这种类型的问题,因为在一个调用等待阻塞资源时异步执行。在此Node.js示例中:

var allRecords;
module.exports = getAllRecords(callback) {
  if(allRecords) {
    return callback(null,allRecords);
  }

  db.getRecords({}, function(err, records) {
    if (err) {
      return callback(err);
    }

    // Use existing object if it has been
    // set by another async request to this
    // function
    allRecords = allRecords || partners;

    return callback(null, allRecords);
  });
}
第一次调用这个函数时,我会从一个小DB表中懒洋洋地加载所有记录,然后在后续调用时返回内存中的记录

问题:如果同时对该函数发出多个异步请求,那么该表将从数据库多次加载,这是不必要的

为了解决这个问题,我可以通过创建
var锁来模拟锁定机制变量,并在加载表时将其设置为true。然后,我会将其他异步调用放入
setTimeout()
循环,每隔(比如)1秒检查一次这个变量,直到数据可用,然后允许它们返回

该解决方案的问题是:

  • 它是脆弱的,如果第一个异步调用抛出并且没有解除锁定该怎么办
  • 在放弃之前,我们会循环多少次回到计时器中
  • 计时器应该设置多长时间?在某些环境中,1秒可能太长且效率低下

  • 在JavaScript中有解决这个问题的最佳实践吗?

    在第一次调用服务时,初始化一个数组。启动提取操作。创建承诺,并将其存储在数组中

    在后续调用中,如果数据存在,则返回一个已经实现的承诺。如果没有,则向数组中添加另一个承诺并返回该承诺


    当数据到达时,解析列表中的所有等待承诺对象。(一旦有了数据,你就可以扔掉这个列表。)

    我非常喜欢另一个答案中的promise解决方案——非常聪明,非常有趣。承诺不是主要的方法,因此您可能需要教育团队。不过我要去另一个方向

    你想要的是一个memoize函数——一个昂贵结果的内存键/值缓存。JavaScript好的部分最后有一个示例。Lodash有一个功能。这些假设是同步处理,所以不考虑您的场景——也就是说,在其中一个“线程”响应之前,它们会多次命中数据库

    异步库还有一个函数,它可以完全满足您的需要。在它的内部,它保留一个回调的队列数组,一旦得到答案,它就会缓存它并调用所有回调


    如果你对发明感兴趣,一定要用承诺。如果您想要一个即插即用的答案,请使用async#memoize。

    我会使用Promissions。在第一次调用此函数时,创建一个承诺并返回它。在随后的调用中,返回相同的承诺。当数据可用时解决它。@KevinB如果使用同一个promise实例,那么如何保持单独的回调?我猜promise库只会处理多个
    。然后()
    调用,然后做正确的事情?(我没有写过太多基于承诺的代码,至少没有写过太多超简单的东西。)这取决于实现(我也没有写过太多超简单的承诺),但是我非常确定。如果传入回调返回了任何东西,那么,then()将返回一个新的承诺,意思是多次使用。那么,除非您使用
    thepromise=thepromise.then(…