【问题标题】:How to make http request with nested loop如何使用嵌套循环发出 http 请求
【发布时间】:2018-03-23 03:28:22
【问题描述】:

在我的应用程序中,我必须在嵌套循环中发送 HTTP 请求,如下所示:

for(let i=1;i<Names.length;i++) {
    for(let k=1;k<Data.lenght;k++) {
        let url = hostPath + "/"+Names[i] + "/" + Data[i];
        this.http.get(url);
    }
}

我已经按照下面描述的方式完成了上述要求:

for(let i=1;i<Names.length;i++) {
    Observable.from(Data).ConcatMap((data) => {
        let url = hostPath + "/" + Names[i] + "/" + data;
        this.http.get(url);
    }).subscribe(() => {})
}

我想保持关于Names 数组(外循环)的正确顺序,但可以为Data 数组(内循环)发送并行请求。我对 Angular 很陌生,有没有其他方法可以做到这一点?

【问题讨论】:

  • 最好收集您需要执行请求的所有数据,然后用它发出一个请求
  • @DanilGholtsman 有什么建议吗?
  • 您的意思是按顺序运行来自Names 的所有迭代请求,并同时运行来自Data 的给定名称的所有迭代请求吗?
  • @GhassenLouhaichi 是的,正确的。
  • @HardRocker 好吧,您需要服务器端控制器,它可以处理您的名称数组和绑定数据(或对象数组看起来像 requestDataList = [ { name:"HardRocker", data: "somedata"}, {name:"Ghassen", data:"somedata"}, ... , {}]

标签: angular rxjs angular2-template


【解决方案1】:

您可以这样做,一个小问题是您需要使用defaultIfEmpty 处理空数组。以下代码也可以处理:

let allData$ = Names.map(name => Observable.forkJoin(
    Data.map(d => {
        const url = hostPath + '/' + name + '/' + d;
        return this.http.get(url);
    })).defaultIfEmpty([]);
);

Observable.forkJoin(allData$).defaultIfEmpty([]).subscribe();  
// You will get data in same order here

【讨论】:

  • 面临一个问题,当任何中间请求失败时,后续请求都会被取消。如何避免它。我没有添加“defaultIfEmpty([]);”因为它显示错误,因为方法不适用于 Observable。我的应用程序是 Angular 2application。
  • 这很容易处理,您可以在 get 调用中放置一个 catch 并在那里处理错误。例如这一行返回 this.http.get(url).catch(error => Observable.of(undefined)).
  • 实际上我试图将空数组的 Observable 作为 catch(error => Observable.of([])) 返回,这对我有用。如果我返回未定义的 observable 有什么区别?
  • 但是我面临的主要问题是随着请求数量的增加,最多达到 1500,它因 ERR 失败:无法加载资源:内存不足。
  • 无论未定义数组还是空数组都可以,您可以返回对您更有意义的值。
【解决方案2】:

实现目标的一个很好的工具是 JavaScript 异步函数。提议的解决方案提出了两个功能:第一个并行发送Data 承诺,第二个使用并行Data 顺序发送Names 承诺:

/**
 * Sends the Data promises in parallel and returns the promise
 * 
 * @param {string} param the name from the Names array
 * @param {array} array the Data array
 * @returns {promise}
 */
function processParallel(param, array) {
    return Promise.all(array.map((element) => {
        // make sure to call $http and hostPath correctly here because of
        // the function scope change
        let url = `${hostPath}/${param}/${element}`;
        return $http.get(url);
    }));
}

/**
 * Sends the Names promises sequentially
 * 
 * @param {array} firstArray the Names array
 * @param {array} secondArray the Data array
 */
async function processSequential(firstArray, secondArray) {
    for (let i = 0; i < firstArray.length; i++) {
        await processParallel(firstArray[i], secondArray);
    };
}

您可以这样称呼它们:

processSequential(Names, Data);

您可以在这个简化示例中测试此解决方案:

const hostPath = '/home';
function processParallel(param, array) {
    return Promise.all(array.map((element) => {
        let url = `${hostPath}/${param}/${element}`;
        return new Promise((resolve) => {
            setTimeout(() => {
                console.log(url);
                resolve();
            }, 500);
        });
    }));
}
async function processSequential(firstArray, secondArray) {
    for (let i = 0; i < firstArray.length; i++) {
        await processParallel(firstArray[i], secondArray);
    };
}
processSequential(['John', 'Sarra', 'Marie'], ['1', '2', '3']);

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-24
    • 2020-09-13
    • 2019-07-21
    • 1970-01-01
    • 2019-10-20
    • 1970-01-01
    • 2014-02-14
    • 1970-01-01
    相关资源
    最近更新 更多