JavaScript 同步 promise 返回

标签 javascript node.js synchronization promise semaphore

我有一个 promise 对象的 JavaScript 方法。该对象应该第一次被获取,但此后,应该返回一个缓存的实例。为了模拟检索,我们将在此处延迟。

var Promise = require('bluebird');
var retrievedObject = null;
var retrievalCount = 0;

var retrieveObject = Promise.coroutine(
function *retrieveObject(){
  if (retrievedObject) {
    return retrievedObject;
  }

  yield Promise.delay(1000); // wait one second
  retrievedObject = ++retrievalCount;

  return retrievedObject;
});

在这种情况下,为了简单起见,我们只等待一秒钟,然后返回一个递增的计数。如果缓存工作正常,计数应该只递增一次,而之后的所有时间,它应该保持相同的值,即 1。这应该满足我们的需求,作为递增代码是否已被递增的测试机制是否达到。

现在,我还有一个应该测试对象检索的函数,定义如下:

var testRetrievals = Promise.coroutine(
function *testRetrievals() {
  var count = yield retrieveObject();
  console.log(count);
});

多次调用该函数时,(像这样):

testRetrievals();
testRetrievals();
testRetrievals();
testRetrievals();
testRetrievals();

控制台日志应该是这样的:

1 1 1 1 1

然而,它真正读取的是

1 2 3 4 5

原因很明显。 retrieveObject 方法在第一次调用的 promise 产生之前被调用,因为所有调用启动所需的时间不到一秒钟。但是,我正在寻找一种以某种方式同步 retrieveObject 方法的方法,这样在第一次调用之后,它就不会进入检索过程(在我们的例子中是延迟),而是等待先调用完成。最符合 JavaScript/Node 惯用的方式是什么?我正在考虑引入类似信号量的结构,但我担心这会破坏 Node 的非等待行为。

最佳答案

I'm thinking of introducing semaphore-like structures

是的,你可以做到。我们需要做的主要事情是在调用方法时立即在我们的缓存中创建插槽,而不是在等待检索之后。

因此,在要存储的结果值旁边,我们需要一个pending flag来跟踪我们是否已经开始检索,以及一种通知等待更改的监听器的方法还没有解决的旗帜……
听起来很熟悉?是的,这是一个 promise ,它已经内置了这些信号量。

您只需将 promise 本身存储在缓存中:

var Promise = require('bluebird');
var retrievedPromise = null;
var retrievalCount = 0;

var retrieveObject = Promise.coroutine(function* retrieveObject() {
    if (retrievedPromise) {
        return yield retrievedPromise;
    }

    retrievedPromise = Promise.delay(++retrievalCount, 1000); // wait one second
    var retrievedObject = yield retrievedPromise;
    return retrievedObject;
});

事实上,您甚至不需要带有 yield 的协程:

…
var retrievedPromise = null;
function retrieveObject() {
    if (!retrievedPromise) 
        retrievedPromise = Promise.delay(++retrievalCount, 1000); // wait one second
    return retrievedPromise;
}

关于JavaScript 同步 promise 返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34210101/

相关文章:

php - 创建 php 文件以从某些本地服务器同步 mysql 数据

javascript - 为未包含在 div 中的文本设置样式

javascript - 有没有一种方法可以让我不使用数据库将上传的图像放入 html 页面?

node.js - NodeJS UNABLE_TO_VERIFY_LEAF_SIGNATURE

node.js - 在 Jenkins 中构建成功,但 AWS-Codebuild 出现插件错误

php - SQL Server 和 MySQL 之间的一种同步方式

javascript - Jquery UI Accordion 标题格式

javascript - 为什么将服务注入(inject)第二个 Controller 后,AngularJS 1.4.8 应用程序无法运行?

javascript - 如何从谷歌驱动器下载动态文件

api - 如何在没有 Firefox 的情况下访问 Firefox 同步书签