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

问题描述:

我知道等待异步方法很笨,one should use callbacks instead。但是如果第三方API迫使你同步呢?如何等待异步方法的回调返回值?

我正在开发一款Chrome扩展程序,可防止用户访问已在另一个选项卡中打开的网站。我基本上需要取消基于打开标签中的URL的请求。我想用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

不,这不是:-( – Bergi 2013-02-28 00:10:33

+0

当你调用'onBeforeRequest'时,你不能听所有'chrome.tabs'的变化,并且'websiteAlreadyOpenInOtherTab'已经包含正确的值吗? – Bergi 2013-02-28 00:12:20

+0

我觉得你很亲切不正确地解决问题。首先,如果事情需要是异步的,那么不需要同步响应,而是在模型中工作,并使用异步回调,如果您决定选项卡不应该打开,则关闭它。有一个单独的API函数来关闭标签,你不需要仅仅从onbeforerequest返回false ... – davin 2013-02-28 00:23:31

也许您可以通过跟踪标签的网址?:通过使用chrome.tabs.query

  • 解决问题

    1. 当应用程序启动后,得到所有打开的标签网址订阅chrome.tabs.onUpdatedchrome.tabs.onRemoved并在更改时添加/删除/更新URL。

    某种类型的代码示例的基础上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; 
        } 
        }; 
    
    }()); 
    

    现在你应该可以直接问tabUrlHandleronBeforeRequestMethod

    function onBeforeRequest(details) { 
        var websiteAlreadyOpenInOtherTab = tabUrlHandler.contains(details.url); 
    
        if (websiteAlreadyOpenInOtherTab) { 
        return { cancel: true }; 
        } 
    } 
    
  • +0

    太棒了!感谢一个非常详细的例子,这是我必须采取的路线。 – Sven 2013-02-28 08:01:58

    +0

    谢谢!为一个有趣的问题+1! :) – nekman 2013-02-28 09:24:56