确保给定参数的每个任务仅在Node.JS中完成一次

时间:2016-07-13 10:16:18

标签: javascript node.js concurrency promise

我有一个Node.JS应用程序,它截取了一个URL的截图。由于多个用户可能同时请求相同的网址,因此我想确保在任何时候我只抓取一次网址的屏幕截图。

我已经通过以下方式实现了它:

var inProgressUrls = {};

function grabScreenshot(url) {
  var inProgress = inProgressUrls[url];
  if (inProgress) {
    return inProgress;
  }

  var promise = new Promise(function(fulfill, reject) {
    ... grab screenshot ...

    // Once done, remove the Promise from the map.
    delete inProgressUrls[url];
  });

  inProgressUrls[url] = promise;

  return promise;
}

我想知道的是,我是否缺少一些并发问题或更好的实现方法?

1 个答案:

答案 0 :(得分:0)

在我看来,您提供的代码可以帮助您完成工作。

下面我只是试图优化另一个角落案例:)

一旦调用resolve(fulfill),执行将进入事件循环,然后在下一个可用/可能的tick中调用promise的异步操作。让我们说在eventloop中有人用同一个url调用grabScreenshot,我试着在下面进行优化。

delete将在异步操作中发生,除了来自对象的delete url之外什么都不做。

var inProgressUrls = {};

function grabScreenshot(url) {
    var inProgress = inProgressUrls[url];
    if (inProgress) {
        return inProgress;
    }

    var promise = new Promise(function(fulfill, reject) {
        asyncScreenGrab(url,(error, data) => {
            if (!error) {
                fulfill(data);
            } else {
                reject(error);
            }

            //NOT CALLING DELETE HERE TO OPTIMISE LITTLE MORE!
            //IF GRAB IS CALLED WITH SAME URL WHILE AFTER THE RESOLVE OR REJECT, BUT WE ARE AT EVENT LOOP
            //AND ASYN ACTIONS ARE NOT STARTED EXECUTING
        });
    });

    inProgressUrls[url] = promise;

    //DELETE THE STORED PROMISE EITHER FOR RESOLVE OR FOR REJECT
    promise.then(() => delete inProgressUrls[url]).catch(() => delete inProgressUrls[url])

    return promise;
}