如何等待异步方法的回调返回值?

时间:2013-02-28 00:00:39

标签: javascript asynchronous google-chrome-extension

我知道等待异步方法很愚蠢,one should use callbacks instead。但是如果第三方API强迫你同步呢?

我正在开发一个Chrome扩展程序,可防止用户访问已在另一个标签页中打开的网站。我基本上需要根据打开标签中的网址取消请求。我想像这样使用chrome.webRequest.onBeforeRequest

function onBeforeRequest(details) {
  var websiteAlreadyOpenInOtherTab;

  // Here i want to set `websiteAlreadyOpenInOtherTab` by using the `chrome.tabs`
  // API. It's asynchronous though and that's my problem. I cant return a value
  // from an asynchronous method call.

  if (websiteAlreadyOpenInOtherTab) {
    return { cancel: true };
  }
}

chrome.webRequest.onBeforeRequest.addListener(
  onBeforeRequest,
  { urls: ['<all_urls>'], types: ['main_frame'] },
  ['blocking']);

希望您在上面的代码中看到我的困境。我需要根据异步方法调用的结果返回一个对象。是否有可能实现这一目标?

1 个答案:

答案 0 :(得分:6)

也许 您可以通过跟踪标签网址来解决问题?:

  1. 当应用启动时,使用chrome.tabs.query
  2. 获取所有打开的标签网址
  3. 订阅chrome.tabs.onUpdatedchrome.tabs.onRemoved,并在网址发生变化时添加/删除/更新。
  4. 某种基于documentation的代码示例:

    var tabUrlHandler = (function() {
       // All opened urls
       var urls = {},
    
       queryTabsCallback = function(allTabs) {
          allTabs && allTabs.forEach(function(tab) {
              urls[tab.id] = tab.url;
          });
       },
    
       updateTabCallback = function(tabId, changeinfo, tab) {
           urls[tabId] = tab.url;
       },
    
       removeTabCallback = function(tabId, removeinfo) {
           delete urls[tabId]; 
       };
    
       // init
       chrome.tabs.query({ active: true }, queryTabsCallback);
       chrome.tabs.onUpdated.addListener(updateTabCallback);
       chrome.tabs.onRemoved.addListener(removeTabCallback);
    
       return {
         contains: function(url) {
            for (var urlId in urls) {
               if (urls[urlId] == url) {
                  return true;
               }
            }
    
            return false;
         }
       };
    
    }());
    

    现在,您应该可以直接在tabUrlHandler

    中询问onBeforeRequestMethod
    function onBeforeRequest(details) {
      var websiteAlreadyOpenInOtherTab = tabUrlHandler.contains(details.url);
    
      if (websiteAlreadyOpenInOtherTab) {
        return { cancel: true };
      }
    }