如何处理服务迟到的数据? [英] How to handle data comes late from service?

查看:117
本文介绍了如何处理服务迟到的数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的有角度的应用程序中,我需要将数据存储到在初始阶段为空的数组.

In my angular application, i am in the need to store the data to an array which will be empty at initial stage.

示例:

someFunction() {

 let array = [];

 console.log("step 1");

 this.service.getRest(url).subscribe(result => { 

   result.data.forEach(element => {

   console.log("step 2");

    array.push(element); // Pushing all the objects comes from res.data     

   });

   console.log("step 3");

 });

   console.log("step 4");

}

在这里,我已按步骤顺序列出了console.log().

Here i have listed down the console.log() with step order.

调用函数时的顺序

第1步 第4步 第2步 步骤3

Step 1 Step 4 Step 2 Step 3

在第1步之后,第4步调用,然后在第2步之后.因此,如果我console.log(array)代替第4步,它将再次给出空数组.

Here after step 1, the step 4 calls and later the step 2.. So if i console.log(array) in place of step 4, it gives again empty array..

但是它代替了step 2 and 3给出了值.从服务中出来的值是空的.

But in place of step 2 and 3 it gives value.. Coming out of the service the value is empty.

因此,我总是在array中得到空值.

And hence always i am getting empty value in the array.

即使有一段时间的服务调用和响应返回,也请帮助我将数据存储到变量中.

Kindly help me to store the data to the variable even though there is a time duration of service call and response coming back.

尝试修改代码很长时间,但无法正常工作.

Tried by modifying code for a long time but couldn't get it worked..

修改:

我在下面提供了我目前正在使用的实时应用程序 stackblitz 链接

I have given below the real time application i am currently working with stackblitz link https://stackblitz.com/edit/angular-x4a5b6-ng8m4z

在此演示中,请参见文件 https://stackblitz.com/edit/angular-x4a5b6-ng8m4z?file=src%2Fapp%2Fquestion.service.ts

Here in this demo see the file https://stackblitz.com/edit/angular-x4a5b6-ng8m4z?file=src%2Fapp%2Fquestion.service.ts

我在哪里使用服务电话.如果我放async getQuestions() {},则给出questions.forEach of undefined

Where i am using the service call.. If i put async getQuestions() {}, it is giving error of questions.forEach of undefined

service.ts

    jsonData: any = [
    {
      "elementType": "textbox",
      "class": "col-12 col-md-4 col-sm-12",
      "key": "project_name",
      "label": "Project Name",
      "type": "text",
      "value": "",
      "required": false,
      "minlength": 3,
      "maxlength": 20,
      "order": 1
    },
    {
      "elementType": "textbox",
      "class": "col-12 col-md-4 col-sm-12",
      "key": "project_desc",
      "label": "Project Description",
      "type": "text",
      "value": "",
      "required": true,
      "order": 2
    },
    {
      "elementType": "dropdown",
      "key": 'project',
      "label": 'Project Rating',
      "options": [],
      "order": 3
    }
  ];

  getQuestions() {

    let questions: any = [];

    //In the above JSON having empty values in "options": [],

    this.jsonData.forEach(element => {
      if (element.elementType === 'textbox') {
        questions.push(new TextboxQuestion(element));
      } else if (element.elementType === 'dropdown') {

        //Need to push the data that comes from service result (res.data) to the options

        questions.push(new DropdownQuestion(element));

        console.log("step 1");

      //The service which  i call in real time..

        // return this.http.get(element.optionsUrl).subscribe(res => {

        //res.data has the following array, Using foreach pushing to elements.options.

      //   [
      //   { "key": 'average', "value": 'Average' },
      //   { "key": 'good', "value": 'Good' },
      //   { "key": 'great', "value": 'Great' }
      // ],

        // res.data.forEach(result => {
          console.log("step 2");
        //   element.options.push(result);
        // });
        // console.log(element.options) give values as the above [
      //   { "key": 'average'...
        console.log("step 3");
                // console.log(element.options) give values as the above [
      //   { "key": 'average'...
        // });
        console.log("step 4");
      //But here console.log(element.options) gives empty 
      }
    });

    return questions.sort((a, b) => a.order - b.order);
  }

推荐答案

第一步是将函数getQuestion转换为Observable.

The first step if convert your function getQuestion in an Observable.

为什么有必要?因为您需要调用this.http.get(element.optionsUrl).这是异步的(所有http.get返回均可观察到).并且您需要等待被调用完成才能获取数据.可以观察到的好处是,在订阅功能"内部您拥有数据.

Why it is necesary? Because you need call to a this.http.get(element.optionsUrl). This is asyncronous (all http.get return observable). And you need wait to the called is finished to get the data. The good of observable is that inside "subscribe function" you have the data.

因此,我们必须考虑服务返回可观察的东西,组件订阅了服务".

