老派递归Angluar 19

问题描述 投票:0回答:1

我有一个递归 JavaScript(我的脑筋急转弯逻辑),我在 Angular 19 中使用它从 Youtube 中提取数据。 该脚本正在运行,只是我想知道这应该是一个更好的方法,因为这是我以前的学校 JavaScript。 谢谢您的任何建议。

public getSeriesList() {
  this.record.webTubeSeries = [];
  this._seqNum = 0;
  this.getUrlYouTube()
  .pipe(first())
    .subscribe({
      next: (res: any) => {
        this.parseVideoList(res["items"]);
        if (res['nextPageToken']) {
          let repeatGetNextVideoPage = (_token: string) => {
            this.getNextVideoPage(_token)
              .subscribe(
                (result: any) => {
                  this.parseVideoList(result["items"]);
                  if (result["nextPageToken"]) {
                    repeatGetNextVideoPage(result["nextPageToken"]);
                  }
                }
              ),
              (err: any) => {
                console.log("HTTP Error", err.message)
              }
          }
          repeatGetNextVideoPage(res["nextPageToken"]);
        }
      }
    }
  );
}
private getNextVideoPage(_token: string) {
  let url = (this.urlYouTube + this.videoListId + '&pageToken=' + _token);
  return this.http.get(url);
}
private parseVideoList(result: any) {
  for (let v of result) {
    var item = new WebtubeSeries;
    item.videoTitle = v.snippet.title;
    item.videoId = v.snippet.resourceId.videoId;
    if (v.snippet.thumbnails) {
      item.urlThumbNailDefault = v.snippet.thumbnails.default.url;
      item.urlThumbNailMedium = v.snippet.thumbnails.medium.url;
      item.urlThumbNailHigh = v.snippet.thumbnails.high.url;
      item.widthDefault = v.snippet.thumbnails.default.width.toString();
      item.heightDefault = v.snippet.thumbnails.default.height.toString();

      item.widthMedium = v.snippet.thumbnails.medium.width.toString();
      item.heightMedium = v.snippet.thumbnails.medium.height.toString()

      item.widthHigh = v.snippet.thumbnails.high.width.toString()
      item.heightHigh = v.snippet.thumbnails.high.height.toString();
      item.seqNumber = this._seqNum++;
      //item.id = item.seqNumber;
      this.record.webTubeSeries.push(item);
    }
  }
}

谢谢。

javascript angular typescript rxjs angular19
1个回答
0
投票

在 Angular19 中,他们引入了

resource
rxResource
,可用于基于输入信号的数据处理。我建议使用
rxResource
这种方法,因为我们可以利用 rxjs 来执行递归。

首先我们在类构造函数中定义类逻辑的构造。

export class WebtubeSeries {
  videoTitle: any;
  urlThumbNailDefault: any;
  urlThumbNailMedium: any;
  videoId: any;
  urlThumbNailHigh: any;
  widthDefault: any;
  heightDefault: any;
  widthMedium: any;
  heightMedium: any;
  widthHigh: any;
  heightHigh: any;
  seqNumber: number;

  constructor(v: any, _seqNum = 0) {
    this.seqNumber = _seqNum;
    // this.videoTitle = v.snippet.title;
    // this.videoId = v.snippet.resourceId.videoId;
    // if (v.snippet.thumbnails) {
    //   this.urlThumbNailDefault = v.snippet.thumbnails.default.url;
    //   this.urlThumbNailMedium = v.snippet.thumbnails.medium.url;
    //   this.urlThumbNailHigh = v.snippet.thumbnails.high.url;
    //   this.widthDefault = v.snippet.thumbnails.default.width.toString();
    //   this.heightDefault = v.snippet.thumbnails.default.height.toString();

    //   this.widthMedium = v.snippet.thumbnails.medium.width.toString();
    //   this.heightMedium = v.snippet.thumbnails.medium.height.toString();

    //   this.widthHigh = v.snippet.thumbnails.high.width.toString();
    //   this.heightHigh = v.snippet.thumbnails.high.height.toString();
    //   this.seqNumber = _seqNum;
    // }
    // this.seqNumber = 0;
  }
}

然后,我们可以使用名为

