or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

async-functions.mdcache-management.mdfunction-memoization.mdindex.mdmethod-memoization.mdprofiling.mdweakmap-memoization.md

method-memoization.mddocs/

0

# Method Memoization

1

2

Specialized utilities for memoizing object methods with lazy property descriptors and proper `this` context handling. Ideal for prototype method optimization and instance-specific caching where methods need to be memoized on a per-instance basis.

3

4

## Capabilities

5

6

### Method Memoization with Property Descriptors

7

8

Create lazy property descriptors for memoizing object methods with proper `this` binding and instance-specific caching.

9

10

```javascript { .api }

11

/**

12

* Create memoized method property descriptors

13

* @param {Object} methods - Object mapping method names to descriptors

14

* @returns {Object} Lazy property descriptors for Object.defineProperties

15

*/

16

const memoizeMethods = require("memoizee/methods");

17

const descriptors = memoizeMethods(methodsObject);

18

```

19

20

**Usage Examples:**

21

22

```javascript

23

const memoizeMethods = require("memoizee/methods");

24

const d = require("d"); // Property descriptor helper

25

26

class DataProcessor {

27

constructor(data) {

28

this.data = data;

29

this.processed = false;

30

}

31

}

32

33

// Define memoized methods on prototype

34

Object.defineProperties(DataProcessor.prototype, memoizeMethods({

35

36

// Basic memoized method

37

calculateSum: d(function() {

38

console.log("Computing sum...");

39

return this.data.reduce((sum, val) => sum + val, 0);

40

}),

41

42

// Memoized method with options

43

expensiveTransform: d(function(transformType) {

44

console.log(`Performing ${transformType} transform...`);

45

return this.data.map(val => {

46

switch(transformType) {

47

case 'double': return val * 2;

48

case 'square': return val * val;

49

default: return val;

50

}

51

});

52

}, { maxAge: 60000 }), // Cache for 1 minute

53

54

// Async memoized method

55

fetchRelatedData: d(function(endpoint, callback) {

56

console.log(`Fetching from ${endpoint}...`);

57

setTimeout(() => {

58

callback(null, { endpoint, data: `data-for-${this.data[0]}` });

59

}, 100);

60

}, { async: true })

61

62

}));

63

64

// Usage

65

const processor1 = new DataProcessor([1, 2, 3, 4, 5]);

66

const processor2 = new DataProcessor([10, 20, 30]);

67

68

processor1.calculateSum(); // "Computing sum...", returns 15

69

processor1.calculateSum(); // Cache hit, returns 15 (no console output)

70

71

processor2.calculateSum(); // "Computing sum...", returns 60 (different instance)

72

processor2.calculateSum(); // Cache hit for processor2

73

74

// Each instance has its own cache

75

processor1.expensiveTransform('double'); // Computed for processor1

76

processor2.expensiveTransform('double'); // Computed for processor2 (different cache)

77

```

78

79

### Advanced Method Configuration

80

81

Configure memoized methods with complex options including custom normalizers and argument handling.

82

83

```javascript { .api }

84

/**

85

* Advanced method memoization options

86

*/

87

const descriptors = memoizeMethods({

88

methodName: d(function(...args) {

89

// Method implementation

90

}, {

91

// Standard memoization options

92

length: number,

93

primitive: boolean,

94

maxAge: number,

95

max: number,

96

async: boolean,

97

promise: boolean,

98

99

// Method-specific options

100

getNormalizer: function(length) {

101

// Return custom normalizer function

102

return function(args) {

103

return customKeyGeneration(args);

104

};

105

}

106

})

107

});

108

```

109

110

**Usage Examples:**

111

112

```javascript

113

const memoizeMethods = require("memoizee/methods");

114

const d = require("d");

115

116

class ApiClient {

117

constructor(baseUrl, apiKey) {

118

this.baseUrl = baseUrl;

119

this.apiKey = apiKey;

120

}

121

}

122

123

Object.defineProperties(ApiClient.prototype, memoizeMethods({

124

125

// Custom normalizer for complex object arguments

126

fetchUserData: d(function(userQuery) {

127

console.log("Fetching user data...");

128

return fetch(`${this.baseUrl}/users`, {

129

method: 'POST',

130

body: JSON.stringify(userQuery),

131

headers: { 'Authorization': `Bearer ${this.apiKey}` }

132

}).then(r => r.json());

133

}, {

134

promise: true,

135

maxAge: 300000, // 5 minute cache

136

getNormalizer: function(length) {

137

return function(args) {

138

// Normalize based on query content, not object identity

139

return JSON.stringify(args[0]);

140

};

141

}

142

}),

143

144

// Method with argument resolvers

145

processNumbers: d(function(num1, num2, operation) {

146

console.log(`Processing: ${num1} ${operation} ${num2}`);

147

switch(operation) {

148

case 'add': return num1 + num2;

149

case 'multiply': return num1 * num2;

150

default: return 0;

151

}

152

}, {

153

length: 3,

154

resolvers: [Number, Number, String], // Type coercion

155

maxAge: 30000

156

}),

157

158

// Async method with size limiting

159

heavyComputation: d(function(input, callback) {

160

console.log("Starting heavy computation...");

161

setTimeout(() => {

162

const result = input.map(x => x ** 2).reduce((a, b) => a + b, 0);

163

callback(null, result);

164

}, 1000);

165

}, {

166

async: true,

167

max: 50, // Limit cache size per instance

168

dispose: (result) => {

169

console.log("Disposing computation result:", result);

170

}

171

})

172

173

}));

174

175

// Usage

176

const client = new ApiClient("https://api.example.com", "key123");

177

178

client.fetchUserData({ name: "Alice", active: true });

179

client.fetchUserData({ active: true, name: "Alice" }); // Cache hit (normalized)

180

181

client.processNumbers("10", "5", "add"); // 15 (with type coercion)

182

client.processNumbers(10, 5, "add"); // Cache hit

183

```

