Почему я не могу переместить «await» в другие части моего кода?

#javascript #promise #async-await

#javascript #обещаю #async-await

Вопрос:

Правка2: Решение внизу

Я использую chrome-console и пытаюсь вывести выбранные данные, и я получаю желаемый результат, только написав «await» точно в нужном месте, хотя другое решение может сделать это раньше, и я не знаю, почему / как это работает.

solution() — это «официальное» решение из веб-курса, который я делаю. В настоящее время обе функции возвращают одно и то же.В myFunction я пытался написать «await» перед каждой используемой функцией и сделать каждую функцию «асинхронной», но я все еще не могу заменить «await» внутри журнала, хотя другое решение может.

 const urls = ['https://jsonplaceholder.typicode.com/users']

const myFunction = async function() {
                                          // tried await before urls/fetch (  make it async)
   const arrfetched = urls.map(  url => fetch(url) );   
   const [ users ] = arrfetched.map( async fetched => {  //tried await in front of arrfetched
       return (await fetched).json();                   //tried await right after return
   });
   console.log('users', await users);                   // but can't get rid of this await
}

const solution = async function() {

  const [ users ] = await Promise.all(urls.map(async function(url) {
      const response = await fetch(url);
      return response.json();
  }));
  console.log('users', users);                          // none here, so it can be done 
}

solution();
myFunction();
  

Я бы подумал, что «await» работает таким образом, что делает:

    const a = await b;
   console.log(a);       // this doesn't work
  

то же, что

    const a = b;
   console.log(await a); // this works
  

но это не так, и я не понимаю, почему нет. Я чувствую себя как обещание.все это приводит к чему-то неожиданному, поскольку простое написание «await» в объявлении не может сделать то же самое, только после объявления.

Правка 1: это не работает

 const myFunction = async function() {

    const arrfetched = await urls.map( async url => await fetch(url) );
    const [ users ] = await arrfetched.map( async fetched => {
        return await (await fetched).json();
    });
    console.log('users', users);
}
  

Всем спасибо за помощь Edit2:, я пытался поместить «.toString()» во множество переменных и переключать, где я помещаю «await» в коде, а где нет.
Насколько я понимаю, если я не использую Promise.all, то мне нужно ожидать каждый раз, когда я хочу использовать (как в реальных данных, а не просто использовать) функцию или переменную, которая содержит promises. Недостаточно иметь await только там, где обрабатываются данные, а не дальше.
В приведенной выше правке 1 пользовательские запуски выполняются раньше, чем любое другое ожидание завершено, поэтому независимо от того, сколько ожиданий я записываю, ни одно из них не выполняется. Копирование этого кода в консоль (в моем случае chrome-) прекрасно его демонстрирует:

 const urls = [
      'https://jsonplaceholder.typicode.com/users',
    ]
    const myFunction = async function() {

      const arrfetched =  urls.map( async url => fetch(url) );
      const [ users ] =  arrfetched.map( async fetched => {
          console.log('fetched', fetched);
          console.log('fetched wait', await fetched);
          return (await fetched).json();
      });
      console.log('users', users);
      console.log('users wait', await users);
    }

    myFunction();

// Output in the order below:
// fetched()
// users()
// fetched wait()
// users wait()
  

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

1. Не ясно, чего вы пытаетесь достичь.

2. Я хочу избавиться от await внутри консоли моей функции следующим образом: console.log(‘users’, пользователи);

3.Вы здесь все слишком усложняете. В вашем «edit1» вы разрешаете массив promises с помощью async await , а затем вы сопоставляете этот массив, чтобы фактически притвориться, что удваиваете await то, что уже разрешено. Если fetch возвращает a Promise , первый .map должен быть асинхронным. Если .json() возвращает Promise , то второй также должен быть асинхронным. Однако реальное await должно произойти во время fetch операции, а не во время чего-либо еще.

4. Таким образом, большее количество ожиданий, чем необходимо, может нарушить работу кода, работающего в остальном?

5. Просто чтобы прояснить это (в дополнение к моему ответу): лишнее await никогда не вредно (кроме как с точки зрения производительности). Ожидание не-обещания, например, await 'hello' сначала превратит его в обещание, а затем ожидает этого, так что это эквивалентно await Promise.resolve('hello')

Ответ №1:

