@@ -201,20 +201,25 @@ class LRU {
201201 * @since 1.0.0
202202 */
203203 get ( key ) {
204- let result ;
204+ const item = this . items [ key ] ;
205205
206- if ( this . has ( key ) ) {
207- const item = this . items [ key ] ;
206+ if ( item !== undefined ) {
207+ // Check TTL only if enabled to avoid unnecessary Date.now() calls
208+ if ( this . ttl > 0 ) {
209+ if ( item . expiry <= Date . now ( ) ) {
210+ this . delete ( key ) ;
208211
209- if ( this . ttl > 0 && item . expiry <= Date . now ( ) ) {
210- this . delete ( key ) ;
211- } else {
212- result = item . value ;
213- this . set ( key , result , true ) ;
212+ return undefined ;
213+ }
214214 }
215+
216+ // Fast LRU update without full set() overhead
217+ this . moveToEnd ( item ) ;
218+
219+ return item . value ;
215220 }
216221
217- return result ;
222+ return undefined ;
218223 }
219224
220225 /**
@@ -236,6 +241,52 @@ class LRU {
236241 return key in this . items ;
237242 }
238243
244+ /**
245+ * Efficiently moves an item to the end of the LRU list (most recently used position).
246+ * This is much faster than calling set() for LRU position updates.
247+ *
248+ * @method moveToEnd
249+ * @memberof LRU
250+ * @param {Object } item - The item to move to the end.
251+ * @private
252+ * @since 11.3.5
253+ */
254+ moveToEnd ( item ) {
255+ // If already at the end, nothing to do
256+ if ( this . last === item ) {
257+ return ;
258+ }
259+
260+ // Remove item from current position in the list
261+ if ( item . prev !== null ) {
262+ item . prev . next = item . next ;
263+ }
264+
265+ if ( item . next !== null ) {
266+ item . next . prev = item . prev ;
267+ }
268+
269+ // Update first pointer if this was the first item
270+ if ( this . first === item ) {
271+ this . first = item . next ;
272+ }
273+
274+ // Add item to the end
275+ item . prev = this . last ;
276+ item . next = null ;
277+
278+ if ( this . last !== null ) {
279+ this . last . next = item ;
280+ }
281+
282+ this . last = item ;
283+
284+ // Handle edge case: if this was the only item, it's also first
285+ if ( this . first === null ) {
286+ this . first = item ;
287+ }
288+ }
289+
239290 /**
240291 * Returns an array of all keys in the cache, ordered from least to most recently used.
241292 *
@@ -329,38 +380,20 @@ class LRU {
329380 * @since 1.0.0
330381 */
331382 set ( key , value , bypass = false , resetTtl = this . resetTtl ) {
332- let item ;
383+ let item = this . items [ key ] ;
333384
334- if ( bypass || this . has ( key ) ) {
335- item = this . items [ key ] ;
385+ if ( bypass || item !== undefined ) {
386+ // Existing item: update value and position
336387 item . value = value ;
337388
338389 if ( bypass === false && resetTtl ) {
339390 item . expiry = this . ttl > 0 ? Date . now ( ) + this . ttl : this . ttl ;
340391 }
341392
342- if ( this . last !== item ) {
343- const last = this . last ,
344- next = item . next ,
345- prev = item . prev ;
346-
347- if ( this . first === item ) {
348- this . first = item . next ;
349- }
350-
351- item . next = null ;
352- item . prev = this . last ;
353- last . next = item ;
354-
355- if ( prev !== null ) {
356- prev . next = next ;
357- }
358-
359- if ( next !== null ) {
360- next . prev = prev ;
361- }
362- }
393+ // Always move to end, but the bypass parameter affects TTL reset behavior
394+ this . moveToEnd ( item ) ;
363395 } else {
396+ // New item: check for eviction and create
364397 if ( this . max > 0 && this . size === this . max ) {
365398 this . evict ( true ) ;
366399 }
@@ -378,9 +411,9 @@ class LRU {
378411 } else {
379412 this . last . next = item ;
380413 }
381- }
382414
383- this . last = item ;
415+ this . last = item ;
416+ }
384417
385418 return this ;
386419 }
0 commit comments