184

185

### Instance-Specific Caching

186

187

Each object instance maintains its own separate cache for memoized methods.

188

189

```javascript { .api }

190

/**

191

* Instance isolation - each object gets its own method cache

192

* Methods are memoized per instance, not globally

193

*/

194

```

195

196

**Usage Examples:**

197

198

```javascript

199

const memoizeMethods = require("memoizee/methods");

200

const d = require("d");

201

202

class Calculator {

203

constructor(name) {

204

this.name = name;

205

this.calculations = 0;

206

}

207

}

208

209

Object.defineProperties(Calculator.prototype, memoizeMethods({

210

fibonacci: d(function(n) {

211

this.calculations++;

212

console.log(`${this.name}: Computing fib(${n})`);

213

if (n < 2) return n;

214

return this.fibonacci(n - 1) + this.fibonacci(n - 2);

215

})

216

}));

217

218

const calc1 = new Calculator("Calculator A");

219

const calc2 = new Calculator("Calculator B");

220

221

// Each instance has separate cache

222

calc1.fibonacci(10); // Computes and caches for calc1

223

calc2.fibonacci(10); // Computes and caches for calc2 (separate cache)

224

225

calc1.fibonacci(10); // Cache hit for calc1

226

calc2.fibonacci(10); // Cache hit for calc2

227

228

console.log(`${calc1.name} calculations: ${calc1.calculations}`);

229

console.log(`${calc2.name} calculations: ${calc2.calculations}`);

230

231

// Cache management per instance

232

calc1.fibonacci.clear(); // Clears only calc1's cache

233

calc2.fibonacci.delete(10); // Deletes only from calc2's cache

234

```

235

236

## Method Cache Management

237

238

### Per-Instance Cache Control

239

240

Access cache management methods on individual instances.

241

242

```javascript { .api }

243

/**

244

* Cache management methods available on each instance

245

*/

246

instance.methodName.delete(...args); // Delete specific cache entry

247

instance.methodName.clear(); // Clear all cached results for this instance

248

instance.methodName._get(...args); // Get cached value without execution

249

instance.methodName._has(...args); // Check if result is cached

250

```

251

252

**Usage Examples:**

253

254

```javascript

255

class DataAnalyzer {

256

constructor(dataset) {

257

this.dataset = dataset;

258

}

259

}

260

261

Object.defineProperties(DataAnalyzer.prototype, memoizeMethods({

262

analyzeData: d(function(analysisType) {

263

console.log(`Analyzing ${analysisType}...`);

264

return { type: analysisType, result: Math.random() };

265

}, { maxAge: 60000 })

266

}));

267

268

const analyzer = new DataAnalyzer([1, 2, 3]);

269

270

analyzer.analyzeData('mean'); // Computed

271

analyzer.analyzeData('median'); // Computed

272

273

// Check cache status

274

console.log(analyzer.analyzeData._has('mean')); // true

275

console.log(analyzer.analyzeData._has('mode')); // false

276

277

// Get cached value

278

const cachedMean = analyzer.analyzeData._get('mean');

279

console.log(cachedMean);

280

281

// Clear specific entry

282

analyzer.analyzeData.delete('mean');

283

284

// Clear all cached results for this instance

285

analyzer.analyzeData.clear();

286

```

287

288

### Reference Counting for Methods

289

290

Use reference counting with method memoization for sophisticated memory management.

291

292

```javascript { .api }

293

/**

294

* Reference counting methods for memoized methods

295

*/

296

const descriptors = memoizeMethods({

297

methodName: d(function(...args) {

298

// Method implementation

299

}, {

300

refCounter: true

301

})

302

});

303

304

// Additional methods available with refCounter

305

instance.methodName.deleteRef(...args); // Decrement reference

306

instance.methodName.getRefCount(...args); // Get reference count

307

```

