Как выполнить два вызова API с помощью Promise.все в Angular9?

#javascript #node.js #angular #promise #angular-promise

#javascript #node.js #angular #обещание #angular-обещание

Вопрос:

Я выполняю вызов API, используя Promise.all , как показано ниже:

     Promise.all(this.hostName.slice(0, this.Id.length).map((hostName) => {
        return this.serviceC.status(hostName)
            .then(res => {
                return new Promise((resolve, reject) => {
                    const oretry: ORInterface = {
                        oQid: res.rows[0].qid,
                        reason: this.reason
                    };
                    this.serviceB.retry(oretry).subscribe(resolve);
                });
            });
    }))
.then(() => {
        this.dialog.close();
    })
        .catch(err => {
            console.log(err);
        });
  

Приведенный выше код работает нормально.
Теперь я хочу выполнить еще один вызов API после успешного завершения this.serviceB.retry(oretry) .
Второй API является this.serviceB.createDbEntry(sentry) и sentry выглядит следующим образом:

                     const sretry: SDInterface = {
                        hostName,
                        Id: this.Id.slice(0, this.Id.length),
                        reason: this.reason
                    };
  

И я делаю это, как показано ниже

     Promise.all(this.hostName.slice(0, this.Id.length).map((hostName) => {
        return this.serviceC.status(hostName)
            .then(res => {
                return new Promise((resolve, reject) => {
                    const oretry: ORInterface = {
                        oQid: res.rows[0].qid,
                        reason: this.reason
                    };
                    const sretry: SDInterface = {
                        hostName,
                        Id: this.Id.slice(0, this.Id.length),
                        reason: this.reason
                    };
                    this.serviceB.retry(oretry).subscribe(resolve);
                    this.serviceB.createDbEntry(sentry).subscribe(resolve);
                });
            });
    }))
.then(() => {
        this.dialog.close();
    })
        .catch(err => {
            console.log(err);
        });
  

Приведенный выше код выдает ошибку:

 error: "SequelizeValidationError: string violation: Id cannot be an array or an object"
  

Похоже, что он не вызывает второй API для каждого Id

Ответ №1:

Возможно, вы захотите взглянуть на forkJoin

 import { Observable, forkJoin } from 'rxjs';
  

И затем

 ngOnInit() {
    let one = this.http.get('some/api/1') //some observable;
    let two = this.http.get('some/api/2') // another observable;

    forkJoin([one, tow]).subscribe(response => {
     // results[0] is our one call
     // results[1] is our second call
     let var1 = response[1];
     let var2 = response[0];
    }/*, error => { in case error handler } */); 
}
  

Ответ №2:

Не лучше ли было бы использовать Promise.all() еще раз?

 Promise.all(this.hostName.slice(0, this.Id.length).map((hostName) => {
    return this.serviceC.status(hostName)
        .then(res => {
            return new Promise((resolve, reject) => {
                const oretry: ORInterface = {
                    oQid: res.rows[0].qid,
                    reason: this.reason
                };
                this.serviceB.retry(oretry).subscribe(resolve);
            });
        })
        .then(() => {
            return Promise.all(this.Id.slice(0, this.Id.length).map(id => {
                return new Promise((resolve, reject) => {
                    const sretry: SDInterface = {
                        hostName,
                        Id: id,
                        reason: this.reason
                    };

                    this.serviceB.createDbEntry(sentry).subscribe(resolve);
                });
            })
        });
}))
    .then(() => {
        this.dialog.close();
    })
    .catch(err => {
        console.log(err);
    });

  

И использование toPromise() сделает код более кратким.

 Promise.all(this.hostName.slice(0, this.Id.length).map((hostName) => {
    return this.serviceC.status(hostName)
        .then(res => {
            const oretry: ORInterface = {
                oQid: res.rows[0].qid,
                reason: this.reason
            };
            return this.serviceB.retry(oretry).toPromise();
        })
        .then(() => {
            return Promise.all(this.Id.slice(0, this.Id.length).map(id => {
                const sretry: SDInterface = {
                    hostName,
                    Id: id,
                    reason: this.reason
                };

                this.serviceB.createDbEntry(sentry).toPromise();
            })
        });
}))
    .then(() => {
        this.dialog.close();
    })
    .catch(err => {
        console.log(err);
    });

  

Комментарии:

1. Я пытаюсь использовать toPromise() , но получаю ошибку TSLint: Missing semicolon(semicolon)

2. Ошибка с запятой устранена путем добавления еще одной скобки, ...this.serviceB.createDbEntry(sentry).toPromise(); })); }); пожалуйста, обратите внимание, что теперь this.serviceB.createDbEntry(sentry).toPromise(); выполняется два раза вместо одного. Можете ли вы, пожалуйста, проверить?

Ответ №3:

Используйте combineLatest, в Angular мы используем RxJS, а не promises.

 combineLatest(
  [this.http.get('call1'), this.http.get('call2')]
).subscribe(([result1, result2]) => {
  // do stuff with result1 and result2
});
  

Комментарии:

1. У меня есть зависимость от promise . Я могу заставить это работать, используя toPromise() приведенный выше ответ. Единственное, что this.serviceB.createDbEntry(sentry).toPromise(); выполняется дважды вместо одного раза. Можете ли вы, пожалуйста, проверить?

Ответ №4:

promise.all принимает входные данные в массив и выдает ответ в массиве,

Создайте 2 функции, каждая из которых с вашей асинхронной логикой возвращает обещание,

Скажите funcA и funcB, затем используйте ниже, чтобы вызвать их параллельно

 Promise.all([funcA(this.hostName), funcB(this.id)])
    .then(respones => {
        console.log(responses[0]); //return value for funcA
        console.log(responses[1]); //return value for funcB
    })
    .catch(err => console.log(err));
  

Я предполагаю, что ваша логика функций верна, я просто скопировал ваш вопрос и дал им структуру

 const funcA = (hostName) => {
hostName.slice(0, this.Id.length).map((hostName) => {
    return this.serviceC.status(hostName)
        .then(res => {
            return new Promise((resolve, reject) => {
                const oretry: ORInterface = {
                    oQid: res.rows[0].qid,
                    reason: this.reason
                };
                this.serviceB.retry(oretry).subscribe(resolve);
            });
        });
    });
}


const funcB = (Id) => {
Id.slice(0, this.Id.length).map(id => {
                return new Promise((resolve, reject) => {
                    const sretry: SDInterface = {
                        hostName,
                        Id: id,
                        reason: this.reason
                    };

                    this.serviceB.createDbEntry(sentry).subscribe(resolve);
                });
            })
}
  

Комментарии:

1. Не могли бы вы обновить свой ответ и показать, как использовать this.hostName.slice(0, this.Id.length) в funcA и использовать this.Id.slice(0, this.Id.length) в funcB ?

2. funcB выдает ошибку TS2663: Cannot find name 'hostName'. Did you mean the instance member 'this.hostName'?

3. Как передать hostName из funcA в funcB ?

4. funcB все еще выдает ошибку TS2304: Cannot find name 'hostName