Jelajahi Sumber

fix: slow performance when looping through large data

Ahmad Kholid 1 tahun lalu
induk
melakukan
e2a548a808

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "automa",
-  "version": "1.28.2",
+  "version": "1.28.3",
   "description": "An extension for automating your browser by connecting blocks",
   "repository": {
     "type": "git",

+ 65 - 48
src/content/index.js

@@ -33,25 +33,20 @@ function messageToFrame(frameElement, blockData) {
     }
     window.addEventListener('message', onMessage);
 
-    frameElement.contentWindow.postMessage(
-      {
-        type: 'automa:execute-block',
-        blockData: { ...blockData, frameSelector: '' },
-      },
-      '*'
-    );
+    const messageId = `message:${nanoid(4)}`;
+    browser.storage.local.set({ [messageId]: true }).then(() => {
+      frameElement.contentWindow.postMessage(
+        {
+          messageId,
+          type: 'automa:execute-block',
+          blockData: { ...blockData, frameSelector: '' },
+        },
+        '*'
+      );
+    });
   });
 }
 async function executeBlock(data) {
-  if ((data.name || data.label) === 'javascript-code') {
-    const { workflowStates } = await browser.storage.local.get(
-      'workflowStates'
-    );
-    if (workflowStates && workflowStates.length === 0) {
-      throw new Error('Invalid execution');
-    }
-  }
-
   const removeExecutedBlock = showExecutedBlock(data, data.executedBlockOnWeb);
   if (data.data?.selector?.includes('|>')) {
     const [frameSelector, selector] = data.data.selector.split(/\|>(.+)/);
@@ -112,52 +107,74 @@ async function executeBlock(data) {
 
   throw error;
 }
-function messageListener({ data, source }) {
-  if (data.type === 'automa:get-frame' && isMainFrame) {
-    let frameRect = { x: 0, y: 0 };
+async function messageListener({ data, source }) {
+  try {
+    if (data.type === 'automa:get-frame' && isMainFrame) {
+      let frameRect = { x: 0, y: 0 };
 
-    document.querySelectorAll('iframe').forEach((iframe) => {
-      if (iframe.contentWindow !== source) return;
+      document.querySelectorAll('iframe').forEach((iframe) => {
+        if (iframe.contentWindow !== source) return;
 
-      frameRect = iframe.getBoundingClientRect();
-    });
+        frameRect = iframe.getBoundingClientRect();
+      });
 
-    source.postMessage(
-      {
-        frameRect,
-        type: 'automa:the-frame-rect',
-      },
-      '*'
-    );
+      source.postMessage(
+        {
+          frameRect,
+          type: 'automa:the-frame-rect',
+        },
+        '*'
+      );
 
-    return;
-  }
+      return;
+    }
 
-  if (data.type === 'automa:execute-block') {
-    executeBlock(data.blockData)
-      .then((result) => {
-        window.top.postMessage(
-          {
-            result,
-            type: 'automa:block-execute-result',
-          },
-          '*'
-        );
-      })
-      .catch((error) => {
-        console.error(error);
+    if (data.type === 'automa:execute-block') {
+      const messageToken = await browser.storage.local.get(data.messageId);
+      if (!data.messageId || !messageToken[data.messageId]) {
         window.top.postMessage(
           {
             result: {
               $isError: true,
-              message: error.message,
-              data: error.data || {},
+              message: 'Block id is empty',
+              data: {},
             },
             type: 'automa:block-execute-result',
           },
           '*'
         );
-      });
+        return;
+      }
+
+      await browser.storage.local.remove(data.messageId);
+
+      executeBlock(data.blockData)
+        .then((result) => {
+          window.top.postMessage(
+            {
+              result,
+              type: 'automa:block-execute-result',
+            },
+            '*'
+          );
+        })
+        .catch((error) => {
+          console.error(error);
+          window.top.postMessage(
+            {
+              result: {
+                $isError: true,
+                message: error.message,
+                data: error.data || {},
+              },
+              type: 'automa:block-execute-result',
+            },
+            '*'
+          );
+        });
+    }
+  } catch (error) {
+    console.error(error);
   }
 }
 

+ 14 - 6
src/workflowEngine/WorkflowState.js

@@ -8,6 +8,8 @@ class WorkflowState {
 
     this.states = new Map();
     this.eventListeners = {};
+
+    this.storageTimeout = null;
   }
 
   _updateBadge() {
@@ -16,8 +18,14 @@ class WorkflowState {
   }
 
   _saveToStorage() {
-    const states = Object.fromEntries(this.states);
-    return this.storage.set(this.key, states);
+    if (this.storageTimeout) return;
+
+    this.storageTimeout = setTimeout(() => {
+      this.storageTimeout = null;
+
+      const states = Object.fromEntries(this.states);
+      this.storage.set(this.key, states);
+    }, 1000);
   }
 
   dispatchEvent(name, params) {
@@ -65,7 +73,7 @@ class WorkflowState {
   async add(id, data = {}) {
     this.states.set(id, data);
     this._updateBadge();
-    await this._saveToStorage(this.key);
+    this._saveToStorage(this.key);
   }
 
   async stop(id) {
@@ -89,7 +97,7 @@ class WorkflowState {
       ...state,
       status: 'running',
     });
-    await this._saveToStorage();
+    this._saveToStorage();
 
     this.dispatchEvent('resume', { id, nextBlock });
   }
@@ -105,14 +113,14 @@ class WorkflowState {
 
     this.states.set(id, { ...state, ...data });
     this.dispatchEvent('update', { id, data });
-    await this._saveToStorage();
+    this._saveToStorage();
   }
 
   async delete(id) {
     this.states.delete(id);
     this.dispatchEvent('delete', id);
     this._updateBadge();
-    await this._saveToStorage();
+    this._saveToStorage();
   }
 }
 

+ 7 - 3
src/workflowEngine/WorkflowWorker.js

@@ -30,7 +30,7 @@ function blockExecutionWrapper(blockHandler, blockData) {
         reject(error);
       })
       .finally(() => {
-        clearTimeout(timeout);
+        if (timeout) clearTimeout(timeout);
       });
   });
 }
@@ -319,9 +319,13 @@ class WorkflowWorker {
       }
 
       if (result.nextBlockId && !result.destroyWorker) {
-        setTimeout(() => {
+        if (blockDelay > 0) {
+          setTimeout(() => {
+            executeBlocks(result.nextBlockId, result.data);
+          }, blockDelay);
+        } else {
           executeBlocks(result.nextBlockId, result.data);
-        }, blockDelay);
+        }
       } else {
         this.engine.destroyWorker(this.id);
       }