Therefore, we must thinking that the "services return observables, the component subscribe to the services".

好吧,让这个问题.主要问题是我们需要多次调用http.get.众所周知,对http的所有调用都是异步的,因此如何确保我们拥有所有数据(请记住,只有数据进入了subscribe函数.因为我们不想有多个subscribe-最好有没有订阅服务,我们需要使用forkJoin.ForkJoin需要一个调用数组,并返回一个结果数组.

Well, let the issue. The main problem is that we need several calls to http.get. As we know, all the calls to http are asyncronous, so how can be sure that we have all the data (remember that we only has the data into the subscribe function. As we don't want have several subscribe -the best is have no subscribe- in our service, we need use forkJoin. ForkJoin need an array of calls, and return an array of result.

因此,首先创建一个可观察数组,然后我们返回该可观察数组.等一下!我们不想返回带有选项的数组,我们想要一个可观察的问题.为此,尽管返回了observable数组,我们仍返回了使用此observable数组的对象.我在响应的底部放了一个简单的例子

So the fist is create an array of observable, then we return this array of observable. Wait a moment! we don't want return an array with the options, we want a observables of question. For this, in spite of return the array of observable, we return an object that use this array of observable. I put a simple example at bottom of the response

getQuestions():Observable<any[]> { //See that return an Observable

    let questions: any = [];

    //First we create an array of observables
    let observables:Observable<any[]>[]=[];
    this.jsonData.forEach(element => {
      if (element.elementType === 'dropdown') {
        observables.push(this.http.get(element.optionsUrl))
      }
    }
    //if only want return a forkjoin of observables we make
    //return forkJoin(observables)
    //But we want return an Observable of questions, so we use pipe(map)) to transform the response

    return forkJoin(observables).pipe(map(res=>
    {  //here we have and array like-yes is an array of array-
       //with so many element as "dowpdown" we have in question
       // res=[
       //      [{ "key": 'average', "value": 'Average' },...],
       //        [{ "key": 'car', "value": 'dog },...],
       // ],
       //as we have yet all the options, we can fullfit our questions
       let index=0;
       this.jsonData.forEach((element) => { //see that have two argument, the 
                                                  //element and the "index"
          if (element.elementType === 'textbox') {
             questions.push(new TextboxQuestion(element));
          } else if (element.elementType === 'dropdown') {
               //here we give value to element.options
               element.option=res[index];
               questions.push(new DropdownQuestion(element));
               index++;
          }
       })
       return question
    }))
 }

注意:关于如何使用"of"转换返回可观察值的函数:简单示例

NOTE: of how convert a function that return a value in observable using "of": Simple example

import { of} from 'rxjs';

getData():any
{
   let data={property:"valor"}
   return data;
}
getObservableData():Observable<any>
{
   let data={property:"observable"}
   return of(data);
}
getHttpData():Observable<any>
{
    return this.httpClient.get("myUrl");
}
//A component can be call this functions as
let data=myService.getData();
console.log(data)
//See that the call to a getHttpData is equal than the call to getObservableData
//It is the reason becaouse we can "simulate" a httpClient.get call using "of" 
myService.getObservableData().subscribe(res=>{
     console.log(res);
}
myService.getHttpData().subscribe(res=>{
     console.log(res);
}

注2:使用forkJoin和map

NOTE2: use of forkJoin and map

getData()
{
    let observables:Observables[];

    observables.push(of({property:"observable"});
    observables.push(of({property:"observable2"});

    return (forkJoin(observables).pipe(map(res=>{
        //in res we have [{property:"observable"},{property:"observable2"}]
        res.forEach((x,index)=>x.newProperty=i)
        //in res we have [{property:"observable",newProperty:0},
        //                {property:"observable2",newProperty:1}]
       }))
}

更新 还有其他方法可以做这些事情.我认为最好有一个返回完整的问题"的函数.

Update There are other way to do the things. I think is better has a function that return the fullfilled "questions".

//You have
jsonData:any=....
//So you can have a function that return an observable
jsonData:any=...
getJsonData()
{
   return of(this.jsonData)
}
//Well, what about to have a function thah return a fullFilled Data?
getFullFilledData()
{
   let observables:Observables[]=[];
   this.jsonData.forEach(element => {
      if (element.elementType === 'dropdown') {
         observables.push(this.http.get(element.optionsUrl))
      }
   })
   return forkJoin(observables).pipe(map(res=>
      let index = 0;
      this.jsonData.forEach((element) => {
      if (element.elementType === 'dropdown') {
         element.options = res[index];
         index++;
      }
   })
   return this.jsonData
   }))
}

通过这种方式,您无需更改组件.如果您调用getFullfilledData,则您拥有(订阅中)数据

In this way you needn't change the component. If you call to getFullfilledData you have (in subscribe) the data

请参见 stackblitz

这篇关于如何处理服务迟到的数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