Как заставить код ждать завершения предыдущих строк

У меня есть функция, которая создает клиента, но перед этим она должна проверить, есть ли похожие имена в базе данных. Если есть, возвращает строку массива с этими именами, если нет, возвращает пустой массив. Мой код до сих пор:

let similarNames:string[] = [];

    this.clientsService.getSimilarNames(clientFormData.clientName, 0).subscribe(res => {
      similarNames = res;
      console.info("Length: ", similarNames.length)
      console.info(similarNames) <-- console.info shows that everything is fine there
      if (similarNames.length > 0){
        this.confirmationService.confirm({
          message: 'There are already similar names:' + similarNames,
          header: 'Similar names',
          icon: 'fa fa-exclamation-triangle',
          acceptLabel: 'Yes',
          rejectLabel: 'No',
          accept: () => {},
          reject: () => {return;}
      })
    }
      this.clientsService.createClient(clientFormData).subscribe(resp => {
        this.isLoading = false;
        this.onCreateClientSuccess();
      }, error => {
        this.isLoading = false;
        this.messageHelperService.showErrorMessage(error, this.messages.CreateError);
      });
    })

Моя проблема в том, что this.clientService.createClient не ждет завершения кода в операторе if. Прямо сейчас он создает клиента, а затем показывает похожие имена и просит создать. Я хочу работать так: если есть какое-либо похожее имя, всплывающее окно должно появиться со списком этих имен, и если оно будет принято, оно должно просто перейти к созданию клиента, если отклонено, оно должно выйти из функции и не создавать клиент.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
51
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете поместить код creatClient в else и продублировать его при использовании обратного вызова accept

Конечно, тогда вы будете дублировать код без уважительной причины.

Итак, лучше создать функцию для «общего» кода и сделать что-то вроде

обратите внимание, что функция является функцией стрелки, чтобы сохранить this

let similarNames: string[] = [];

this.clientsService.getSimilarNames(clientFormData.clientName, 0).subscribe(res => {
    similarNames = res;
    console.info("Length: ", similarNames.length)
    console.info(similarNames)
    const fn = () => {
        this.clientsService.createClient(clientFormData).subscribe(resp => {
            this.isLoading = false;
            this.onCreateClientSuccess();
        }, error => {
            this.isLoading = false;
            this.messageHelperService.showErrorMessage(error, this.messages.CreateError);
        });
    };
    if (similarNames.length > 0) {
        this.confirmationService.confirm({
            message: 'There are already similar names:' + similarNames,
            header: 'Similar names',
            icon: 'fa fa-exclamation-triangle',
            acceptLabel: 'Yes',
            rejectLabel: 'No',
            accept: fn,
            reject: () => {}
        });
    } else {
        fn()
    }
})

Другой альтернативой является использование async/await и нового промиса - кажется, OTT для ситуации, но код выглядит чистым (ИМХО).

let similarNames: string[] = [];

this.clientsService.getSimilarNames(clientFormData.clientName, 0).subscribe(async (res) => {
    similarNames = res;
    
    try {
        if (similarNames.length > 0) {
            await new Promise((resolve, reject) => {
                this.confirmationService.confirm({
                    message: 'There are already similar names:' + similarNames,
                    header: 'Similar names',
                    icon: 'fa fa-exclamation-triangle',
                    acceptLabel: 'Yes',
                    rejectLabel: 'No',
                    accept: resolve,
                    reject: reject // will result a thrown error
                });
            });
        }
        this.clientsService.createClient(clientFormData).subscribe(resp => {
            this.isLoading = false;
            this.onCreateClientSuccess();
        }, error => {
            this.isLoading = false;
            this.messageHelperService.showErrorMessage(error, this.messages.CreateError);
        });
    } catch {
    }
})

Я знаю, что могу просто вставить в accept, но я ищу способ без дублирования кода

Pr0tn12 18.03.2022 11:10

@Pr0tn12 Pr0tn12 Я только что отредактировал ответ, потому что понял: p

Bravo 18.03.2022 11:11

Привет и добро пожаловать в сообщество StackOverflow!

На самом деле, я бы продолжил с RxJS, объединив их в цепочку с pipe и exhaustMap.

this.clientsService.getSimilarNames(clientFormData.clientName, 0).pipe(
  exhaustMap(res => {
        similarNames = res;
        console.info("Length: ", similarNames.length)
        console.info(similarNames) <-- console.info shows that everything is fine there
        if ( similarNames.length > 0 ){
          return this.confirmationService.confirm({
          message: 'There are already similar names:' + similarNames,
          header: 'Similar names',
          icon: 'fa fa-exclamation-triangle',
          acceptLabel: 'Yes',
          rejectLabel: 'No',
          accept: () => {},
          reject: () => {return;}
      })
    }
    return of();
  }),
  exhaustMap(responseFromConfirm => this.clientsService.createClient(clientFormData))
).subscribe(
       () => {
        this.isLoading = false;
        this.onCreateClientSuccess();
      }, 
      error => {
        this.isLoading = false;
        this.messageHelperService.showErrorMessage(error, this.messages.CreateError);
      });

Таким образом, вы связываете свою асинхронную операцию и выдаете значение следующего оператора только после завершения. Конечно, создание будет запущено, даже если проверка на similiarNames не пройдена.

Дополнительные сведения см. в статье exhaustMap.

Другие вопросы по теме