Search code examples
javascripttypescriptgoogle-chrome-extension

Wait for executeScript to finish


I have this script I execute from a Chrome extension

export const getData = () => {
  chrome.tabs.query({ active: true, currentWindow: true }, tabs => {
    chrome.tabs.executeScript(
      tabs[0]?.id,
      { code: `document.getElementById('a1').innerHTML;` }, parseData
    );
  });
};

const parseData = (result: any) => {
  const obj = new Something();
  // Do complex stuff with this object
  chrome.storage.sync.set(
    {
      id: obj.id,
    }
    );
  console.log('ID from extract', obj.id);
};

From my background script, I call this function and then call the function that gets the parsed data through chrome storage, so both of these functions take callbacks as arguments.

I need my first function to finish before executing the other one but it's completely ignoring the await, I'm not sure why and how can I make it wait, if it's even possible

background script

chrome.runtime.onMessage.addListener(async(request, sender, sendResponse) => {
    let list = [];
      await getData();
      await getExtractedData((value) => {
        // Do a lot of stuff with `list`
        console.log('After extract:', value);
      });
  }
);

getExtractedData function is in another file:

export const getExtractedData = (callback) => {
  return chrome.storage.sync.get(
    [
      'id',
    ],
    callback);
};

It's supposed print this:

ID from extract 123456
After extract {id: 123456}

But it's currently doing this:

After extract {id: 123455}
ID from extract 123456

(After extract is logging what it extracted in the previous run, but not in the current run)


Solution

  • Functions need to return a Promise with a properly wired resolve/reject.

    const getData = () => new Promise(resolve => {
      chrome.tabs.executeScript({code: `document.getElementById('a1').innerHTML`}, res => {
        parseData(res).then(resolve);
      });
    });
    const parseData = (data) => new Promise(resolve => {
      // Do complex stuff with this object
      chrome.storage.sync.set({id: obj.id}, () => resolve(obj.id));
    });
    const getExtractedData = () => new Promise(resolve => {
      chrome.storage.sync.get('id', data => resolve(data.id));
    });
    

    BTW you don't need storage as getData's Promise chain already resolves to the processed id:

    async foo => {
      const resultId = await getData();
      // ..........
    }