【问题标题】:RxJs: Sequence of Web Request. What's a better solution than mine?RxJs:Web 请求序列。有什么比我更好的解决方案?
【发布时间】:2017-03-20 07:08:57
【问题描述】:

我有一个包含 N 个(整数)url 的数组。我想发出网络请求。

要求

  1. 更新状态:我们开始发出网络请求
  2. 请求一个接一个
  3. 在每个 Web 请求之前,我们都会更新我们要调用哪个 URL 的状态。
  4. 更新状态:完成(收到所有网址后)

我想发出以下事件

  • 从网址开始
  • Emit: String: Staring web requests

循环开始(网址应该一个接一个地加载,而不是一次全部加载。数据一收到就发出)

  • Emit: String: 加载 url N[i]
  • Emit: Object: url N[i] 的数据

循环结束

  • 发射:字符串:完成

以下是我的解决方案。我正在寻找更好的解决方案

https://jsbin.com/kotizid/edit?html,js,console

//Fake Webrequest. Returns a promise
function fakeWebrequest(url){
    return new Promise(function(resolve){
        console.log('Making Web request for: '+url);
        setTimeout(function(){
          resolve('RESPONSE: of: '+ url);
        },500);
    });
}


//Urls lists
//null added at end to indicate end. Its a hack
let urls$ = Rx.Observable.of(['url 1','url 2',null]);


//Status Update
let status1$= urls$.map(()=>'Start downloading...')

//Queue
let queue$ =  urls$.flatMap((url)=>url)
              .concatMap((url)=>{
                    if(url==null){
                        return Rx.Observable.of(null)
                    }
                    let status$= Rx.Observable.of(`Loading ${url}`);
                    let promise$= Rx.Observable.fromPromise(fakeWebrequest(url))
                    return status$.merge(promise$);
              })

let finalSeq$ = status1$.merge(queue$);



finalSeq$.subscribe(function(res){
    if(res==null){
        //End
    }else{
        console.log(res);
    }    
})

我的代码有问题

  1. 在url末尾添加了null
  2. 订阅事件必须处理不同类型的数据,这意味着我必须添加 ifs 来猜测触发了哪个事件。例如,如果订阅中的 res 是字符串,则它必须是状态。如果它的空序列必须已经结束。

我正在寻找更好的解决方案。请提出建议。

【问题讨论】:

    标签: rxjs rxjs5


    【解决方案1】:

    假设我正确理解了您的问题,可能的解决方案是:

    const { Observable } = Rx;
    
    // fake http request
    function fakeWebrequest(url){
        return Observable
            .of(`RESPONSE: of: ${url}`)
            .delay(500);
    }
    
    
    const urls = ['url 1','url 2'];
    
    let requests$ = Observable.from(urls.map(url => fakeWebrequest(url)));
    
    requests$
      .concatAll()
      .subscribe(
        // next
        res => {
          console.log(res)
        },
        // error
        _ => {},
        // complete
        _ => console.log('All requests ended')
      );
    

    输出如下:

    RESPONSE: of: url 1
    RESPONSE: of: url 2
    All requests ended
    

    http://jsbin.com/muquzuwexa/edit?js,console

    【讨论】:

    • 它有两个问题。 a> 一次发出所有网络请求。 b> 我们如何在发出网络请求之前发出状态
    • 它不会一次发出所有请求。尝试在延迟之前将 console.log 放在 do 中。它只是创建一个冷的可观察对象,不会立即触发。你说的状态是什么意思?如果您想在每个请求之前记录诸如“请求获取 ${url} 的请求已启动”之类的内容,请将其放入 do 和 console.log 之前.of(RESPONSE: of: ${url})跨度>
    • 在您的fakeWebrequest 中放置一个控制台,您会发现它会立即被调用。 status 我的意思是在发出每个 Web 请求之前发出带有字符串的事件。您可以查看我的 JSBIN 链接,并尝试模拟相同的行为。 JSBIn 现在下线了,所以你可能需要增重。
    • 该函数立即被调用:YES。但它只是返回一个可观察的。真的,我可以想象你将拥有http.get('...') 或帖子、放置等,而不是Observable.of,对吗?那么 angular 使用 observable 并且在您订阅它之前不会触发您的请求。关键是,你“准备”了请求,而不是触发它们。
    • 是的,函数被调用,但可观察的“body”不会立即调用,而是按顺序为每个 url 调用 - 一切正常 :) 。这是我的情况:let requests = this.meta.gallery2DImageFiles.map( photo => { return this.interiorService.uploadGallery2DImage(interiorId, photo.file); // here angular http observable is created } ); requests.push(new Observable( photo => { ... })); req.concatAll().subscribe(...)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-24
    • 2013-10-22
    • 1970-01-01
    • 2017-09-13
    • 2011-11-16
    • 2022-06-28
    • 1970-01-01
    相关资源
    最近更新 更多