$cache[$key] = empty($arr) ? NULL : $arr; return $cache[$key]; } // 门户 获取需要在频道显示的栏目主题数据 function portal_channel_thread($fid) { global $forumlist; if (empty($fid)) return NULL; $orderby = array('tid' => 1); $page = 1; // 遍历所有在频道显示内容的栏目 $category_forumlist = channel_category($fid); $arrlist = array(); $forum_tids = array(); $tidlist = array(); if ($category_forumlist) { foreach ($category_forumlist as &$_forum) { // 频道显示数据 $arrlist['list'][$_forum['fid']] = array( 'fid' => $_forum['fid'], 'name' => $_forum['name'], 'rank' => $_forum['rank'], 'type' => $_forum['type'], 'url' => $_forum['url'], 'channel_new' => $_forum['channel_new'], ); $forum_thread = thread_tid__find(array('fid' => $_forum['fid']), $orderby, $page, $_forum['channel_new'], 'tid', array('tid')); // 最新信息按栏目分组 foreach ($forum_thread as $key => $_thread) { $forum_tids[$key] = $_thread; } unset($forum_thread); } $tidlist += $forum_tids; } unset($category_forumlist); // 获取属性对应的tid集合 list($flaglist, $flagtids) = flag_thread_by_fid($fid); empty($flagtids) || $tidlist += $flagtids; unset($flagtids); // 频道置顶 $stickylist = sticky_list_thread($fid); empty($stickylist) || $tidlist += $stickylist; // 在这之前合并所有二维数组 tid值为键/array('tid值' => tid值) $tidarr = arrlist_values($tidlist, 'tid'); // 在这之前使用$tidarr = array_merge($tidarr, $arr)前合并所有一维数组 tid/array(1,2,3) if (empty($tidarr)) { $arrlist['list'] = isset($arrlist['list']) ? array_multisort_key($arrlist['list'], 'rank', FALSE, 'fid') : array(); return $arrlist; } $tidarr = array_unique($tidarr); $pagesize = count($tidarr); // 遍历获取的所有tid主题 $threadlist = well_thread_find_asc($tidarr, $pagesize); // 遍历时为升序,翻转为降序 $threadlist = array_reverse($threadlist); foreach ($threadlist as &$_thread) { // 各栏目最新内容 isset($forum_tids[$_thread['tid']]) AND $arrlist['list'][$_thread['fid']]['news'][$_thread['tid']] = $_thread; // 全站置顶内容 isset($stickylist[$_thread['tid']]) AND $arrlist['sticky'][$_thread['tid']] = $_thread; // 首页属性主题 if (!empty($flaglist)) { foreach ($flaglist as $key => $val) { if (isset($val['tids']) && in_array($_thread['tid'], $val['tids'])) { $arrlist['flaglist'][$key][array_search($_thread['tid'], $val['tids'])] = $_thread; ksort($arrlist['flaglist'][$key]); $arrlist['flag'][$_thread['tid']] = $_thread; } } } } unset($threadlist); if (isset($arrlist['sticky'])) { $i = 0; foreach ($arrlist['sticky'] as &$val) { ++$i; $val['i'] = $i; } } if (isset($arrlist['flag'])) { $i = 0; foreach ($arrlist['flag'] as &$val) { ++$i; $val['i'] = $i; } } if (isset($arrlist['flaglist'])) { foreach ($arrlist['flaglist'] as &$val) { $i = 0; foreach ($val as &$v) { ++$i; $v['i'] = $i; } } } isset($arrlist['list']) AND $arrlist['list'] = array_multisort_key($arrlist['list'], 'rank', FALSE, 'fid'); return $arrlist; } ?>javascript - How to reuse angular observable across multiple components? (To avoid having to duplicate a request twice?) - Stack
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to reuse angular observable across multiple components? (To avoid having to duplicate a request twice?) - Stack

programmeradmin1浏览0评论

I have a service "MyHttpService" that includes an observable like this:

grabData() {
return this.http.get('myaddress')
                         .map((res:Response) => {return res.json()})
                         .catch((error:any) => Observable.throw(error.json().error || 'Server error')); 
}

I have 2 components. OneComponent and TwoComponent that both have "MyHttpService" injected that depend on the data returned by MyHttpService.

OneComponent loads up first. TwoComponent loads up after button click.

Within the onNgInit() of each component I have:

     this.myHttpService.grabData()
        .subscribe(
              data => {
 // do something to the data
});

Is it correct to assume that even though I have this subscribe in both components, that there are not going to be multiple HTTP requests called and that the call to "grabData()" when TwoComponent loads is the same data already pulled by OneComponent? Or will it make a new call? I want to avoid multiple HTTP requests to the same endpoint. If multiple calls are being made each time a component that has this is called, what is the best way to handle this so that I don't have multiple calls to the service each time I initialize TwoComponent?

I have a service "MyHttpService" that includes an observable like this:

grabData() {
return this.http.get('myaddress')
                         .map((res:Response) => {return res.json()})
                         .catch((error:any) => Observable.throw(error.json().error || 'Server error')); 
}

I have 2 components. OneComponent and TwoComponent that both have "MyHttpService" injected that depend on the data returned by MyHttpService.

OneComponent loads up first. TwoComponent loads up after button click.

Within the onNgInit() of each component I have:

     this.myHttpService.grabData()
        .subscribe(
              data => {
 // do something to the data
});

Is it correct to assume that even though I have this subscribe in both components, that there are not going to be multiple HTTP requests called and that the call to "grabData()" when TwoComponent loads is the same data already pulled by OneComponent? Or will it make a new call? I want to avoid multiple HTTP requests to the same endpoint. If multiple calls are being made each time a component that has this is called, what is the best way to handle this so that I don't have multiple calls to the service each time I initialize TwoComponent?

Share Improve this question asked Jul 19, 2017 at 21:44 RolandoRolando 62.6k103 gold badges278 silver badges422 bronze badges 0
Add a comment  | 

3 Answers 3

Reset to default 12

The Http service returns what are known as cold observables. This means that every new subscriber will cause the work for that observable to be done again, which in the case of Http, is to make the network request.

Luckily, there are mechanisms in RxJS to allow you to publish (a.k.a multicast or multiplex) an observable so that multiple subscribers do not cause multiple requests.

The way I usually do this for Http is with the .publishReplay(1).refCount() pair of operators. The .publishReplay(1) means that later subscribers get the most recent successful value straight away, without making another request. .refCount() means that the first subscriber makes the request, and the last one to unsubscribe cleans up the original Http observable.

Version 5.4.0 added a shortcut for these two operators, which is .shareReplay(1).

Just whack either version on the end of the line in your grabData() service method, and it should work like you desire.

grabData() {
    return this.http.get('myaddress')
                    .map((res:Response) => {return res.json()})
                    .catch((error:any) => 
                         Observable.throw(error.json().error || 'Server error'))
                    .publishReplay(1).refCount(); // or .shareReplay(1)
}

You can use the share operator to make an observable multicast. This is also relevant within a single component as multiple async bindings to the same osbervable will cause multiple requests to be made. There is a good ng-conf talk here that covers the issue.

import 'rxjs/add/operator/share';

grabData() {
  return this.http.get('myaddress')
                  .map((res:Response) => {return res.json()})
                  .catch((error:any) => Observable.throw(error.json().error || 'Server error'))
                  .share(); 
}

When you subscribe in TwoComponent it will cause the http request to be sent again. The best way for you to prevent multiple http calls would be to store the response data in your service and before the http call, check if you have already saved the data and if so just directly returning the data.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论