LINUX.ORG.RU

node.js promise vs callback

 ,


0

1

Привет всем, у меня импорт на node.js, ему надо десятки тысяч страниц обойти, и получается функция делает запрос и потом вызывает саму себя, то есть рекурсия, и в стаке вызовов функций выходит функция вызывает себя десятки тысяч раз и наверняка из-за этого память лишняя и нагрузки больше. Обычным циклом, понятное дело, нельзя. А промисы? Недопонял их архитектуру, главное не понял зачем это вообще надо. Если вместо колбека для запроса использовать промис - это хоть что-то изменит в лучшую сторону? Вопрос загуглить очень просто, материала по разным подходам много, но все же что есть лучшее с точки зрения производительности?

Если очень много колбеков, можешь иногда дергать Process.NextTick, setTimeout, setImmediate и т.п. После этого стек теряется и отсчет начинается заново.

https://learn.javascript.ru/generator#библиотека-co

Промисы нужны вместе с генераторами. Получается код, который выглядит как синхронный. Без генераторов на промисах получается не намного лучше чем с колбеками.

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

Промисы нужны вместе с генераторами. Получается код, который выглядит как синхронный. Без генераторов на промисах получается не намного лучше чем с колбеками.

Или сразу async/await + Babel и не мучиться.

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

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

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

Ну я же их не в рантайме гоняю. Нет, не напрягает вообще.

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

Кстати, кроме асинка генераторы-то и так достаточно мало где нужны. И ещё — я тривиальному полифиллу из async/await в генераторы верю больше, чем написанию генераторов с этими же целями ручками.

И да, в седьмой ноде у нас уже должен быть async/await за флагом. Но опять же — в продакшне лучше использовать полифилл, чем фичу за `--harmony-*` флагом.

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

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

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

Я просто не вижу разницы между async/await и co/yield, а костылять то чего нет в LTS неохота. Наигрался уже в новые фичи ноды, надо делом заниматься, код кодить.

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

Промисы это всякая асинхронная хрень в функциональном стиле. Без них тебе наверняка под колбеки потребуется библиотека async или что-то подобное.

Посмотри `bluebird` - самый яркий пример что можно делать из промисов. Это для ознакомления, использовать в чистом виде не агитирую.

Нехватка оперативки - не похоже на стек, он обычно раньше кончается. Если у тебя ресурсоемкие задачи, а не просто большой цикл - заведи очередь, нарежь на чанки и скармливай туда, вместо того чтобы самопальные рекурсии изобретать. Из модного я знаю только kue, но себе мы запилили собственный лисапед на редиске https://github.com/nodeca/nodeca.core/tree/master/lib/queue. Всё не соберусь в пакет оформить.

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

Cпасибо, промисы я понял чтобы колбеки в цепочку организовывать, без чего можно жить спокойно

Колбек ты передаешь при вызове функции, он у тебя в этот момент уже должен быть подготовлен. А промис ты можешь сначала вызвать а уже потом думань «а нужно ли мне еще что нибудь делать после его завершения?», можно ничего не делать, можно потом как нибудь получить результат работы промиса... + «колбек» промиса возвращает промис и можно строить цепочки + ты можешь решить что тебе надо дождаться выполнения не одного промиса а целой пачки одновременно + обработка ошибок, там так то 2 «колбека»...

В общем это принципиально разные вещи.

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

Первый короче. Плюс co дропнут как только, так сразу, и всё равно потом переписывать всё на async/await. Так что если у тебя всё на co — то да, пока можно не дёргаться, но если ты сейчас решаешь, взять в руки co или async/await в проекте, который ты ещё планируешь поддерживать — смело выбирай async/await.

Плюс async/await даёт нормальный синтаксис, в котором гораздо легче ловить ошибки до выполнения — мы уже после парсинга скрипта понимаем, что происходит. Ну и семантика у него нормальная (для человеков).

И да, есть некоторые шансы на то, что уже в v7.0 async/await будет без флагов (но скорее всего таки за флагом, конечно).

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

А, а вот в LTS асинк только следующей осенью прилетит. Не этой.

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

я вот смотрю на пример async/await

export function logout(router) {
  return async (dispatch) => {
    try {
      const {data: {success, message}} = await axios.get('/logout');
 
      (success)
        ? dispatch({ type: LOGOUT_SUCCESS })
        : dispatch({ type: LOGOUT_FAILURE, message });
 
     } catch (e) {
         dispatch({ type: LOGOUT_FAILURE, e.data.message });
     }
   };
}
это ведь практически те же самые промисы, только хуже — нужно городить коллбеки внутри конструкции. То есть те же самые промисы, только хардкорные. Не сказать, что это лучше чего бы то ни было, даже если брать ванилу. Неуклюжее говно

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

Ты откуда этот код взял? Честно говоря, тут похоже на то, что этот код — неуклюжее говно. Зачем оборачивать функцию? `router` вообще не используется. Плюс ты передаёшь каллбэк `dispatch` внутрь async функции и возвращаешь из неё по каллбэку. А потом удивляешься.

Выкинь это нафиг и перепиши заново нормально =).

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

в любом случае, я не понял, чем это может быть лучше промисов, если это и есть имитация промисов

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

