From 85717e7f419ba1a2e506cb369c3df124ebfa44d9 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Fri, 18 Aug 2023 10:45:59 +0200 Subject: [PATCH] desperate commit --- src/Evaluator.ts | 73 +++++++++++++++++++++----------------------- src/TransportNode.js | 14 ++++----- 2 files changed, 41 insertions(+), 46 deletions(-) diff --git a/src/Evaluator.ts b/src/Evaluator.ts index 8ea2061..9fff596 100644 --- a/src/Evaluator.ts +++ b/src/Evaluator.ts @@ -6,22 +6,14 @@ const delay = (ms: number) => setTimeout(() => reject(new Error("Operation took too long")), ms) ); + const tryCatchWrapper = ( application: Editor, code: string ): Promise => { - /** - * This function wraps a string of code in a try/catch block and returns a promise - * that resolves to true if the code is valid and false if the code is invalid after - * being evaluated. - * - * @param application - The main application instance - * @param code - The string of code to wrap and evaluate - * @returns A promise that resolves to true if the code is valid and false if the code is invalid - */ return new Promise((resolve, _) => { try { - Function(`"use strict";try{${code}} catch (e) {console.log(e)};`).call(application.api); + Function(`"use strict";try{${code}} catch (e) {console.log(e)};`).call(application.api); resolve(true); } catch (error) { console.log(error); @@ -30,35 +22,46 @@ const tryCatchWrapper = ( }); }; +const cache = new Map(); +const MAX_CACHE_SIZE = 20; + +const addFunctionToCache = (code: string, fn: Function) => { + if (cache.size >= MAX_CACHE_SIZE) { + // Delete the first item if cache size exceeds max size + cache.delete(cache.keys().next().value); + } + cache.set(code, fn); +} + export const tryEvaluate = async ( - /** - * This function attempts to evaluate a string of code in the context of user API. - * If the code is invalid, it will attempt to evaluate the previous valid code. - * - * @param application - The main application instance - * @param code - The set of files to evaluate - * @param timeout - The timeout in milliseconds - * @returns A promise that resolves to void - * - */ application: Editor, code: File, timeout = 5000 ): Promise => { try { code.evaluations!++; - const isCodeValid = await Promise.race([ - tryCatchWrapper( - application, - (`let i = ${code.evaluations};` + code.candidate) as string - ), - delay(timeout), - ]); - - if (isCodeValid) { - code.committed = code.candidate; + const candidateCode = code.candidate; + + if (cache.has(candidateCode)) { + // If the code is already in cache, use it + cache.get(candidateCode)!.call(application.api); + console.log('Using cached code') } else { - await evaluate(application, code, timeout); + console.log('Evaluating code') + const wrappedCode = `let i = ${code.evaluations};` + candidateCode; + // Otherwise, evaluate the code and if valid, add it to the cache + const isCodeValid = await Promise.race([ + tryCatchWrapper(application, wrappedCode as string), + delay(timeout), + ]); + + if (isCodeValid) { + code.committed = code.candidate; + const newFunction = new Function(`"use strict";try{${wrappedCode}} catch (e) {console.log(e)};`); + addFunctionToCache(candidateCode, newFunction); + } else { + await evaluate(application, code, timeout); + } } } catch (error) { console.log(error); @@ -70,14 +73,6 @@ export const evaluate = async ( code: File, timeout = 1000 ): Promise => { - /** - * This function evaluates a string of code in the context of user API. - * - * @param application - The main application instance - * @param code - The set of files to evaluate - * @param timeout - The timeout in milliseconds - * @returns A promise that resolves to void - */ try { await Promise.race([ tryCatchWrapper(application, code.committed as string), diff --git a/src/TransportNode.js b/src/TransportNode.js index ac8d263..3ffd396 100644 --- a/src/TransportNode.js +++ b/src/TransportNode.js @@ -14,7 +14,12 @@ export class TransportNode extends AudioWorkletNode { this.currentPulsePosition = 0; this.nextPulsePosition = -1; this.executionLatency = 0; - this.lastLatencies = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + this.lastLatencies = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; this.indexOfLastLatencies = 0; // setInterval(() => this.ping(), 1000); this.startTime = null; @@ -35,17 +40,12 @@ export class TransportNode extends AudioWorkletNode { if (this.nextPulsePosition !== nextPulsePosition) { this.nextPulsePosition = nextPulsePosition; setTimeout(() => { - // const now = performance.now(); // Use AudioContext time instead const now = this.app.audioContext.currentTime; this.app.clock.time_position = futureTimeStamp; // this.$clock.innerHTML = `[${futureTimeStamp.bar}:${futureTimeStamp.beat}:${zeroPad(futureTimeStamp.pulse, '2')}]`; - tryEvaluate( - this.app, - this.app.global_buffer, - ); + tryEvaluate(this.app, this.app.global_buffer); this.hasBeenEvaluated = true; this.currentPulsePosition = nextPulsePosition; - // const then = performance.now(); // Use AudioContext time instead const then = this.app.audioContext.currentTime; this.lastLatencies[this.indexOfLastLatencies] = then - now; this.indexOfLastLatencies = (this.indexOfLastLatencies + 1) % this.lastLatencies.length;