Cauthon
Cauthon

Reputation: 520

JavaScript - wait for async functions to complete

In my Chrome extension, I check each web request under a specific domain. If the URL matches a specific condition, and there's an existing open tab that matches another URL, I'd like to return {cancel: true}, which means the request is blocked.

So my code works this way: if the requested URL matches my condition, check all open tabs. If one of the open tabs matches my (second) condition, I want to return {cancel: true} from my initial (outer) function.

The Problem: The return from the outer function fires before all of the tabs are checked (= before all the forEach loops are executed), therefore it always returns {cancel: false}.

[I know there are many questions related to this, and one of the main solutions includes callback functions, but specifically in my case I haven't yet succeeded in making this work.]

Code:

function onBeforeRequestHandler (details) {
    var cancel = false;
    var url = details.url;
    // condition 1
    if (url.indexOf("condition_1") > -1){

        // check all open windows/tabs
        chrome.windows.getAll({populate:true}, function(windows){
            windows.forEach(function(single_window){
                single_window.tabs.forEach(function(tab){
                    // condition 2
                    if (tab.url.indexOf("condition_2") > -1){
                        cancel = true;
                        // this is less important - updating the tab works
                        chrome.tabs.update(tab.id, {url: url});
                    }
                });
            });
        });
        // always getting cancel = false here because it fires too quickly
        return {cancel: cancel};
    }
    else
        return {cancel: false};
}

chrome.webRequest.onBeforeRequest.addListener(onBeforeRequestHandler, {urls: ["some_domain"]}, ["blocking"]);

Upvotes: 0

Views: 206

Answers (1)

Sheile
Sheile

Reputation: 443

Currently, you can't cancel the request based on asynchronous function in the Google Chrome.

In the Firefox, it already supported asynchronous function with Promise, you can implement that like following code.

function onBeforeRequestHandler (details) {
   var cancel = false;
   var url = details.url;
   // condition 1
   if (url.indexOf("condition_1") > -1){
       // check all open windows/tabs
       // return Promise which will be resolved after populate windows/tabs
       return browser.windows.getAll({populate:true})
           .then(function(windows) {
               windows.forEach(function(single_window) {
                   single_window.tabs.forEach(function(tab) {
                   // condition 2
                   if (tab.url.indexOf("condition_2") > -1) {
                       // this is less important - updating the tab works
                       browser.tabs.update(tab.id, {url: url});
                       return { cancel: true }
                   }
               });
           });
         })
   }
   else
       return {cancel: false};
}

history / references

According to webRequest.onBeforeRequest in MDN.

From Firefox 52 onwards, instead of returning BlockingResponse, the listener can return a Promise which is resolved with a BlockingResponse. This enables the listener to process the request asynchronously. https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webRequest/onBeforeRequest

Already reported feature request on the Chrome like the Firefox, but this ticket has NOT been closed. https://bugs.chromium.org/p/chromium/issues/detail?id=625860

Upvotes: 1

Related Questions