Сделайте вызов ajax внутри .map () - PullRequest
1 голос
/ 05 августа 2020

Я обновляю jquery и вижу, что опция «asyn c: false» устарела. Это имеет смысл, и в 99,9% случаев я согласен с обоснованием, но у меня есть случай, когда я думаю, что мне это действительно нужно, и я не могу, хоть убей, понять, как заставить эту работу работать с чисто асинхронным c ajax, независимо от того, как я использую обещания или async / await.

Мой вариант использования - компонент Vue, и у меня есть массив контактов. Что мне нужно сделать, так это сопоставить контакты и проверить их. Одна из таких проверок требует быстрой проверки действительности электронной почты через конечную точку «check_email» ajax.

После того, как я проверил (или нет) список, я затем отправляю список (если он действителен) или показываю сообщения об ошибках ( если недопустим).

Мой код выглядит примерно так

sendContacts: function() {
   valid = this.validateContacts()

   if (valid) {
       // send the contacts
   } else {
      return // will display error messages on contacts objects
   }
},

validateContacts: function() {
    this.contacts = this.contacts.map((contact) => {
          if (!contact.name) {
            contact.validDetails.name = false
            contact.valid = false
            return contact
          }
          if (!contact.email) {
            contact.validDetails.emailExists = false
            contact.valid = false
            return contact
          } 
          if (!check_email(email)) { // THIS IS ASYNC NOW WHAT DO I DO
            contact.valid = false
            contact.validDetails.emailFormat = false
          }
          return contact
    }
     var validData = this.contacts.map(c => {
          return c.valid
     })
     return !validData.includes(false)
}
function check_email(email) {
  const url = `/api/v1/users/check-email?email=${email}`
  let valid = false
  $.ajax({
    url: url,
    type: 'POST',
    async: false, // I can't do this anymore
    headers: {
      'X-CSRFToken': csrfToken
    },
    success: resp => {
      valid = true
    },
    error: err => {
    }
  })
  return valid
}

моя функция данных:

data: function() {
    return {
        contacts: [this.initContact()],
        showThanks: false,
        emailError: false,
        blankEmail: false,
        blankName: false
    }
  },
methods: {
    initContact: function() {
        return {
          name: null,
          email: null,
          title: null,
          validDetails: this.initValidDetails(),
          valid: true,
        }
    },
    initValidDetails: function() {
      return {
        emailDomain: true,
        emailExists: true,
        emailFormat: true,
        name: true
      }
    }
}

Опять же, я пробовал async / await в во всех местах, о которых я мог подумать, и я не могу заставить это правильно проверить, а затем правильно выполнить logi c относительно того, должна ли срабатывать часть функции отправки контактов. Пожалуйста, помогите!

1 Ответ

1 голос
/ 05 августа 2020

Если какая-либо часть вашей проверки является асинхронной, вы должны рассматривать ее как асинхронную целиком. Это включает в себя вызов validateContacts в sendContacts.

Во-первых, вы должны изменить check_email, чтобы вернуть Promise<bool>. Обычно плохая идея включать jQuery в проект Vue, поэтому давайте вместо этого будем использовать fetch ( Ax ios - еще одна популярная альтернатива).

async function check_email(email) {
  const params = new URLSearchParams({ email })
  const res = await fetch(`/api/v1/users/check-email?${params}`, {
    method: 'POST',
    headers: {
      'X-CSRFToken': csrfToken
    }
  })
  return res.ok
}

As для вашего asyn c logi проверки c лучше всего сопоставить ваши контакты с массивом обещаний и дождаться их всех с помощью Promise.all.

async validateContacts () {
  const validationPromises = this.contacts.map(async contact => {
    if (!contact.name) {
      return {
        ...contact,
        valid: false,
        validDetails: {
          ...contact.validDetails,
          name: false
        }
      }
    }
    if (!contact.email) {
      return {
        ...contact,
        valid: false,
        validDetails: {
          ...contact.validDetails,
          emailExists: false
        }
      }
    } 
    if (await check_email(contact.email)) { // await here
      return {
        ...contact,
        valid: false,
        validDetails: {
          ...contact.validDetails,
          emailFormat: false
        }
      }
    }
    return { ...contact, valid: true }
  })

  // now wait for all promises to resolve and check for any "false" values
  this.contacts = await Promise.all(validationPromises)
  return this.contacts.every(({ valid }) => valid)
}

Как уже упоминалось, теперь вам нужно обрабатывать это асинхронно в sendContacts

async sendContacts () {
   if (await this.validateContacts()) {
     // send the contacts
   }
}
...