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

Javascript函数更有效地处理并发异步函数,javascript,node.js,promise,bluebird,Javascript,Node.js,Promise,Bluebird,考虑以下几点: 每秒最多可有100个并发请求的web应用程序 每个传入请求当前向端点发出http请求以获取一些数据(可能需要5秒) 我只想发出一次http请求,也就是说,我不想同时调用同一个端点,因为它将返回相同的数据 想法是只有第一个请求才会进行http调用以获取数据 当此呼叫为“机上”时,后续请求将不会发出相同的呼叫,而是“等待”第一个机上请求完成。 当对数据的初始http请求已响应时,它必须使用数据响应所有调用。 我使用Bluebird Promissions来实现执行http请求的异步

考虑以下几点:

  • 每秒最多可有100个并发请求的web应用程序
  • 每个传入请求当前向端点发出http请求以获取一些数据(可能需要5秒)
  • 我只想发出一次http请求,也就是说,我不想同时调用同一个端点,因为它将返回相同的数据
  • 想法是只有第一个请求才会进行http调用以获取数据
  • 当此呼叫为“机上”时,后续请求将不会发出相同的呼叫,而是“等待”第一个机上请求完成。
  • 当对数据的初始http请求已响应时,它必须使用数据响应所有调用。
  • 我使用Bluebird Promissions来实现执行http请求的异步函数。
我想创建/使用某种通用方法/类来包装业务逻辑承诺方法。这个通用方法/调用将知道何时调用实际的业务逻辑函数,何时等待inflight完成,然后在有响应时解析所有等待的调用

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

类似于lodash节流/去盎司,但不完全相同

如果它不存在的话,我可以自己写,但我很难给它起个合理的名字


任何帮助都将不胜感激。

一个web应用程序只能有6个并发请求,因为这是硬浏览器限制。年纪大一点的人只能做两件事。因此,无论你做什么,这都是一个硬限制

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

现在,对于你的实际问题,你所要求的那种缓存对于承诺来说非常简单

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);
  }
}

由于原始功能是一行代码,因此没有帮助程序

一个web应用程序只能有6个并发请求,因为这是硬浏览器的限制。年纪大一点的人只能做两件事。因此,无论你做什么,这都是一个硬限制

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

现在,对于你的实际问题,你所要求的那种缓存对于承诺来说非常简单

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);
  }
}

由于原始功能是一行代码,因此没有帮助程序

您可以实现PromiseCaching,如:

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
调用函数,缓存中没有承诺,因此它将触发GET请求并缓存并返回该承诺。当有人立即使用相同的url调用函数时,不会触发更多请求,而是会返回此url的第一个承诺,并且消费者可以订阅
done/fail
回调。 当响应准备就绪且承诺得到履行,并且有人使用相同的url发出请求时,它将再次获得缓存的承诺,该承诺已经准备就绪


PromiseCaching是一种防止重复异步任务的好技术。

您可以实现PromiseCaching,如:

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
调用函数,缓存中没有承诺,因此它将触发GET请求并缓存并返回该承诺。当有人立即使用相同的url调用函数时,不会触发更多请求,而是会返回此url的第一个承诺,并且消费者可以订阅
done/fail
回调。 当响应准备就绪且承诺得到履行,并且有人使用相同的url发出请求时,它将再次获得缓存的承诺,该承诺已经准备就绪


Promise缓存是一种防止重复异步任务的好技术。

您可以使用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);
}

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

在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);
}

一个web应用程序只能有6个并发请求,因为这是硬浏览器的限制。旧IE只能做2个。一个web应用程序只能有6个并发请求,因为这是硬浏览器的限制。老IE只能做2.谢谢你的回复,但我可能对我的要求不是很清楚。我不是在寻找一个缓存解决方案,因为我已经缓存了响应。此外,此功能将在服务器端express应用程序上。考虑到缓存是空的或过期的,同时得到多个请求时,每个请求都会发出这个HTTP数据获取请求。这就是我试图避免的。只有第一个请求应该发出服务器端http数据GET请求,任何后续请求都不应该发出,而是“等待”第一个调用响应并重新使用它。我现在明白了。很有魅力-我基本上是用节点缓存来缓存的