TL; DR: Promise.all это важно, но в этом нет ничего волшебного. Он просто преобразует массив обещаний в обещание, которое разрешается с помощью массива.

Давайте разберемся myFunction :

 const arrfetched = urls.map(  url => fetch(url) );
  

Это возвращает массив обещаний, пока все хорошо.


 const [ users] = arrfetched.map( async fetched => {
  return (await fetched).json();
});
  

Вы разрушаете массив, чтобы получить первый элемент, так что это то же самое, что и это:

 const arr = arrfetched.map( async fetched => {
  return (await fetched).json();
});
const users = arr[0];
  

Здесь мы преобразуем массив обещаний в другой массив promises. Обратите внимание, что вызов map с async помощью функции всегда приведет к массиву обещаний.

Затем вы перемещаете первый элемент этого массива в users , так что users теперь фактически содержит одно обещание. Затем вы ожидаете его перед печатью:

 console.log('users', await users);
  

В отличие от этого, другой фрагмент делает здесь что-то немного другое:

 const [ users ] = await Promise.all(urls.map(async function(url) {
  const response = await fetch(url);
  return response.json();
}));
  

Еще раз, давайте разделим деструктурирование:

 const arr = await Promise.all(urls.map(async function(url) {
  const response = await fetch(url);
  return response.json();
}));
const users = arr[0];
  

Promise.all преобразует массив обещаний в одно обещание, результатом которого является массив. Это означает, что после того, как await Promise.all все в arr было ожидаемо (вы можете представить await Promise.all что-то вроде цикла, который ожидает все в массиве). Это означает, что arr это просто обычный массив (не массив обещаний) и, следовательно, users его уже ожидают, или, скорее, это никогда не было обещанием в первую очередь, и, следовательно, вам не нужно await это.

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

1. Здесь мы преобразуем массив обещаний в другой массив promises. Обратите внимание, что вызов map с помощью асинхронной функции всегда приведет к появлению массива обещаний. Оооо, итак, моя правка1: const [ users] = await arrfetched.map( … ожидает не пормисы, а массив обещаний, которого ему не нужно ждать!

2. Совершенно верно. await [Promise.resolve(42), Promise.resolve(24)] == [Promise.resolve(42), Promise.resolve(24)] (потому что вы ожидаете массив, который не является обещанием и, следовательно, ничего не делает), но await Promise.all([Promise.resolve(42), Promise.resolve(24)]) == [await Promise.resolve(42), await Promise.resolve(24)] == [42, 24]

Ответ №2:

Возможно, самый простой способ объяснить это — описать, чего достигает каждый шаг:

 const urls = ['https://jsonplaceholder.typicode.com/users']

async function myFunction() {

  // You can definitely use `map` to `fetch` the urls
  // but remember that `fetch` is a method that returns a promise
  // so you'll just be left with an array filled with promises that
  // are waiting to be resolved.
  const arrfetched = urls.map(url => fetch(url));

  // `Promise.all` is the most convenient way to wait til everything's resolved
  // and it _also_ returns a promise. We can use `await` to wait for that 
  // to complete.
  const responses = await Promise.all(arrfetched);

  // We now have an array of resolved promises, and we can, again, use `map`
  // to iterate over them to return JSON. `json()` _also_ returns a promise
  // so again you'll be left with an array of unresolved promises...
  const userData = responses.map(fetched => fetched.json());

  //...so we wait for those too, and destructure out the first array element
  const [users] = await Promise.all(userData);

  //... et voila!
  console.log(users);
}

myFunction();  

Ответ №3:

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

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

1. Итак, когда я пишу что-то вроде в Edit1, это не работает, потому что что-то не асинхронно, хотя я не получаю ошибок?

2. Позвольте мне перефразировать это. Клавиша await должна использоваться в асинхронной функции. Функция map также является функцией, которая будет выполнена, когда сможет. Если вам нужны эти данные, вы можете отобразить эти вызовы в promise.all. Таким образом, функция будет продолжена только в том случае, если все обещания будут выполнены

3. Итак, написав await в консоли. войти Я получаю то же самое, что и await Promise.all, но когда я пишу await внутри объявления переменной, это игнорируется, потому что это не в асинхронной функции?

4. Да, но это похоже на ошибку. Вы должны попытаться избежать этого. Если вы хотите подождать. для обещания используйте правильную функцию для него. Надеюсь, это поможет логике, поскольку она может быть довольно абстрактной.