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

Posted

技术标签:

【中文标题】如何等待异步方法的回调返回值?【英文标题】:How to wait for an asynchronous method's callback return value? 【发布时间】:2013-02-14 00:31:22 【问题描述】:

我知道等待异步方法是愚蠢的,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']);

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

【问题讨论】:

onBeforeRequest 被调用时,你不能听所有chrome.tabs 的变化并让websiteAlreadyOpenInOtherTab 已经包含正确的值吗? 我认为您处理问题的方法不正确。首先,如果事情需要异步,那么不需要同步响应,而是在模型中工作并使用异步回调,如果您决定不应该打开选项卡,则关闭它。有一个单独的 API 函数来关闭选项卡,您不需要仅从 onbeforerequest 中返回 false... @davin:但这会导致“标签闪烁”之类的,完全不同的行为(并且会发送请求) @Bergi 是的,差不多。 onBeforeRequest 不能包含正确的值(因为在调用 onBeforeRequest 之前我不会知道它。但我可以维护某种了解打开选项卡的结构。这是一个走动好吧。@davin +1关于@Bergi的论点。在我的用例中发送请求并关闭选项卡是不可接受的。该请求应该被取消。但无论如何感谢您的建议。:) 【参考方案1】:

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

    应用启动时,使用chrome.tabs.query获取所有打开的标签页网址 订阅 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;
     
   ;

());

现在您应该可以直接在您的onBeforeRequestMethod 中询问tabUrlHandler

function onBeforeRequest(details) 
  var websiteAlreadyOpenInOtherTab = tabUrlHandler.contains(details.url);

  if (websiteAlreadyOpenInOtherTab) 
    return  cancel: true ;
  

【讨论】:

太棒了!感谢您提供非常详细的示例,这是我必须采取的路线。 谢谢! +1 一个有趣的问题! :)

以上是关于如何等待异步方法的回调返回值?的主要内容,如果未能解决你的问题,请参考以下文章

如何等待值然后返回一个对象

如何获取AsyncTask 异步处理的返回值

异步/等待不等待返回值

在异步函数内部,从回调函数返回值返回 Promise(undefined) [重复]

在异步函数内部,从回调函数返回值返回 Promise(undefined) [重复]

如何在异步等待函数中返回值?