Javascript 函数以更有效地处理并发异步函数
Javascript function to handle concurrent async function more efficiently
考虑以下几点:
- 每秒最多可以有 100 个并发请求的 Web 应用程序
- 当前每个传入请求都会向端点发出 http 请求以获取一些数据(最多可能需要 5 秒)
- 我只想发出一次 http 请求,即我不想对同一个端点进行并发调用,因为它会 return 相同的数据
- 想法是只有第一个请求会进行 http 调用以获取数据
- 虽然此调用是 'inflight',但后续请求不会进行相同的调用,而是 'wait' 以完成第一个飞行请求。
- 当对数据的初始 http 请求得到响应后,它必须响应所有使用数据的调用。
- 我正在使用 Bluebird 承诺用于执行 http 请求的异步函数。
我想要 create/use 某种通用的 method/class 来包装业务逻辑承诺方法。这个通用 method/call 将知道何时调用实际的业务逻辑函数,何时等待飞行中完成,然后在有响应时解决所有等待的调用。
我希望已经有一个节点模块可以做到这一点,但想不出这种类型的实用程序会被称为什么。
类似于 lodash throttle/debounce,但不完全相同。
如果它不存在我可以自己写,但是很难为它想出一个合理的名字。
如有任何帮助,我们将不胜感激。
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);
}
}
由于原始功能是一行代码,因此没有帮助程序。
您可以实现 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 请求并缓存 return承诺。当有人立即使用相同的 url 调用该函数时,不会触发更多请求,而是针对此 url 的第一个承诺将被 returned,消费者可以订阅 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);
}
考虑以下几点:
- 每秒最多可以有 100 个并发请求的 Web 应用程序
- 当前每个传入请求都会向端点发出 http 请求以获取一些数据(最多可能需要 5 秒)
- 我只想发出一次 http 请求,即我不想对同一个端点进行并发调用,因为它会 return 相同的数据
- 想法是只有第一个请求会进行 http 调用以获取数据
- 虽然此调用是 'inflight',但后续请求不会进行相同的调用,而是 'wait' 以完成第一个飞行请求。
- 当对数据的初始 http 请求得到响应后,它必须响应所有使用数据的调用。
- 我正在使用 Bluebird 承诺用于执行 http 请求的异步函数。
我想要 create/use 某种通用的 method/class 来包装业务逻辑承诺方法。这个通用 method/call 将知道何时调用实际的业务逻辑函数,何时等待飞行中完成,然后在有响应时解决所有等待的调用。
我希望已经有一个节点模块可以做到这一点,但想不出这种类型的实用程序会被称为什么。
类似于 lodash throttle/debounce,但不完全相同。
如果它不存在我可以自己写,但是很难为它想出一个合理的名字。
如有任何帮助,我们将不胜感激。
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);
}
}
由于原始功能是一行代码,因此没有帮助程序。
您可以实现 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 请求并缓存 return承诺。当有人立即使用相同的 url 调用该函数时,不会触发更多请求,而是针对此 url 的第一个承诺将被 returned,消费者可以订阅 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);
}