AngularJs:在内部调用$http或$resource时,让方法同步返回

AngularJs: Have method return synchronously when it calls $http or $resource internally

本文关键字:方法 返回 同步 在内部 调用 http AngularJs resource      更新时间:2023-09-26

有没有一种方法可以等待promise,这样您就可以从中获得实际结果并返回,而不是返回promise本身?我在想一些类似于C#await关键字如何处理Tasks的东西。

下面是一个例子,说明为什么我希望有一个像canAccess()这样的方法,它返回true或false,而不是promise,这样它就可以在if语句中使用。方法canAccess()将使用$http或$resource进行AJAX调用,然后以某种方式等待promise得到解决。

看起来像这样:

$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基本上是一个单线程的野兽。仔细想想,它在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的双向绑定使这变得非常容易。

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

有用的链接:

  • 官方文件
  • 如何在AngularJS中添加$resource方法的回调

你不能-angular、Q(promise)或javascript(目前)中没有任何功能可以做到这一点。

当ES7发生时(带有等待),您将

如果您使用另一个框架或transpiler(如链接的文章所建议的那样-Traceur transpiler或Spawn),您可以

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

我的方法是用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);
    };

我最近遇到了这个问题,并创建了一个名为"syncPromises"的实用程序。这基本上是通过发送我所说的"指令列表"来实现的,该列表是按顺序调用的函数数组。您需要调用first-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函数,这些函数都将按顺序发生。