Асинхронное программирование в Javascript — Promise.all() не работает должным образом

Я застрял в асинхронном программировании на Javascript. Я знаю, что Promise.all() будет работать параллельно.

Не могли бы вы сказать мне, что я не так с этим кодом ниже?

Это должно занять 100ms. А на самом деле нужно 200ms :(

// 1. Define function here
var getFruit = async (name) => {
  const fruits = {
    pineapple: ":pineapple:",
    peach: ":peach:",
    strawberry: ":strawberry:"
  };
  await fetch('https://jsonplaceholder.typicode.com/photos'); // abount 100ms 
  return fruits[name];
};

var makeSmoothie = async () => {
  const a = getFruit('pineapple');
  const b = getFruit('strawberry');
  const smoothie = await Promise.all([a, b]);
  return smoothie;
  //return [a, b];
};
  
/// 2. Execute code here
var tick = Date.now();
var log = (v) => console.info(`${v} \n Elapsed: ${Date.now() - tick}`);
makeSmoothie().then(log);

API возвращает список фотографий, и вы пытаетесь получить фрукты ... как они связаны?

Nilesh Patel 24.12.2020 05:26

@TangentiallyPerpendicular нет, await в getFruit не блокирует параллельный getFruit вызов, который вызывает Promise.all.

Matt 24.12.2020 05:29

@Nilesh Patel Мне просто нужно какое-то обещание, чтобы измерить, а также определить, работает ли Promise.all правильно или нет. Особенно, что я не так с методом getFruit().

Nguyễn Văn Phong 24.12.2020 05:40
Поведение ключевого слова "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) для оценки ваших знаний,...
2
3
131
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Ваша логика в порядке, она работает максимально параллельно со стороны клиента.

Вы можете проверить это, дождавшись setTimeout вместо выборки:

await new Promise(resolve => setTimeout(resolve, 100));

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

Редактировать:

Просто чтобы объяснить немного больше, что не поместится в комментарии.

Давайте поместим мой трюк с ожиданием в реальную функцию:

const wait = ms => new Promise(resolve => setTimeout(resolve, ms));

Хорошо, теперь вы бы назвали это как await wait(100). Теперь для сравнения:

  • await wait(100)
  • await fetch(...)

С точки зрения настройки вашего кода, они одинаковы. Они выполняют некоторую асинхронную задачу, которая занимает около 100 мс и возвращает результат. Если бы Promise.all() не выполнял это параллельно, версия wait(100) определенно заняла бы 200 мс или больше.

fetch не такой надежный тест, как setTimeout, потому что он работает по сети. Есть много вещей, которые вы не можете контролировать с помощью этого звонка, например:

  • Некоторые браузеры ограничивают количество параллельных подключений к одному и тому же домену.
  • Лаги в DNS или самом сервере, типичные сбои сети
  • Сам домен может форсировать 1 соединение за раз с вашего IP.

Не совсем ясно, что именно вызывает здесь очевидное синхронное поведение. Возможно, вы найдете какие-то ответы в сетевой панели. Но с точки зрения кода вам больше нечего делать. Он доказуемо распараллелен с тестом setTimeout, который гораздо более надежен как тест, поскольку это просто локальный таймер.

Привет, братан, не мог бы ты сказать мне, почему мой fetch() не работает параллельно? А чем отличаются ваши fetch() и await new Promise?

Nguyễn Văn Phong 24.12.2020 05:33

@Phong Он уже сказал вам, почему ваша выборка не работает параллельно. Fetch может работать параллельно, но он предполагает, что https://jsonplaceholder.typicode.com обслуживает запросы последовательно. Почему jsonplaceholder.typicode.com не отвечает параллельно, может быть из-за многих вещей: все браузеры имеют ограничение на подключение к каждому IP-адресу, поэтому вы можете достичь этого ограничения (помните, запросы браузера иногда генерируют два запроса — запрос OPTION для CORS, а затем реальные запросы GET, которые могут быть двумя соединениями), сам веб-сайт может иметь ограниченную пропускную способность и т. д.

slebetman 24.12.2020 05:41

Попробуйте запросить 100 изображений вместо 2. Некоторые серверы и маршрутизаторы увеличивают пропускную способность при ответе с большим количеством данных. Почему некоторое сетевое оборудование и серверы спроектированы таким образом? Таким образом, они могут одинаково быстро обслуживать многих клиентов, а не одного клиента.

slebetman 24.12.2020 05:44

Спасибо @slebetman и @Matt. Это решено. Кстати, что произойдет, если я изменю await fetch() или await wait(100) блокировщиком кода, как это loop from 1 to 2000. Это становится синхронизацией, верно? В итоге Promise.all() не работают параллельно?

Nguyễn Văn Phong 24.12.2020 05:48

@Phong правильно, Promise.all может планировать только асинхронные задачи параллельно. Он не может преобразовать синхронный цикл ЦП в отдельный поток или что-то еще. fetch по своей природе асинхронный, поэтому его вообще можно запланировать с помощью Promise.all

Matt 24.12.2020 05:49

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