Как использовать async / await для получения входных данных от пользователя, но подождать, пока не будет прочитан весь оператор условия перед разрешением?

#javascript #node.js #asynchronous #promise

#javascript #node.js #асинхронный #обещание

Вопрос:

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

Как мне использовать promises /async /await, чтобы дождаться, пока моя функция requestSiteURL() завершит выполнение своего оператора условия, прежде чем устанавливать переменную в getURL()?

 const readline = require('readline').createInterface({
   input: process.stdin,
   output: process.stdout,
});

// request url from user in command prompt
const requestSiteURL = () => {
  return new Promise((resolve, reject) => {
    readline.question('Please type url: ', async (url) => {
      if (validUrl.isUri(url)) {
        readline.close();
        resolve(url);
        // if user types no, then use base url
      } else if ('No' || 'no' || 'NO') {
        url = URL;
        resolve(url);
      } else {
        reject(
          console.log(
            'Please type in a valid URL or type "no" to use base url.'
          )
        );
        requestSiteURL();
      }
    });
  });
};

// grabs all urls from original link and returns array
const getURLS = async () => {
  let url = await requestSiteURL();
  url = deleteFowardSlash(url);
  try {
    const res = await axios.get(url);
    const data = res.data;
    const $ = cheerio.load(data);

    const urlQueue = [];

    // finds all absolute links and pushs to urlQueue array
    $("a[href^='http']").each((i, elem) => {
      let link = $(elem).attr('href');
      //checks to make sure link isnt any duplicate links in urlqueue array
      link = deleteFowardSlash(link);
      uniqueLinkChecker(link, urlQueue);
    });
    return urlQueue;
  } catch (err) {
    console.error(err);
    return response.status(400).send(err);
  }
};
 

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

1. установка какой переменной в getURL (ах)?

2. переменная установлена как url

3. Это else if ('No' || 'no' || 'NO') { просто неправильное условие. Возможно, вы имеете в виду else if (url.toLowerCase() === 'no') { ?

4. И, return Promise.resolve().then((resolve, reject) => должно быть return new Promise((resolve, reject) => . Promise.resolve() возвращает разрешенное обещание, которое вы можете вызвать .then() , но оно НЕ передает два аргумента .then() обработчику. Вместо этого вам нужно использовать new Promise() конструктор.

5. Пожалуйста, НЕ редактируйте исправления, о которых идет речь. Это меняет весь ваш вопрос и делает недействительными ответы, которые вам уже дали люди.

Ответ №1:

Я думаю, что это вопрос синтаксиса. Здесь я переключил исходную строку, чтобы правильно использовать конструктор Promise. Обещание mdn

 // request url from user in command prompt
const requestSiteURL = () => {
  return new Promise((resolve, reject) => {
    readline.question('Please type url: ', async (url) => {
      if (validUrl.isUri(url)) {
        readline.close();
        resolve(url);
        // if user types no, then use base url
      } else if (url.toLowerCase() === 'no') {
        url = URL;
        resolve(url);
      } else {
        console.log(
          'Please type in a valid URL or type "no" to use base url.'
        )
        requestSiteURL().then(resolve);
      }
    });
  });
};
 

Редактировать: добавление версии async / await. В принципе, я думаю, вам никогда не придется отклонять. Я отредактировал приведенное выше, чтобы также не отклонять. Также я предполагаю URL , что это URL-адрес по умолчанию (это противоречит глобальному пространству имен URL, просто для записи)

 // request url from user in command prompt
const requestSiteURL = async function () {
  const url = await new Promise(resolve => {
    readline.question('Please type url: ', resolve)
  })
  if (validUrl.isUri(url)) {
    readline.close()
    return url
  } else if (url.toLowerCase() === 'no') {
    return URL
  } else {
    console.log('Please type in a valid URL or type "no" to use base url.')
    return requestSiteURL()
  }
}
 

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

1. итак, я внес это изменение, и оно запрашивает меня из другой функции, но никогда не проходит через условные операторы. Если я напишу «картофель», он все равно примет это

2. возможно, проверьте validUrl.isUri . Это единственное другое условие, которое я вижу, кроме правильного.

3. итак, если я напишу действительный URL-адрес с этим, я получу правильный вывод, но в противном случае я получаю сообщение об ошибке, что у меня есть необработанное promiserejectionwarning

4. Добавлена версия async / await, также первая перестала отклоняться при ближайшем рассмотрении.

5. это сработало, я также поместил свой URL-адрес по умолчанию в свою функцию, чтобы он не был глобальным. Большое вам спасибо!!!!

Ответ №2:

На первый взгляд не похоже, что ваше условие «else» вообще будет ждать. Вы отклоняете обещание и рекурсивно вызываете requestSiteURL() , но ничего не делаете с возвращенным обещанием. Это снова задаст вопрос, но вызывающая функция не имеет возможности получить доступ к этому обещанию. Исходное обещание, которое было возвращено, уже отклонено. Новое обещание нигде не упоминается, поэтому, когда resolve или reject вызывается во второй раз, нет кода для доступа к результату.

Если вы хотите, чтобы ваш код потерпел неудачу и отклонил возвращенное обещание, тогда вам не следует вызывать его снова в операторе else .

Если вы хотите, чтобы функция one продолжала задавать вопрос до тех пор, пока не будет введен правильный ответ, вы можете исправить эту проблему, инкапсулировав свой код в функцию и продолжая вызывать ее при ошибке, пока она не разрешится с помощью исходного параметра «разрешить» возвращаемого вами обещания. Это не похоже на readline.вопрос () принимает асинхронную функцию либо:

 // request url from user in command prompt
const requestSiteURL = () => {
  return new Promise((resolve, reject) => {
    const askQuestion = () => {
      readline.question('Please type url: ', (url) => {
        if (validUrl.isUri(url)) {
          readline.close(); // close readline here?
          resolve(url);
        } else if ('No' || 'no' || 'NO') {
          url = URL;
          // don't close readline here?
          resolve(url);
        } else {
          console.log(
            'Please type in a valid URL or type "no" to use base url.'
          );
          // call askQuestion() again until we resolve with something
          askQuestion()
        }
      });
      
      // call askQuestion() the first time
      askQuestion();
  });
};
 

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

1. добавленный мной код не включает весь мой скрипт, я могу включить его, он просто очень длинный.