【问题标题】:AngularJs: Have method return synchronously when it calls $http or $resource internallyAngularJs:让方法在内部调用 $http 或 $resource 时同步返回
【发布时间】:2013-11-25 03:08:23
【问题描述】:

有没有办法等待一个承诺,以便您可以从中获得实际结果并返回它而不是返回承诺本身?我正在考虑类似于 C# await 关键字如何与任务一起使用的东西。

这是一个示例,说明为什么我想要一个像 canAccess() 这样返回 true 或 false 而不是 Promise 的方法,以便可以在 if 语句中使用它。方法 canAccess() 将使用 $http 或 $resource 进行 AJAX 调用,然后以某种方式等待承诺得到解决。

看起来像这样:

$scope.canAccess = function(page) {
    var resource = $resource('/api/access/:page');
    var result = resource.get({page: page});

    // how to await this and not return the promise but the real value
    return result.canAccess;
}

有没有办法做到这一点?

【问题讨论】:

    标签: javascript angularjs


    【解决方案1】:

    一般来说这是个坏主意。让我来告诉你为什么。浏览器中的 JavaScript 基本上是一个单线程的野兽。想想看,它在 Node.js 中也是单线程的。因此,您在开始等待远程请求成功或失败时所做的任何不“返回”的操作都可能涉及某种循环以延迟请求后代码的执行。像这样的:

    var semaphore = false;
    var superImportantInfo = null;
    
    // Make a remote request.
    $http.get('some wonderful URL for a service').then(function (results) {
      superImportantInfo = results;
    
      semaphore = true;
    });
    
    while (!semaphore) {
      // We're just waiting.
    }
    
    // Code we're trying to avoid running until we know the results of the URL call.
    console.log('The thing I want for lunch is... " + superImportantInfo);
    

    但是,如果您在浏览器中尝试这样做并且调用需要很长时间,浏览器会认为您的 JavaScript 代码卡在一个循环中,并在用户面前弹出一条消息,让用户有机会停止您的代码。因此 JavaScript 的结构是这样的:

    // Make a remote request.
    $http.get('some wonderful URL for a service').then(function (results) {
      // Code we're trying to avoid running until we know the results of the URL call.
      console.log('The thing I want for lunch is... " + results);
    });
    
    // Continue on with other code which does not need the super important info or 
    // simply end our JavaScript altogether. The code inside the callback will be 
    // executed later.
    

    这个想法是回调中的代码将在服务调用返回时由事件触发。因为事件驱动是 JavaScript 喜欢的方式。 JavaScript 中的计时器是事件,用户操作是事件,发送和接收数据的 HTTP/HTTPS 调用也会生成事件。您需要构建代码以在这些事件发生时对其做出响应。

    在远程服务调用返回并且它可能发现它确实是真的之前,你能不能构造你的代码,让它认为 canAccess 是假的?我一直在 AngularJS 代码中这样做,我不知道应该向用户显示的最终权限集是什么,因为我还没有收到它们,或者我还没有收到要显示在第一页。我有默认显示,直到真实数据返回,然后页面根据新数据调整为新形式。 AngularJS 的双向绑定让这非常容易。

    【讨论】:

    • 是的,你提出了一些非常好的观点。我绝对可以用这种方式构建我的代码,而且应该不会太难。我更好奇是否有办法做到这一点,但你已经说服我不要这样做了。我喜欢默认设置为无访问权限,然后让双向绑定处理其余部分的想法。谢谢。
    • 在第一个例子中,我认为while 语句的条件永远不会是真的。这是因为它将同步运行并阻止 HTTP 请求发生。
    • 在某些情况下您真的想等待,我认为这是最初的问题。这个答案并没有真正回答这个问题。
    • 尽管我同意答案中的观点,但我不喜欢“你甚至不应该这样做,做其他事情”的答案,因为他们没有回答这个问题。回答问题!
    • 谢谢!有时你真的需要等待(在我的情况下,我需要来自 Angular 的 jQuery 插件中的数据..)
    【解决方案2】:

    使用 .get() 回调函数确保您获得已解析的资源。

    有用的链接:

    【讨论】:

      【解决方案3】:

      我的方法是使用 OLD javascript 对象创建一个函数,如下所示:

      var globalRequestSync = function (pUrl, pVerbo, pCallBack) {
      
              httpRequest = new XMLHttpRequest();
              httpRequest.onreadystatechange = function () {
      
                  if (httpRequest.readyState == 4 && httpRequest.status == 200) {
                      pCallBack(httpRequest.responseText);
                  }
              }
              httpRequest.open(pVerbo, pUrl, false);
              httpRequest.send(null);
      
          };
      

      【讨论】:

        【解决方案4】:

        您不能 - angularQ(承诺)或 javascript(目前)中没有任何功能可以做到这一点。

        你会ES7发生时(await)。

        如果您使用其他框架或转译器(如链接文章中的建议 - Traceur 转译器或 Spawn),则可以

        如果你推出自己的实现,你可以!

        【讨论】:

          【解决方案5】:

          我最近遇到了这个问题,并制作了一个名为“syncPromises”的实用程序。这基本上是通过发送我所谓的“指令列表”来工作的,它是按顺序调用的函数数组。您需要调用第一个 then() 来解决问题,当响应返回指令列表中的下一项时动态附加一个新的 .then() ,因此您需要跟踪索引。

          // instructionList is array.
          function syncPromises (instructionList) {
            var i = 0,
              defer = $q.defer();
          
            function next(i) {
          
              // Each function in the instructionList needs to return a promise
              instructionList[i].then(function () {
                var test = instructionList[i++];
                if(test) {
                  next(i);
                }
              });
            }
          
            next(i);
          
            return defer.promise;
          }

          我发现这给了我们最大的灵活性。 您可以自动推送操作等以构建指令列表,您还可以在被调用函数中附加尽可能多的 .then() 响应处理程序。您还可以链接多个按顺序发生的 syncPromises 函数。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2013-08-29
            • 1970-01-01
            • 2015-11-21
            • 2012-11-30
            • 1970-01-01
            • 2015-11-22
            • 1970-01-01
            相关资源
            最近更新 更多