Javascript函数可以更有效地处理并发异步函数

Javascript function to handle concurrent async function more efficiently

本文关键字:函数 处理 并发 异步 有效地 Javascript      更新时间:2023-09-26

考虑以下内容:

  • 每秒最多可有100个并发请求的web应用程序
  • 当前,每个传入请求都会向端点发出http请求以获取一些数据(这可能需要5秒)
  • 我只想发出一次http请求,即我不想对同一个端点进行并发调用,因为它将返回相同的数据
  • 其想法是只有第一个请求才会进行http调用以获取数据
  • 当此调用是"正在进行"时,后续请求将不会进行相同的调用,而是"等待"第一个正在进行的请求完成。
  • 当对数据的初始http请求已响应时,它必须用数据响应所有调用。
  • 我正在使用Bluebird promise来执行http请求的异步函数。

我想创建/使用某种通用方法/类来包装业务逻辑promise方法。这个通用方法/调用将知道何时调用实际的业务逻辑函数,何时等待inflight完成,然后在有响应时解析所有等待的调用。

我希望已经有一个节点模块可以做到这一点,但我想不出这种类型的实用程序会被称为什么。

类似于lodash-through/debounce的东西,但不完全相同。

如果它不存在,我可以自己写,但很难想出一个合理的名字。

如有任何帮助,我们将不胜感激。

您可以实现PromiseCache,例如:

module.exports = function request(url) {
    if (caches[url]) return caches[url];
    var promise = req(url);
    return (caches[url] = promise);
};
var req = require('');
var caches = {};

编辑

让我来解释一下:

这里不是关于缓存响应,而是关于缓存承诺。Nodejs是单线程的,也就是说,即使所有东西都是异步的,也没有并发的函数调用,在某个时间点,只运行一段代码。这意味着,将有人首先调用url为y.com/foo的函数,缓存中不会有promise,因此它将触发GET请求并缓存并返回该promise。当有人立即用相同的url调用函数时,不会再触发请求,而是会返回该url的第一个promise,消费者可以订阅done/fail回调。当响应准备好并且promise实现,并且有人使用相同的url发出请求时,它将再次取回缓存的promise,该promise已经准备好了。

Promise缓存是防止重复异步任务的好方法。

一个web应用程序只能有6个并发请求,因为这是浏览器的硬限制。旧的IE只能做2。所以,无论你做什么,这都是一个严格的限制。

通常,您应该在服务器端解决多路复用问题。

现在,对于你的实际问题,你所要求的缓存与承诺非常简单。

function once(fn) {
    var val = null; // cache starts as empty
    return () => val || (val = fn()); // return value or set it.
}

var get = once(getData);
get();
get(); // same call, even though the value didn't change.

现在,您可能需要添加一个到期策略:

function once(fn, timeout) {
  var val = null, timer = null; // cache starts as empty
  return () => val || (val = fn().tap(invalidate)); // return value and invalidate
  function invalidate() { 
    clearTimeout(timer); // remove timer.
    timer = setTimeout(() => val = null, timeout);
  }
}
var get = once(getData, 10000); 

如果失败,您可能还想取消缓存结果:

function once(fn, timeout) {
  var val = null, timer = null; // cache starts as empty
  return () => val || 
   (val = fn().catch(e => value = null, Promise.reject(e)).tap(invalidate));
  function invalidate() { 
    clearTimeout(timer); // remove timer.
    timer = setTimeout(() => val = null, timeout);
  }
}

由于最初的功能是一行代码,因此没有辅助程序。

您可以使用promise来防止重复请求同时

在nodejs中编写示例,您也可以在浏览器中使用此模式

const rp = require('request-promise'), 
var wait = null; 
function getUser(req, rep, next){
  function userSuccess(){
    wait = null;
  };
  function userErr(){
    wait = null;
  };
  if (wait){
    console.log('a wait');
  }
  else{
    wait = rp.get({ url: config.API_FLIX + "/menu"});
  }
  wait.then(userSuccess).catch(userErr);
}