А почему легче ошибки ловить? Разве там не будет стандартной промисопроблемы с просиранием стека?

PS. У меня вот на такой штуке https://github.com/nodeca/event-wire весь проект сделан, там с yield на await перейти можно будет «поиском и заменой».

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

то что выше, касалось, собственно, библиотеки, что же касается es7 async/await, это другая история, там сахар, который при добавлении ключевого слова async оборачивает содержимое асинхронных функций в промис. То есть это уже сахар над промисами. Это еще имеет смысл какой-то. Но если у тебя и так все функции возвращают промисы, это не очень то и нужно.

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

Я про дурацкие ошибки в коде =). Хотя глянул на co ещё раз, там всё несколько лучше, чем я думал, но объявлять функции всё равно неудобно.

С async/await можно, например, написать правила для статического анализатора, которые проверяют, что мы их правильно используем. С `co` это тоже возможно, но будет сложнее и гораздо менее надёжно.

Вот, например: https://github.com/avajs/eslint-plugin-ava/issues/123

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

то что выше, касалось, собственно, библиотеки

async/await

Библиотека не называется «async/await». Библиотека называется «async», и к async/await она отношения не имеет. И это несколько не то, что стоит использовать в 2016 в новом проекте =).

es7

Для справки: «es7» (на самом деле ECMAScript 2016) уже давно вышел и там нет async/await.

То есть это уже сахар над промисами. Это еще имеет смысл какой-то.

Бинго! Ты добрался до матчасти =), молодец. А то выше ты писал, что async/await это «имитация промисов», а это чушь.

Но если у тебя и так все функции возвращают промисы, это не очень то и нужно.

Но, кажется, ты прочитал только про ключевое слово «async». Читай дальше, там ещё про «await» есть.

ChALkeR ★★★★★ ()

Может, не на асинхронном языке попробуешь?

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

Да не, на node.js очень даже норм, тему создал просто чтобы понять что работает лучше: promise или callback, не правильнее или понятнее выглядит, а быстрее работает, скатилась в срачь понятное дело. Пусть кидают помидоры, но iced coffeescript по удобности писания проще async/await и promise на столько же, как и coffeescript проще js. Так вот, не асинхронный язык. Сначала писал на руби, на node.js переписывал потому что на синхронном языке оно работает во много раз дольше. Да, руби медленный, но время в основном на получение страниц уходит, и тут только асинхронность спасет.

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

То есть за счет создания тредов и управления ими? Нода великолепна тем, что это встроено в саму её суть и о потоках думать не надо, надо только о промисах или колбеках. Переписывать все на что-то другое ради призрачной возможности ускорить - увы, просто времени нет. Но на будущее, посоветуете годную альтернативу, где потоками так же удобно пользоваться, как волшебная асинхронность ноды, шоб работало ещё быстрее? Как фанат lua я бы на ней попробовал, но это изначально смехотворно.

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

Ну, не такой уж он и медленный. Легко на рельсах выдавали 500 страниц в секунду на дохлой виртуалке (примерно 1/5 по мощности от DigitalOcean).

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

Слушай, эти тесты уже весь мир видел и обсудил, хоть кто-нибудь видел исходники тестов? Что они там натестировали - одному богу известно. Тестировать нужно самому на своих примерах. У меня Rails выдаёт 400-500 ответов в секунду, Django около 600-700 под Cpython и 900-1200 под pypy. По-моему, это нормальная производительность. Node.js на простых задачках выдаёт 4500 ответов в секунду, но мне такая ультра нагрузка не нужна, в конце концов есть vibe.d и iris-go.

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

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

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

То есть за счет создания тредов и управления ими? Нода великолепна тем, что это встроено в саму её суть и о потоках думать не надо, надо только о промисах или колбеках.

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

Я уже не говорю о том, что сложную логику на колбеках писать не очень удобно. Можно, но в синхронном стиле удобнее.

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

Парсеры я писал на Scrapy, скорость вполне отличная, но сам Scrapy я бы переписал - там движок немного наркоманский из-за как раз этих наркоманских асинхронностей.

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

Мне 20 почти, и вовсе нет там таких проблем страшных - трейсбек никуда не подпадает, домены - даже не знаю что с ними не так, в общем ничего там страшного нет.

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

Начнешь использовать - узнаешь, каким ты был оптимистом :)

Если луа хотел - возьми тарантул, они последнюю версию позиционируют как луа-платформу, где тарантул такой же модуль как все остальное.

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

В промисах стек вообще потерять как нефик делать.

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

pavel-g ()
Ответ на: комментарий от Vit

В промисах стек вообще потерять как нефик делать.

Интересно взглянуть на пример с потерей стектрейса в промисах.

pavel-g ()
Ответ на: комментарий от pavel-g

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

А в итоге иногда в лог пишется, что из таймера вылетела неведомая херня и немедленно упала. Потом сиди и гадай причину. Особенно много лулзов с yield и корутинными обертками.

В реальной жизни бывает многое, чего быть не должно :)

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

А что сложного в потоках? Написал синхронную функцию передал ее в новый поток и все дела. Сразу исчезают колбеки и промисы.

Int0l ()
Последнее исправление: Int0l (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.