LINUX.ORG.RU

«Синхронная» работа с XMLHttpRequest в js

 ,


0

2

Привет!

Столкнулся с необходимостью написания небольшой поделки, которая использует javascript. У меня есть список item'ов, мне нужно по каждому из них сделать запрос к внешнему сервису и результат показать табличкой типа «| item | результат запроса |». Запросы выполняю через XMLHttpRequest. Так вот при работе с ним синхронно все получается так, как я и хочу - я по каждому элементу списка создаю новую строку таблицы через js, в первую колонку пишу item, выполняю запрос, результат записываю во вторую колонку, и перехожу к следующему элементу. И все хорошо, только вот консоль мне постоянно ругается «э ты чо в 2К18 никто не пишет синхронно быстро переделывай посоны засмеют», если мне нужно больше чем одну таких таблички сделать то js (ну движок браузера или что там) видно не умеет нормально параллелить запросы и все это постоянно отваливается с чудесным «NetworkError: A network error occurred.», ну и вообще в интернетах все советуют забыть про синхронные запросы.

Итак, что мне делать? Я не хочу чтоб у меня эти коллбэки ехали через коллбэки и коллбэками погоняли, мне в целом все равно сколько будет занимать загрузка страницы (с кучей элементов и синхронно это порядка секунды, потому что все на локалхосте), как-то можно делать запрос асинхронно, при этом дожидаться результатов его выполнения (код, который получает данные из «удаленного» источника собран в функцию, которая (грубо говоря) на вход получает урл и параметры, и возвращает текст ответа).

Заранее спасибо за советы!

Ответ на: комментарий от makoven

Чего это? Для того чтоб поправить одну функцию мне надо тащить ноду и какие-то плагины? А описания что оно делает нигде нет?

micronekodesu ★★ ()
Ответ на: комментарий от Norgat

Так это если я сам пишу, в случае «библиотечного» XMLHttpRequest мне тогда его синхронно надо вызывать внутри async и будет то же самое, только плюс еще скорее всего что-то с этим асинком вылезет. А если я буду делать запрос асинхронно то как обертка узнает что он завершился?

micronekodesu ★★ ()
Ответ на: комментарий от micronekodesu

Для того чтоб поправить одну функцию мне надо тащить ноду и какие-то плагины? А описания что оно делает нигде нет?

Что не смеетесь? Не смешно? Это Россияджаваскрипт!

makoven ★★★★★ ()
Ответ на: комментарий от makoven

Это неправильный жабоскрипт, олдфаги за то PHP/JS и ценили, что не надо ничего конпелять — просто сохраняешь файл и перезагружаешь страничку.

bodqhrohro_promo ()

как-то можно делать запрос асинхронно, при этом дожидаться результатов его выполнения

Сделай через рекурсию.

anonymous ()

легко. Заворачиваем функцию с колбеком в промис, которому делаем await. Если нужна поддержка в старых браузерах, скармливаем это babel-у

anonymous ()
Ответ на: комментарий от anonymous

Это все круто, конечно, только для промиса мне все равно коллбэк потребуется. Это я и так могу без всяких там фетчей, промисов, эвейтов и вот этого всего. Мне надо взять ответ и присвоить как значение переменной. Не в коллбэке, а именно в виде функции, которая получает урл на вход и выдает данные с этого урла на выход.

micronekodesu ★★ ()
Ответ на: комментарий от anonymous

легко. Заворачиваем функцию с колбеком в промис, которому делаем await. Если нужна поддержка в старых браузерах, скармливаем это babel-у

легко

makoven ★★★★★ ()
Ответ на: комментарий от bodqhrohro_promo

Это неправильный жабоскрипт, олдфаги за то PHP/JS и ценили, что не надо ничего конпелять — просто сохраняешь файл и перезагружаешь страничку.

С webpack тебе вообще ни чего не надо делать. Сохранит редактор, вебпак соберет и перезагрузит страничку в браузере.

Deleted ()
Ответ на: комментарий от Deleted

вебпак соберет и перезагрузит страничку в браузере

Угу, только перед этим конпелировать будет полминуты, если проект больше хэллоуворлда и машинка не топовая. В конпелируемых языках так-то тоже «всё само» — жамкнул F9 и жди, пока окошко появится. Или не появится, потому что у тебя ошибка, которую статический анализ не выявил, только при сборке вылезла.

bodqhrohro_promo ()
Ответ на: комментарий от bodqhrohro_promo

При чем тут коллбэкофобия? Как я то что мне нужно могу сделать на коллбэках? Мне надо для каждого элемента массива выполнить запрос и записать рядом результат. Вот прям даже давай псевдокодом, чтоб ты не думал что я прошу сделать за меня, потому что я реально не понимаю какой алгоритм действий в этом случае, а не не могу нагуглить какие есть методы у объекта. Я делаю так:

Для каждого ЭЛЕМЕНТ из СПИСОК
    НОВАЯ_СТРОКА = ТАБЛИЦА.создать_новую_строку()
    ЯЧЕЙКА1 = НОВАЯ_СТРОКА.создать_ячейку()
    ЯЧЕЙКА2 = НОВАЯ_СТРОКА.создать_ячейку()
    ЯЧЕЙКА1.текст(ЭЛЕМЕНТ)
    ОТВЕТ = выполнить_запрос(урл, ЭЛЕМЕНТ)
    ЯЧЕЙКА2.текст(ОТВЕТ)
<переходим к следующему элементу>

Теперь расскажи, пожалуйста, как мне то же самое сделать с коллбэком. Впилить глобальных переменных которые я буду в этих коллбэках модифицировать, потом как-то понять что все коллбэки выполнились, потом по этой глобальной переменной перебирать элементы (а, перед этим в коллбэк мне надо еще и пихать мои ЭЛЕМЕНТы), при этом как-то еще пытаться организовать нормальный порядок этих записей?

micronekodesu ★★ ()
Ответ на: комментарий от micronekodesu

сначала получение и отображение данных разнеси на разные циклы

quester ★★ ()
Ответ на: комментарий от micronekodesu

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Obje...

Плюс тебе понадобится фабрика, что-то типа

let РАДУЖНАЯ_ФАБРИКА = (ЭЛЕМЕНТ) => fetch('http://natribu.org/' + ЭЛЕМЕНТ)