rxResource
的属性定义
loader
来进行 API 调用。

在加载器内部,我们使用

expand
用于递归 API 调用,当没有下一个 API 令牌时,我们还使用
takeUntil
来停止序列。

最后,我们使用

reduce
合并结果并构建最终结果。

youtube = rxResource({
  loader: () => {
    let _seqNum = 0;
    let records: any = [];
    return this.getUrlYouTube().pipe(
      expand((response: any) =>
        this.getNextVideoPage(response['nextPageToken'])
      ),
      takeWhile((response: any) => !!response['nextPageToken'], true),
      reduce((all: any, data: any) => all.concat(data.items), []),
      map((response: any) => {
        console.log(response);
        return this.parseVideoList(response, _seqNum);
      })
    );
  },
});

完整代码:

import { Component } from '@angular/core';
import { rxResource } from '@angular/core/rxjs-interop';
import { bootstrapApplication } from '@angular/platform-browser';
import { of, first, EMPTY, expand, takeWhile, tap, reduce, map } from 'rxjs';
import { CommonModule } from '@angular/common';

export class WebtubeSeries {
  videoTitle: any;
  urlThumbNailDefault: any;
  urlThumbNailMedium: any;
  videoId: any;
  urlThumbNailHigh: any;
  widthDefault: any;
  heightDefault: any;
  widthMedium: any;
  heightMedium: any;
  widthHigh: any;
  heightHigh: any;
  seqNumber: number;

  constructor(v: any, _seqNum = 0) {
    this.seqNumber = _seqNum;
    // this.videoTitle = v.snippet.title;
    // this.videoId = v.snippet.resourceId.videoId;
    // if (v.snippet.thumbnails) {
    //   this.urlThumbNailDefault = v.snippet.thumbnails.default.url;
    //   this.urlThumbNailMedium = v.snippet.thumbnails.medium.url;
    //   this.urlThumbNailHigh = v.snippet.thumbnails.high.url;
    //   this.widthDefault = v.snippet.thumbnails.default.width.toString();
    //   this.heightDefault = v.snippet.thumbnails.default.height.toString();

    //   this.widthMedium = v.snippet.thumbnails.medium.width.toString();
    //   this.heightMedium = v.snippet.thumbnails.medium.height.toString();

    //   this.widthHigh = v.snippet.thumbnails.high.width.toString();
    //   this.heightHigh = v.snippet.thumbnails.high.height.toString();
    //   this.seqNumber = _seqNum;
    // }
    // this.seqNumber = 0;
  }
}

@Component({
  selector: 'app-root',
  imports: [CommonModule],
  template: `
    {{youtube.value() | json}}
  `,
})
export class App {
  a = 0;
  record: any = {
    webTubeSeries: [],
  };
  getUrlYouTube() {
    this.a++;
    const randon = Math.random();
    return of({
      items: [0, 0, 0, 0, 0],
      nextPageToken: randon,
    });
  }
  youtube = rxResource({
    loader: () => {
      let _seqNum = 0;
      let records: any = [];
      return this.getUrlYouTube().pipe(
        expand((response: any) =>
          this.getNextVideoPage(response['nextPageToken'])
        ),
        takeWhile((response: any) => !!response['nextPageToken'], true),
        reduce((all: any, data: any) => all.concat(data.items), []),
        map((response: any) => {
          console.log(response);
          return this.parseVideoList(response, _seqNum);
        })
      );
    },
  });

  private parseVideoList(response: any, _seqNum: number) {
    const result = [];
    for (let v of response) {
      console.log(v);
      _seqNum++;
      // if (v.snippet.thumbnails) {
      result.push(new WebtubeSeries(v, _seqNum));
      // }
    }
    return result;
  }

  private getNextVideoPage(_token: string) {
    this.a++;
    const randon = Math.random();
    return of({
      items: [1, 2, 3, 4, 5],
      nextPageToken: this.a > 10 ? null : randon,
    });
    // let url = this.urlYouTube + this.videoListId + '&pageToken=' + _token;
    // return this.http.get(url);
  }
}

bootstrapApplication(App);

Stackblitz 演示

© www.soinside.com 2019 - 2024. All rights reserved.