【问题标题】:Race condition in Angular HTTP promisesAngular HTTP 承诺中的竞争条件
【发布时间】:2016-09-08 05:08:56
【问题描述】:

所以,我有一个小的 API 交互代码,如下所示:

function load_posts() {
  return $http
    .get('/posts')
    .then(on_success);

  function on_success(response) {
    return response.data;
  }
}

function get_posts() {
  if (blog.posts) {
    return $q.when(blog.posts);
  }

  return load_posts().then(function (posts) {
    blog.posts = posts;

    return blog.posts;
  });
}

我这样做是为了避免一直访问 API 以获得相同的结果。我有几个单独的指令和组件可能需要调用此 API 端点,但它们不需要每次都获得新的结果。但这会导致一个丑陋的竞争条件:如果两个或更多组件在 load_posts 响应到达之前调用 get_posts 方法,那么它们都会发出 API 请求。没有副作用,因为这只是一次缓存尝试,但它破坏了整个目的。

关于如何进行此操作的任何想法?

【问题讨论】:

    标签: javascript angularjs http-post angular-http


    【解决方案1】:

    $http 服务可以缓存请求。 See heredocs 以更深入地解释缓存的工作原理。

    默认的 $http 缓存在我们的数据时特别有用 不会经常改变。我们可以这样设置:

    $http({
      method: 'GET',
      url: '/api/users.json',
      cache: true
    });
    // Or, using the .get helper
    $http.get('/api/users.json', {
      cache: true
    });
    

    现在,通过 $http 向 URL 发出的每个请求 /api/users.json 将存储在默认的 $http 缓存中。关键是 $http 缓存中的这个请求是完整路径 URL。

    【讨论】:

      【解决方案2】:

      这并不是一个真正的竞争条件问题,它只是一个记忆函数的问题。您可以使用 Underscore.js 中的 memoize() 之类的东西,或者自己实现它:

      var load_posts = () => {
        const p = $http
          .get('/posts')
          .then(response => response.data);
        load_posts = () => p;
        return p;
      };
      

      【讨论】:

        【解决方案3】:

        1) 将数据检索提取到单独的“blogService”服务中;

        2) 在执行请求的服务中缓存承诺;

        3) 为所有客户端返回相同的承诺,如果您不想暴露整个响应对象,可以操作结果;

        var promise = null;
        
        function loadBlogs() {
            promise = promise || $http.get("/posts").then(function(response){return reponse.data;});
            return promise;
        }
        

        4) 然后只需调用服务方法并等待承诺在您需要的任何地方解决(控制器、指令等):

        function getPosts() {
            blogService.loadBlogs().then(function (posts) {
                vm.posts = posts;
          });
        

        【讨论】:

        • 我不想将所有内部响应数据暴露给客户。这就是获取帖子与加载帖子不同的原因。
        • 嗯,有一个微妙但重要的区别。在我的回答中,我强调承诺缓存应该在单独的服务(这将是单例)中完成,而不是直接在控制器或指令中。
        • 所以,你的代码可能只是var loadBlogs = (promise => () => promise = promise || $http.get('/posts').then(response => response.data))(null); var getPosts = () => postService.loadBlogs(posts => blog.posts = posts); ...只是说
        • 投反对票的人至少可以花点时间解释一下原因吗? @Jaromanda_X:你说的是真的,但是 1)更短并不意味着更具可读性,2)不是每个人都可以使用新的 ES 功能和/或转译器,因为项目中的不同限制(主要是政治,如果你与企业合作过,你知道我的意思)
        猜你喜欢
        • 1970-01-01
        • 2021-04-22
        • 2018-02-25
        • 2022-11-18
        • 2015-06-22
        • 2016-03-07
        • 2011-07-17
        • 2013-02-27
        • 2021-04-16
        相关资源
        最近更新 更多