Promise.all(СПИСОК.map(ЭЛЕМЕНТ => РАДУЖНАЯ_ФАБРИКА(ЭЛЕМЕНТ)).then(СПИСОК => {
 ... твоя лабуда выше
})

bodqhrohro_promo ()
Ответ на: комментарий от micronekodesu

Тащемта, да, так даже веселее будет — табличка будет весело наполняться по мере выполнения запросов ^_^

bodqhrohro_promo ()
Ответ на: комментарий от micronekodesu

Тебе правильно сказали заюзать промисы и прочую херь.

Но! Есть ощущение, что ты что-то делаешь не так. Отдельный запрос для ячейки — ужс. Вот если на бекенд тебе никак не залезть, тогда мучайся с колбеками, тут уж ничего не поделать. А вот если можно на бекенд, то там и надо собирать полностью весь (JSON) объект данных для всех ячеек и одним ответом отдавать. И это нормально, т.к. ты не тратишь время на лишние запрос-ответ и тащишь данные с хранилища «на горячую». Гибкость сервиса не в его фронте, а именно в бекенде. Фронт он же тупо вьюха, пусть и с мильеном перделок.

deep-purple ★★★★★ ()
Ответ на: комментарий от bodqhrohro_promo

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

Вот лично я не встречался с такой проблемой. Мои проекты на реакте в районе 3к-5к строк кода, все работает быстро, на слабой машинке (макбук).

Продакшн сборка - 12 сек, дев - 0-1.

Наверное, для вебпака 3-5к строк это ниочем.

Deleted ()
Последнее исправление: Bizun (всего исправлений: 1)
Ответ на: комментарий от bodqhrohro_promo

Это типа много?!
Наверное, для вебпака 3-5к строк это ниочем.

Читать умеешь?

Это типа мало?! По сравнению с сохранил-перезагрузил?!

Продакшн сборку я делаю не чаще раза в день. Эти 12 секунд, которые я на нее трачу, экономят часы разработки.

Deleted ()

Блин, ну пиши в async стиле. Про вебпак - замени его на нормальный rollup, он собирает за миллисекунды, в отличии от тормозного вебпака. Async поддерживают все современные браузеры, примеры приводить глупо - всё в инете есть. И про оптимизацию - ты не можешь собрать все свои ячейки в один запрос? Сначала подготовь данные для запроса, а затем отсылай всё в объекте на свой бэкенд, если он твой, конечно.

menangen ★★★★★ ()
Ответ на: комментарий от bodqhrohro_promo

Ну как я и говорил, хэллоуворлд-левел.

Если ты собираешь десятки тысяч строк кода, ты делаешь что-то не так.

По сравнению с чем?

Ванильным жиэсом.

Deleted ()
Ответ на: комментарий от menangen

Сначала подготовь данные для запроса, а затем отсылай всё в объекте на свой бэкенд, если он твой, конечно.

Так в том то и проблема что у меня только «фронт» (ну фронт это очень громко сказано, конечно). На бэке типа REST, я могу за один запрос вытащить только одну сущность, не могу передать список элементов или что-то подобное.

Про вебпак - замени его на нормальный rollup

Вообще нет никакого желания разбираться в сортах, мне надо написать одну страничку один раз и все. Ничего там собирать по сто раз в минуту я не планирую (даже не смотря на то что это вообще дичь какая-то).

Async поддерживают все современные браузеры, примеры приводить глупо - всё в инете есть.

Так вопрос не в том как работает асинк или как его использовать, а в том что я не могу вернуть значение из ансинхронной функции, кроме как передав его в другую функцию (коллбэк). И это не всегда оправдано. Тупо x=2+2 посчитать, в случае асинхронного выполнения я не могу просто значение в переменную записать, мне надо весь код перековырять чтоб найти где оно там используется и уже туда его как-то подсовывать.

micronekodesu ★★ ()
Ответ на: комментарий от bodqhrohro_promo

Это типа мало?!

Конечно, мало. Местные тырпрайзы собираются вебпаком на мбп уже под 5 минут и будет хуже. Хотя по сравнению со временем на все тесты — копейки.

По сравнению с сохранил-перезагрузил?!

Мгновенный и автоматический hot reload с сохранением всего состояния страницы же. Никаких перезагрузок. Но в продакшн такое только совсем хипстеры выкладывают, там только скомпилированное.

x3al ★★★★★ ()
Ответ на: комментарий от micronekodesu

На бэке типа REST, я могу за один запрос вытащить только одну сущность, не могу передать список элементов или что-то подобное.

Зависит от того, что за REST. Уйма REST-фреймворков из коробки умеют принимать список ID. К остальным можно прикрутить. И есть GraphQL для хипстеров.

Так вопрос не в том как работает асинк или как его использовать, а в том что я не могу вернуть значение из ансинхронной функции, кроме как передав его в другую функцию (коллбэк).

await, но тогда либо забить на древнебраузеры, либо rollup/webpack. Совсем упоротые запускают babel в браузере, впрочем.

Конечно, это не панацея: await может быть только в async-функции, которая возвращает результат только асинхронно (т.е. Promise), следовательно, весь коллстэк заражается async/await'ом.

x3al ★★★★★ ()
Последнее исправление: x3al (всего исправлений: 1)
Ответ на: комментарий от x3al

Зависит от того, что за REST.

Да без разницы, там то я поправить ничего не могу. Да и ладно с ним, пусть мне нужно выполнять запросы к разным ресурсам, то есть я их объединить не могу. Что тогда?

await, но тогда либо забить на древнебраузеры, либо rollup/webpack. Совсем упоротые запускают babel в браузере, впрочем.

Как вы вообще в одном предложении сравниваете кусок языка для ожидания завершения асинхронного вызова (при том что просто ожидание, результаты его я все равно не получу) и какие-то системы сборки модулей?! И все равно это никак мне не помогает избавится от этих коллбэков. Вообще я даже не понимаю на кой мне тут этот await сдался, мне пофиг выполнится ли код повесив основной поток или сделает это где-то в стронке, мне надо результаты получить и использовать их дальше в том месте кода, где мне это нужно, а не где это решили там прилепить просто потому что.

micronekodesu ★★ ()
Ответ на: комментарий от Deleted

ты делаешь что-то не так

NO U.

Ванильным жиэсом

Исследования влияния сахарка на продуктивность встудею. Не сопутствующих библиотек и фреймворков, а именно сахарка.

bodqhrohro_promo ()
Ответ на: комментарий от bodqhrohro_promo

Полный билд продакшна — >5 минут. Инкрементальный live-ребилд в dev-режиме мгновенный. Это так сложно?

x3al ★★★★★ ()
Ответ на: комментарий от micronekodesu

никак мне не помогает избавится от этих коллбэков

const data = await fetch('https://what.ever/'); и можешь работать без коллбэков в этой же функции. Коллбэки для старых браузеров (если нужны) за тебя напишет babel. Стандарт для склеивания выхлопа babel с regenerator-runtime, полифилом fetch и прочим шлаком — webpack, сойдёт и rollup, тут и появляются модули.

x3al ★★★★★ ()

Поставь typescript вместо бабеля. И быстрее, и проще.

Shadow ★★★★★ ()
Ответ на: комментарий от micronekodesu

На бэке типа REST, я могу за один запрос вытащить только одну сущность, не могу передать список элементов или что-то подобное.

Так вопрос не в том как работает асинк или как его использовать, а в том что я не могу вернуть значение из ансинхронной функции, кроме как передав его в другую функцию (коллбэк). И это не всегда оправдано. Тупо x=2+2 посчитать, в случае асинхронного выполнения я не могу просто значение в переменную записать, мне надо весь код перековырять чтоб найти где оно там используется и уже туда его как-то подсовывать.

let list = [];

async function fetchAll() {
    list = await Promise.all([
        fetch('http://example.com/1'),
        fetch('http://example.com/2'),
        fetch('http://example.com/3'),
        fetch('http://example.com/4'),
        fetch('http://example.com/5'),
    ]);
}

fetchAll();
static_lab ★★★★★ ()
Ответ на: комментарий от Shadow

C#

Ну вот async/await оттуда и притащили.

треды

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

bodqhrohro_promo ()
Ответ на: комментарий от x3al

В старых браузерах и так JS-движки тормозные, а если их ещё высранной бабелем лапшой кормить, так ващееее. Не, надо писать изначально, чтобы в IE5 работало, а под остальные говнобраузеры уже лепить костыли.

bodqhrohro_promo ()
Ответ на: комментарий от bodqhrohro_promo

В теории можно, но с такими ограничениями стоимость разработки современного веб-приложения, умеющего всё от hidpi до выступа ябблофона будет космической и конкуренты задавят. Плюс нелегко найти квалифицированных кодеров, которые за (любые) деньги будут трогать IE5 руками, а не через тысячу полифиллов.

x3al ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.