
使用基于 ioredis 构建的多功能、易于使用的缓存管理器来提升 node.js 应用程序的性能。简化缓存、优化效率并简化操作。
我根据自己的需求开发了一个基于 ioredis 的类,重点关注易用性和性能。它包括 typescript 支持,旨在实现简单使用和高效操作。它仍然可以进一步改进和优化,可以动态数据库使用和更详细的错误处理。我想与您分享,如果您有任何反馈或改进建议,我将不胜感激。
import Redis, { type RedisOptions } from 'ioredis';
interface CacheConfig {
defaultTTL?: number;
}
export class cacheManager {
private static instance: cacheManager;
private static redisClient: Redis;
private currentKey: string | null;
private defaultTTL: number;
private static readonly DEFAULT_TTL = 3600;
private constructor(config?: CacheConfig) {
const redisConfig: RedisOptions = {
db: 2,
retryStrategy: (times: number) => {
const delay = Math.min(times * 50, 2000);
return delay;
},
lazyConnect: true,
maxRetriesPerRequest: 3,
enableReadyCheck: true,
autoResubscribe: true,
autoResendUnfulfilledCommands: true,
reconnectOnError: (err: Error) => {
const targetError = 'READONLY';
return err.message.includes(targetError);
},
};
if (!cacheManager.redisClient) {
cacheManager.redisClient = new Redis(redisConfig);
cacheManager.redisClient.on('error', (error: Error) => {
console.error('Redis Client Error:', error);
});
cacheManager.redisClient.on('connect', () => {
console.debug('Redis Client Connected');
});
cacheManager.redisClient.on('ready', () => {
console.debug('Redis Client Ready');
});
}
this.currentKey = null;
this.defaultTTL = config?.defaultTTL ?? cacheManager.DEFAULT_TTL;
}
public static getInstance(config?: CacheConfig): cacheManager {
if (!cacheManager.instance) {
cacheManager.instance = new cacheManager(config);
}
return cacheManager.instance;
}
public key(key: string): cacheManager {
this.validateKey(key);
this.currentKey = key;
return this;
}
private validateKey(key: string): void {
if (key.length > 100) throw new Error('Key too long');
if (!/^[\w:-]+$/.test(key)) throw new Error('Invalid key format');
}
public async getValue<T>(): Promise<T | null> {
try {
if (!this.currentKey) {
throw new Error('Key is required');
}
const value = await cacheManager.redisClient.get(this.currentKey);
return value ? JSON.parse(value) : null;
} catch (error) {
console.error('getValue Error:', error);
return null;
}
}
public async getMultiple<T>(keys: string[]): Promise<Record<string, T | null>> {
try {
const pipeline = cacheManager.redisClient.pipeline();
for (const key of keys) {
pipeline.get(key);
}
type PipelineResult = [Error | null, string | null][] | null;
const results = (await pipeline.exec()) as PipelineResult;
const output: Record<string, T | null> = {};
if (!results) {
return output;
}
keys.forEach((key, index) => {
const result = results[index];
if (result) {
const [err, value] = result;
if (!err && value) {
try {
output[key] = JSON.parse(value);
} catch {
output[key] = null;
}
} else {
output[key] = null;
}
} else {
output[key] = null;
}
});
return output;
} catch (error) {
console.error('getMultiple Error:', error);
return {};
}
}
public async setValue<T>(value: T, ttl: number = this.defaultTTL): Promise<boolean> {
try {
if (!this.currentKey) {
throw new Error('Key is required');
}
const stringValue = JSON.stringify(value);
if (ttl) {
await cacheManager.redisClient.setex(this.currentKey, ttl, stringValue);
} else {
await cacheManager.redisClient.set(this.currentKey, stringValue);
}
return true;
} catch (error) {
console.error('setValue Error:', error);
return false;
}
}
public async setBulkValue<T>(keyValuePairs: Record<string, T>, ttl: number = this.defaultTTL, batchSize = 1000): Promise<boolean> {
try {
const entries = Object.entries(keyValuePairs);
for (let i = 0; i < entries.length; i += batchSize) {
const batch = entries.slice(i, i + batchSize);
const pipeline = cacheManager.redisClient.pipeline();
for (const [key, value] of batch) {
const stringValue = JSON.stringify(value);
if (ttl) {
pipeline.setex(key, ttl, stringValue);
} else {
pipeline.set(key, stringValue);
}
}
await pipeline.exec();
}
return true;
} catch (error) {
console.error('setBulkValue Error:', error);
return false;
}
}
public async getOrSetValue<T>(fallbackFn: () => Promise<T>, ttl: number = this.defaultTTL): Promise<T | null> {
try {
if (!this.currentKey) {
throw new Error('Key is required');
}
const cachedValue = await this.getValue<T>();
if (cachedValue !== null) {
return cachedValue;
}
const value = await fallbackFn();
await this.setValue(value, ttl);
return value;
} catch (error) {
console.error('getOrSetValue Error:', error);
return null;
}
}
public async delete(): Promise<boolean> {
try {
if (!this.currentKey) {
throw new Error('Key is required');
}
await cacheManager.redisClient.del(this.currentKey);
return true;
} catch (error) {
console.error('delete Error:', error);
return false;
}
}
public async exists(): Promise<boolean> {
try {
if (!this.currentKey) {
throw new Error('Key is required');
}
return (await cacheManager.redisClient.exists(this.currentKey)) === 1;
} catch (error) {
console.error('exists Error:', error);
return false;
}
}
public async getTTL(): Promise<number> {
try {
if (!this.currentKey) {
throw new Error('Key is required');
}
return await cacheManager.redisClient.ttl(this.currentKey);
} catch (error) {
console.error('getTTL Error:', error);
return -1;
}
}
public static async disconnect(): Promise<void> {
if (cacheManager.redisClient) {
await cacheManager.redisClient.quit();
}
}
}
以上就是使用 TypeScript 和 ioredis 在 Nodejs 中构建高性能缓存管理器的详细内容,更多请关注php中文网其它相关文章!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号