0

我目前正在学习更多关于角度和打字稿的异步方面的知识,如果我缺乏知识,请原谅我,我目前正面临一个问题,我正在尝试实现承诺以使包含 for 循环的函数在调用之前先完成下一个功能,

这是一个示例代码,其中目标是我有一个 for 循环来遍历所有表单,并且在循环中,是调用服务以获取要放入对象中的必要数据,然后继续使用所述创建一个新对象数据并将新创建的数据推送到数组中,在此函数结束后,下一个函数将运行以将数组提交给服务。

例如我有一个大小为 2 的表单,我希望在调用最后一个 resolve() 返回 submitObj() 并最终调用 sendTestObject() 之前结束 for 循环,

在 component.ts

 submitObj() {

    // call function to create object and wait for it to finish
    // via a promise.then()
    this.createTestObject().then((){

        //then finally call another service to give created object
        this.sendTestObject();
    });
    
}
 
 
 createTestObject() {
    const testObjList: testActvity[] = [];
    let count = 1;
    return new Promise ((resolve) => {

    // How do I make it so that this for loop goes in order
    // and finishes first
    // before going to the next line of code?
    for (const i in this.testFormArray.controls) {
      testObj = new Actvity();
      let promise = new Promise((resolve,reject) =>{
      
      this.testService.getTestData().then(res => {
        console.log(count);
        if (res) {
            if (res.results) {
                this.testArrayForm.controls[i].get('testForm').patchValue({
                    "Id": res.results.Id,
                    "type": res.results.type,
                })
            }
        }      
      })}
      
      resolve();
    }
  });
  
  promise.then(()=> {
     console.log("in then() of " + count);
     testObj.testForm = this.testArrayForm.controls[i].get('testForm').value;
     testObjList.push(testObj);
     count ++;
  })

  //How do I wait for the for loop to finish first before running this?
  console.log("FINISHED)"
  resolve();
}

在 service.ts

getTestData(): Promise<any>{
    let res = this.http.get("testData.json")
    .toPromise()
    .then( res => {
      return res ;
    }). catch (err => {
        return err ;
    });
     return new Promise ((resolve, reject) => {
       resolve(res);
     });
 }
4

2 回答 2

0

为什么不使用“concat”rxjs 操作符(Angular 可以很好地与 observables 配合使用,而无需使用 Promise)?一个简单的例子:

如果我们有一个返回 observable 的函数:

obs(value){
   return of(value).pipe(delay(1000))
}

并连接一个可观察的数组

const $concatObs=concat(...[0,1,2,3].map(x=>this.obs(x)));

我们可以订阅

$concatObs.subscribe(res=>{
      this.value=res;
})

一个简单的堆栈闪电战

更新“cacth 错误”。如果我们的函数可以抛出错误,则 concat 的问题。好吧,我们可以使用 catchError (另一个 rxjs 运算符)来计算这一点。

如果我们“管道”observables,如果有错误返回一个对象{error:....}

const $concatObs = concat(
  ...[0, 1, 2, -2, 3, 4,"finished"].map(x => this.obs(x)
     .pipe(catchError(error=>{
          return of({error:error})
      })))
);

在订阅中,我们可以检查是否有错误

$concatObs.subscribe(res => {
  if (res.error)
  {
    console.log(res.error)
  }else
    this.value = res;
});
于 2020-11-13T11:24:31.977 回答
0

这是我的解决方案。我没有使用您的代码,因为我无法对其进行测试,但我正在展示总体思路。基本上我摆脱了for循环,而是在元素(在你的情况下是表单输入)上迭代,如果承诺的话,会形成一个递归链。一旦最后一个解决了,我们就知道我们已经处理了所有元素:

const data = ['foo', 'bar'];

function processElement(index: number): void {
    console.log('do something with element: ' + index + ' which is: ' + data[index]);
}

function processAllElements(index: number, count: number): Promise<void> {
    return new Promise((resolve, reject) => {
        if(index == count) {
            resolve();
            return;
        }
        
        processElement(index);
        
        return processAllElements(index + 1, count);
    });
}

function run(): void {
    processAllElements(0, data.length)
        .then(() => {
            console.log('All done');
        });
}

run();
于 2020-11-13T10:55:16.973 回答