Search code examples
javascriptsynchronizationchrome-extension-manifest-v3

chrome extension wait for chrome.storage.local.get before proceeding to next line


I am having syncronization problem with chrome.storage.local.get

The code that works:

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
    console.log('chrome.runtime.onMessage.addListener: ', message)
    if (message.type === "NewURL") {
        console.log('background.js: start timer')
        let blockUrlList = ["youtube.com", "dict.cc"]
        /*
        chrome.storage.local.get(["block_urls"], (res) => {
            blockUrlList = "block_urls" in res ? res.block_urls : []
        })
        */
        console.log(blockUrlList)
        chrome.tabs.query({ "url": blockUrlList.map(p => `*://*.${p}/*`)}, (tabs) => {
            tabs.forEach((tab) => {
                console.log('tab.id: ',tab.id, 'tab.url:', tab.url)
            })
        })
    }
})

however, if i try to get blockUrlList from chrome storage I get blank list.

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
    console.log('chrome.runtime.onMessage.addListener: ', message)
    if (message.type === "NewURL") {
        console.log('background.js: start timer')
        let blockUrlList = []
        
        chrome.storage.local.get(["block_urls"], (res) => {
            blockUrlList = "block_urls" in res ? res.block_urls : []
        })
        
        console.log(blockUrlList)
        chrome.tabs.query({ "url": blockUrlList.map(p => `*://*.${p}/*`)}, (tabs) => {
            tabs.forEach((tab) => {
                console.log('tab.id: ',tab.id, 'tab.url:', tab.url)
            })
        })
    }
})

How can I synchronise i.e. wait for chrome.storage.local.get before proceeding to chrome.tabs.query? Also I want chrome.tabs.query to wait on it before proceeding to next line

EDIT
Though the question has been closed by the moderator. I am writing the cleanest (easiest to read) solution I learned.

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
    if (message.type === "NewURL") {
        injectJS()
    }
})
async function injectJS() {   
    try {
        let blockUrlList = []
        const res = await chrome.storage.local.get(["block_urls"])
        blockUrlList = "block_urls" in res ? res.block_urls : []
        
        const qryOptions = { "url": blockUrlList.map(p => `*://*.${p}/*`)}
        const tabs = await chrome.tabs.query(qryOptions)

        tabs.forEach((tab) => {
            chrome.scripting.executeScript({
                target: {tabId: tab.id},
                files: ['content/injected.js']
            })
        })
    } catch (err) {
        console.log('No matching tab', err)
    }
}

Solution

  • You can simply put it into the callback:

    chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
        console.log('chrome.runtime.onMessage.addListener: ', message)
        if (message.type === "NewURL") {
            console.log('background.js: start timer')
            let blockUrlList = []
            
            chrome.storage.local.get(["block_urls"], (res) => {
                blockUrlList = "block_urls" in res ? res.block_urls : []
                console.log(blockUrlList)
                chrome.tabs.query({ "url": blockUrlList.map(p => `*://*.${p}/*`)}, (tabs) => {
                    tabs.forEach((tab) => {
                        console.log('tab.id: ',tab.id, 'tab.url:', tab.url)
                    })
                })
            })
            
        }
    })
    

    The callback, after all is running at the very moment of your preference, i.e., when the get() has finished successfully.