As crypto prices change every millisecond, we need to ability to update this data. But currently there is no way to do that, as formula functions are stateless.
To achieve this, you can use calculationPipeline hook.
Subscribing to REST API
calculationPipeline hook contains a callback and it should return an unsubscribe function.
Above REST API can be written as below, so that we can poll the API every 5 seconds.
Formula lifecycle or calculationPipeline hook is called when selections/cells are moved or deleted, or copy pasted to another location.
It is advisable to use rxjs subscription for websocket updates, so that you can subscribe and unsubscribe to a subject upon disconnect.
Web workers
With calculationPipeline , you can choose to run your code in a web worker. Initialise a single web worker or multiple web workers (if user enters same formula, calculationPipeline will be invoked)
// Initialize a worker when Spreadsheet is loaded// You can also initialize this in calculationPipeline, but you wouldnt// want to create 1 worker per formulaconstcryptoWorker=newWorker('./worker.js')exportconstCRYPTOPRICE= (parser:FormulaParser, arg:FunctionArgument) => {if (!arg ||!arg.value) {thrownewFormulaError("#VALUE!","Websocket URL is required"); }calculationPipeline(parser, (onUpdate) => {cryptoWorker.postMessage({ type:'subscribe', symbol:arg.value })cryptoWorker.onmessage= (event) => {if (event.symbol ===arg.value) {onUpdate(event.data) } }return () => {cryptoWorker.postMessage({ type:'unsubscribe', symbol:arg.value }) } });return`Connecting to websocket`}
Cancelling async formula evaluation when dependencies change
AbortController is used to cancel long running formula when dependencies change, and trigger a new formula evaluation
importtype FormulaParser from"@rowsncolumns/fast-formula-parser";exportconstBACK_END_API= (parser:FormulaParser) => { constcontroller=newAbortController();constsignal=controller.signal;// Listen to abort signals// When cell dependencies change and this formula is still running// Abort signal is emitted for users to abort this requestparser.position?.signal.addEventListener('abort', () => {// Abort the fetch requestcontroller.abort() })constrequest=awaitfetch('/url', { signal })constdata=awaitrequest.json()return [ data.value ]}