Angular 9内部订阅

时间:2020-06-21 14:23:18

标签: angular rxjs6

我正在使用Angular 9和rxjs 6,并且我正在尝试获取节点列表:

NodeService.ts

class EventListener extends StatefulWidget { @override _EventListenerState createState() => _EventListenerState(); } class _EventListenerState extends State<EventListener> { Offset offset = Offset(0, 0); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("EventListener"), ), body: Stack( children: <Widget>[ SingleChildScrollView( child: Column( children: <Widget>[ Container( color: Colors.red, height: 200, ), Container( color: Colors.teal, height: 300, ), Container( color: Colors.orange, height: 400, ) ], ), ), Container( color: Colors.cyan, width: double.infinity, height: 400, alignment: Alignment.center, child: SizedBox( width: 100, height: 100, child: Transform.translate( offset: offset, child: FlatButton( color: Colors.orange, onPressed: () { setState(() { offset += Offset(50, 50); }); print('click !'); }, child: Text("translate"), ), ), ), ) ], ), ); } }

节点实体:



      short _type;    // file type
      short _size;
    int _reserved;
       int _offset;

        int  _info_size;
        int _width;
        int _height;

        short _planes;
        short _bpp;

        int _compression;
        int _imagesize;

        int _xresolution;
        int _yresolution;

        int _colours;
        int _impcolours;


nodes.component.ts:

public getList(): Observable<Nodes[]> { return this.http.get<Nodes[]>(URL); }

=>默认情况下,node.site = null,所以我使用node.site_id在subscription方法中获取完整的“ Site”对象。 但是我几乎有6000次呼叫“ siteService.getSiteById()”,并且出现类似错误的消息:资源不足。

您有更好的方法吗

谢谢

2 个答案:

答案 0 :(得分:0)

如果您需要进行6000个单独的HTTP调用,则可能必须修改后端以在单个请求中返回所有信息。同时,您可以尝试使用带有switchMapconcatMap函数的from的RxJS of运算符来顺序执行请求。

import { of, from } from 'rxjs';
import { switchMap, concatMap, finalize } from 'rxjs/operators';

public getAllNodes() {
  this.dataSource.data = [];
  let sites = [];
  this.nodeService.getList().pipe(
    switchMap(nodes => {
      let requests = [];
      this.dataSource.data = nodes;
      nodes.forEach(node => requests.push(this.siteService.getSiteById(node.site_id)));
      return from(requests);
    }),
    concatMap(request => of(request)),
    finalize(() => {
      this.dataSource.data.forEach((node, index) => node.site = sites[index]);
    })
  ).subscribe(
    site => {
      sites.push(site);
    },
    error => {
      // handle error
    }
  );
}

现在将依次执行6000个请求,所以它太慢了。

更新:使用mergeMap

的并发请求

如Will Alexander在评论中所建议,您可以使用RxJS mergeMap运算符来处理并发请求。但我建议您将其设置为小于6,因为大多数浏览器对同时发送到唯一域的请求数量都有严格的限制。

因此您可以替换

concatMap(request => of(request))

使用

mergeMap(request => of(request), null, 5)   // <-- 5 concurrent requests

答案 1 :(得分:0)

遵循以下原则:

public getAllNodes() {
  return this.nodeService.getList().pipe(

    // emit all elements of the array separately
    map(nodes => from(nodes)),
    
    // subscribe to each Observable in turn
    // allow 5 concurrent requests
    mergeMap(node$ => node$, null, 5).pipe(

      // for each node, get the corresponding site, and emit the full object
      concatMap(
        node => this.siteService.getSiteById(node.site_id),
        (node, site) => { ...node, site })
    ),

    // when Observable completes, emit all emissions as an Array
    toArray()
  );
}

更新:考虑到getList()返回Observables的事实