rag*_*hes 6 javascript caching node.js async-await jestjs
测试的目的是模拟获取不同数据源的并行请求。我为每个请求引入了人为延迟,一段时间后返回一个带有标识数字的简单字符串,以查看数据是否已从缓存中加载(500 毫秒内的请求)。因此,对于 500 毫秒内加载的数据,输出应为“A1B1”,否则,500 毫秒后应为“A2B2”,依此类推。
// index.test.js
const { wait } = require('./util/wait.js');
const { requestAandB, requestBandC } = require('./index.js');
test('Test cache timings ', () => Promise.all([
// send two requests in parallel after 0 ms (immediately)
wait(0).then(() => Promise.all([
expect(requestAandB()).resolves.toEqual('A1B1'),
expect(requestBandC()).resolves.toEqual('B1C1'),
])),
// send two requests in parallel after 480 ms
wait(480).then(() => Promise.all([
expect(requestAandB()).resolves.toEqual('A1B1'),
expect(requestBandC()).resolves.toEqual('B1C1'),
])),
// send two requests in parallel after 520 ms
wait(520).then(() => Promise.all([
expect(requestAandB()).resolves.toEqual('A2B2'),
expect(requestBandC()).resolves.toEqual('B2C2'),
])),
]));
Run Code Online (Sandbox Code Playgroud)
这就是我模拟数据加载的方式
// get-data.js
async function mockLoading(str) {
// introduce some latency
const waitDuration = Math.round(Math.random() * (WAIT_MAX - WAIT_MIN)) + WAIT_MIN;
await wait(waitDuration);
// create or increase counter every time the function is being called
counters[str] = counters[str] === undefined ? 1 : counters[str] + 1;
return str + counters[str];
}
module.exports = {
loadDataA: async () => mockLoading('A'),
loadDataB: async () => mockLoading('B'),
loadDataC: async () => mockLoading('C'),
}
Run Code Online (Sandbox Code Playgroud)
最后,在测试文件中导入的方法requestAandB和实现requestBandC:
const { loadDataA, loadDataB, loadDataC } = require('./model/get-data.js');
const all = Promise.all([loadDataA(), loadDataB(), loadDataC()])
function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms))
}
async function requestAandB() {
const temp = await all
await delay(Math.random() * 510)
return temp.filter((_, i) => i < 2).join("")
}
async function requestBandC() {
const temp = await all
await delay(Math.random() * 510)
return temp.filter((_, i) => i > 0).join("")
}
module.exports = { requestAandB, requestBandC }
Run Code Online (Sandbox Code Playgroud)
对数据“A1B1”、“B1C1”的测试很好,但由于延迟(在mockLoading函数中)始终高于 500 毫秒阈值,因此我无法获得此后返回的数据的正确结果。实际上,“A2B2”和“B2C2”总是失败。
有谁知道我在这里错过了什么?
这确实是一个棘手的问题,但我设法通过执行以下操作来解决它:
移动Promise.all里面各自的功能;这是因为 loadData 函数的承诺仅在模块加载时调用一次(感谢 @Teneff 和 @Observer 的提示)
实现缓存函数来缓存预期的承诺(不是预期的结果...),一旦满足某些条件就返回 loadData (缓存)。
mockLoading我们根本不需要改变这个功能。OP 需要实现客户端代码,然后调用外部 API 来模拟n个异步请求之间的高方差。换句话说,我们必须消除(或最小化)并行异步请求的数据冲突风险,以及如何在 Jest 中测试一些模拟案例。
一些代码使整个过程更加清晰:
const { loadDataA, loadDataB, loadDataC } = require('./model/get-data.js');
// we tackle this problem using memoization
// when `useCache` is called, we cache the loadData function name
// we then assign 1. a timestamp property to it and 2. a pointer to the promise itself
const CACHE_DURATION = 500;
const cache = {};
function useCache(fn) {
const cached = cache[fn.name];
const now = Date.now();
if (!cached || cached.ts < now - CACHE_DURATION) {
cache[fn.name] = { ts: now, promise: fn() }
}
return cache[fn.name].promise;
}
async function requestAandB() {
const [a, b] = await Promise.all([ loadDataA, loadDataB ].map(useCache));
return a + b;
}
async function requestBandC() {
const [b, c] = await Promise.all([ loadDataB, loadDataC ].map(useCache));
return b + c;
}
module.exports = { requestAandB, requestBandC }
Run Code Online (Sandbox Code Playgroud)
谢谢
| 归档时间: |
|
| 查看次数: |
158 次 |
| 最近记录: |