308

309

**Usage Examples:**

310

311

```javascript

312

class ResourceManager {

313

constructor(id) {

314

this.id = id;

315

}

316

}

317

318

Object.defineProperties(ResourceManager.prototype, memoizeMethods({

319

createResource: d(function(resourceType) {

320

console.log(`Creating ${resourceType} resource...`);

321

return {

322

type: resourceType,

323

id: Math.random(),

324

cleanup: () => console.log(`Cleaning up ${resourceType}`)

325

};

326

}, {

327

refCounter: true,

328

dispose: (result) => {

329

if (result && result.cleanup) result.cleanup();

330

}

331

})

332

}));

333

334

const manager = new ResourceManager("mgr-1");

335

336

const resource1 = manager.createResource('database'); // refs: 1

337

const resource2 = manager.createResource('database'); // refs: 2 (cache hit)

338

339

console.log(manager.createResource.getRefCount('database')); // 2

340

341

manager.createResource.deleteRef('database'); // refs: 1

342

manager.createResource.deleteRef('database'); // refs: 0, cleanup called

343

```

344

345

## Advanced Method Patterns

346

347

### Lazy Initialization with Memoization

348

349

Combine lazy initialization with method memoization for optimal performance.

350

351

```javascript

352

class ExpensiveService {

353

constructor(config) {

354

this.config = config;

355

// Don't initialize expensive resources in constructor

356

}

357

}

358

359

Object.defineProperties(ExpensiveService.prototype, memoizeMethods({

360

361

// Lazy initialization - only run once per instance

362

initialize: d(function() {

363

console.log("Initializing expensive service...");

364

this.connection = createDatabaseConnection(this.config);

365

this.cache = new Map();

366

return this;

367

}),

368

369

// Use initialized resources

370

queryData: d(function(query) {

371

this.initialize(); // Ensure initialization (cached after first call)

372

console.log("Querying data...");

373

return this.connection.query(query);

374

}, {

375

async: true,

376

maxAge: 60000

377

})

378

379

}));

380

381

const service = new ExpensiveService({ host: 'localhost' });

382

// No expensive initialization yet

383

384

service.queryData('SELECT * FROM users'); // Initializes and queries

385

service.queryData('SELECT * FROM posts'); // Uses existing initialization

386

```

387

388

### Method Inheritance and Memoization

389

390

Handle method memoization in inheritance hierarchies.

391

392

```javascript

393

class BaseProcessor {

394

constructor(data) {

395

this.data = data;

396

}

397

}

398

399

// Base class memoized methods

400

Object.defineProperties(BaseProcessor.prototype, memoizeMethods({

401

baseProcess: d(function() {

402

console.log("Base processing...");

403

return this.data.length;

404

})

405

}));

406

407

class AdvancedProcessor extends BaseProcessor {

408

constructor(data, options) {

409

super(data);

410

this.options = options;

411

}

412

}

413

414

// Extended class additional memoized methods

415

Object.defineProperties(AdvancedProcessor.prototype, memoizeMethods({

416

advancedProcess: d(function(mode) {

417

console.log("Advanced processing...");

418

const baseResult = this.baseProcess(); // Uses memoized base method

419

return baseResult * (this.options.multiplier || 1);

420

}, { maxAge: 30000 })

421

}));

422

423

const advanced = new AdvancedProcessor([1, 2, 3], { multiplier: 2 });

424

advanced.baseProcess(); // Base method cached

425

advanced.advancedProcess('fast'); // Advanced method cached, reuses base result

426

```

427

428

## Performance Considerations

429

430

### Memory Usage Per Instance

431

432

Method memoization creates separate caches per instance:

433

434

```javascript

435

// Consider memory usage with many instances

436

const instances = [];

437

for (let i = 0; i < 1000; i++) {

438

const instance = new MyClass(data[i]);

439

instance.expensiveMethod(params); // Each instance gets its own cache

440

instances.push(instance);

441

}

442

443

// Use size limits for instances with large caches

444

Object.defineProperties(MyClass.prototype, memoizeMethods({

445

expensiveMethod: d(function(params) {

446

return heavyComputation(params);

447

}, {

448

max: 100, // Limit cache size per instance

449

maxAge: 300000 // Auto-expire entries

450

})

451

}));

452

```

453

454

### Choosing Method Memoization

455

456

Method memoization is ideal when:

457

458

- **Instance-specific results**: Results depend on instance state (`this` context)

459

- **Prototype optimization**: Want to add caching to existing class hierarchies

460

- **Per-instance cache management**: Need separate cache control per object

461

- **Object-oriented design**: Working with class-based architectures

462

463

Use regular memoization when:

464

465

- **Stateless functions**: Results don't depend on `this` context

466

- **Global caching**: Want shared cache across all calls

467

- **Functional programming**: Working with standalone functions