Существуют ли идиоматические способы выражения «if (c1 || c2)» в JavaScript, когда одно из условий является обещанием, а другое - нет?

Когда я выполняю только следующие шаги в моем алгоритме, если выполняются различные условия, я выражаю это следующим образом:

if (sc1 || sc2) {
  do();
  various();
  things();
}

Когда я выполняю только следующие шаги, основанные на выполнении обещания, я могу выразить это следующим образом:

asyncCheck().then(ac1 => {
  if (ac1) {
    do();
    various();
    things();
  }
}

Как я могу выразить в идиоматическом JavaScript, когда условиеsc1 это просто обычное старое синхронное выражение, но условиеac2 приходит асинхронно через обещание?

Предположим, собственные обещания ES6 и нетривиальный код, который выполняется, если выполняются условия.

Например, этот «очевидный» способ кажется уродливым:

if (sc1) {
  do();
  various();
  things();
} else {
  asyncCheck().then(ac2 => {
    if (ac2) {
      do();
      various();
      things();
    }
  }
}

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

Я должен также добавить это наблюдение: так как в моем случае, есть логическое или, оно должно закорачиваться, чтобы не беспокоить медленная отложенная проверка, если простая проверка ужеfalse.

 user110692519 июн. 2016 г., 16:09
... и, конечно, вы можете использовать логическое ИЛИ тожеmy_func(sc1) || asyncCheck().then(my_func)
 user110692519 июн. 2016 г., 16:12
Или, если у вас есть несколько случаев этого, выделитеif в универсальную функцию, которая принимает условие «синхронизация» и обратный вызов. затемmaybeAsync(sc1, function() { do(); various(); things() })
 hippietrail19 июн. 2016 г., 16:02
@Pointy: я думал об этом, но тогда я не мог замкнуть|| если условие не обещания ложно. Я мог бы добавить это к вопросу.
 user110692519 июн. 2016 г., 16:01
Повторный кодуже в функции. Просто переместите его и дайте ему имя. Вы можете вернуть результат условия, поэтомуif (!my_func(sc1)) { asyncCheck().then(my_func) }
 hippietrail19 июн. 2016 г., 16:22
@ Squint: Последнее предложение является одним из наиболее многообещающих видов решений, которые я обдумывал. (Простите за каламбур)
 Pointy19 июн. 2016 г., 15:58
Оберните не-Обещание в Обещание и используйтеPromise.all()? редактировать о, подожди, ты хочешь|| ...

Ответы на вопрос(3)

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

function or(v1, v2, ifPath, elsePath) { 
   v1 = Promise.resolve(v1);
   v2 = Promise.resolve(v2);
   return Promise.all([v1, v2])
          .then(([v1, v2]) => (v1 || v2) ? ifPath() : elsePath());
}

Что позволит вам сделать:

or(ac1, ac2, () => {
  do();
  various();
  things();
}, () => {});

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

Promise.all([ac1, ac2]).then(([r1, r2]) => {
   if(r1 || r2) { 
      do();
      various();
      things();
   }
});

Который легче и легче сочинять. В следующей версии JavaScript (ES8, ES2017) вы, скорее всего, будете иметьasync/await что позволит вам сделать следующее напрямую:

// the function containing this needs to be marked as `async`
if (sc1 || await sc2) {
  do();
  various();
  things();
}

Который сделает вещи проще. Это все еще немного негерметично, но гораздо менее.

 Benjamin Gruenbaum19 июн. 2016 г., 17:08
Да, я сказал, что нет. @ Squint его решение не работает, хотя.
 Benjamin Gruenbaum19 июн. 2016 г., 17:47
@squint приведет к аварийному завершению процесса NodeJS в будущей версии и, скорее всего, запишет отказ в stderr в следующем выпуске. Не говоря уже о том, что не имеет дело с ошибкой.
 Benjamin Gruenbaum19 июн. 2016 г., 16:28
@squint обратите внимание на деструктуризацию массива в аргументе функции.Promise.all([v1, v2]).then(([p1, p2]) => который открывает массив для вас, если вы называетеvс иpи то же самое, что и в ответе. Я могу создать скрипку, если хотите.
 user110692519 июн. 2016 г., 16:47
Но если он должен создать больше обещаний представлятьac2тогда это становится все длиннее и сложнее, и демонстрирует мою точку зрения. Его решение намного чище.
 user110692519 июн. 2016 г., 17:09
@BenjaminGruenbaum: Определить"не работает".
 user110692519 июн. 2016 г., 16:25
Я пытаюсь понять, как это будет работать. Не приходит ли второе условиеот результат асинхронной операции? Кажется, вы используете его до того, как он станет доступен, но, возможно, я просто не правильно его читаю.
 Bergi19 июн. 2016 г., 17:07
Promise.all не похоже на короткое замыкание
 Bergi19 июн. 2016 г., 17:14
@BenjaminGruenbaum: Ах, описание "Вы можете сделать гораздо более простыезвучало так, как будто это было короткое замыкание.
 hippietrail19 июн. 2016 г., 16:26
Я умирал, чтобы играть сasync / await! Мне нравится ваш мыслительный процесс здесь. Это самый дидактический ответ на данный момент.
 Benjamin Gruenbaum19 июн. 2016 г., 16:38
@squint Я только что предположил, что ac1 и ac2 - это проверяемые логические значения или обещания логических значений. Обещания стоят того, чтобы их изучить, и я уверен, что вы полюбите их, кстати, - их трудно поначалу понять, но когда вы их используете, они делают вашу жизнь намного проще - это вернее в Node, чем в клиенте, где вы имеют сложные асинхронные рабочие процессы.
 hippietrail19 июн. 2016 г., 16:41
даac1 а такжеac2 являются логическими значениями, но могут быть выражениями или чем-то еще логическим. В моем реальном коде я извлекаю JSON и разрешаю истину или ложь после проверки возвращаемого объекта.
 Benjamin Gruenbaum19 июн. 2016 г., 16:41
@squint обещанияявляются часть языка. Они так же много JavaScript, какDate или жеArray, Все новые API, такие какfetch верните их и используйте их асинхронные функции. Любая из этих вещей (ac1 или ac2) может быть обещанием - так что вы будете передавать обещания напрямую. Признаюсь, я не очень понимаю соглашение об именах.
 user110692519 июн. 2016 г., 17:51
@BenjaminGruenbaum: якобы и предположительно может произойти сбой, и вашапредположение что ошибка еще не обработана означает, что она "не работает"? Поработайте над своим ответом. Он использует условие, которое еще не существует.
 user110692519 июн. 2016 г., 16:31
Но я имею в виду, что вы звоните сor(ac1, ac2, () => {..., В вопросе он имеетsc1 а такжеac2 условия. Они вместо этого функционируют в этом случае? Я не использую Обещания, поэтому, пожалуйста, извините за мои вопросы.
 user110692519 июн. 2016 г., 16:39
Но это то, что я имею в виду. В исходном кодеac2 не будет доступен до окончания асинхронной операции, поэтому я не понимаю, как ее можно передать. Я должен признать, что у меня есть сильный уклон против таких вещей, как обещания. Я считаю, что полная выразительность языка делает код более простым и понятным, чем ограничения абстракции.
 Benjamin Gruenbaum19 июн. 2016 г., 16:41
@hippietrail, тогда в вашем примере все будет работать нормально, если они либо логические, либо обещают логические.
 user110692519 июн. 2016 г., 16:46
@BenjaminGruenbaum: Обещания являются частью библиотеки, определенной в спецификации. Они являются абстракцией над конструкциями уровня языка. Но прежде, чем мы начнем оспаривать педантизм, дело в том, что они излишни и ограничены. Люди пытаются втиснуть в них все, и в итоге получают более длинный и менее понятный код, чем если бы они только что продумали проблему, используя имеющиеся у них инструменты.await Синтаксис - это конструкция уровня языка, и он имеет гораздо больший смысл в качестве решения. Решение на уровне библиотеки имело смысл (для тех, кто хотел его), когда язык не мог с этим справиться.
 Benjamin Gruenbaum19 июн. 2016 г., 16:30
@hippietrail хорошо в синей птице у нас естьPromise.coroutine который позволяет вам делать сопрограммысегодня с генераторами. Мы вряд ли изобрели это - у Q это тоже есть, а также у многих других бегунов. Фактически создание полностью правильного асинхронного ожидания с генераторами - это упражнение из 10 строк кода :) Если вам нравится асинхронное ожидание, обязательно рассмотрите его. Я планирую написать транспортер, который идет другим путем для моего собственного кода (преобразование сопрограмм в асинхронные функции), и некоторое время я использовал сопрограммы. Для справки: async / await приземлился в Чакре (Edge) год назад и в V8 (Chrome) 2 недели назад.
Решение Вопроса

Promise.resolve(sc1 || asyncCheck()).then(cond => {
  if (cond) {
    do();
    various();
    things();
  }
});

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

(sc1 ? Promise.resolve(true) : asyncCheck()).then(cond => { … });
 Bergi19 июн. 2016 г., 17:51
@hippietrail: Также взгляните наесли с асинхронным случаем или жеесли-либо еще в обещании - короткое замыкание|| оператор не что иное, как сахар для оператора if-else.
 user110692519 июн. 2016 г., 17:10
Гдеac2 приходящий из?
 user110692519 июн. 2016 г., 17:17
Ну, по крайней мере, это демонстрация как чистого, так и правильного использования Обещаний для данной ситуации, поэтому я должен дать +1 за это.
 hippietrail19 июн. 2016 г., 17:44
Хорошо, теперь это то, на что я надеялся, когда сказал «идиоматический»! Выглядит мило, поэтому я попробую и вернусь, чтобы проголосовать ...
 Bergi19 июн. 2016 г., 17:11
@ Squint: Я думаю, OP использовалasyncCheck() для этого. Я отредактирую

function ifConditionsMet() {
  if (sc1) {
    return Promise.resolve(true);
  } else {
    return asyncCheck();
  }
}

ifConditionsMet().then(() => {
  do();
  various();
  things();
});

Я это это должно работать нормально с любой обработкой исключений тоже ...

 hippietrail19 июн. 2016 г., 16:38
Да, это частично псевдокод, поскольку sc1 может быть параметрическим или глобально выполнимым. Важным моментом является то, что это синхронно.
 hippietrail19 июн. 2016 г., 17:48
Я не против понижать голос. Я не новичок в Stack (Overflow | Exchange), и я довольно много узнаю благодаря отзывам, которые привлек этот вопрос.
 Benjamin Gruenbaum19 июн. 2016 г., 18:09
@ Squint Я собираюсь выйти сейчас. Я не думаю, что я самонадеян, и я думаю, что вы грубите и что вы не понимаете обещаний, но ищете оправдания своей некомпетентности - вы, вероятно, чувствуете по-другому, и эта дискуссия не подходит ни одному из нас или доставит нас куда угодно. Давайте согласимся не соглашаться и, надеюсь, поговорим в следующий раз при более позитивных обстоятельствах.
 Benjamin Gruenbaum19 июн. 2016 г., 17:25
Кроме того, буквально никто не выступает за обещания как решение для всего. TC работает над различными примитивами - такими как асинхронные итераторы и наблюдаемые для решения различных вариантов использования.
 hippietrail19 июн. 2016 г., 16:46
В моем текущем коде это игрушка для личного использования и для самостоятельного обучения новым функциям js. Я бы расследовал любые отклонения по мере их появления. Но это хороший момент. Позвольте мне добавить «обещанную» версию. Обратный звонок среди обещаний уже казался мне запахом кода ...
 user110692519 июн. 2016 г., 18:36
Это то, что я нахожу удивительным ...ifConditionMet(my_func) == "плохо", тогда какifConditionMet().then(my_func) == "хорошо", по-видимому, из-за некоторого эфирного понятия идиоматического превосходства. Я думаю, что каждый должен найти религию где-то ...
 Benjamin Gruenbaum19 июн. 2016 г., 16:39
Извините за понижение, но у этого ответа есть некоторые фундаментальные проблемы. Даже если мы проигнорируем тот факт, что вы не передаете функцию в качестве обратного вызова в примере - что происходит здесь, еслиasyncCheck() отклоняет с ошибкой?
 Benjamin Gruenbaum19 июн. 2016 г., 18:01
@hippietrail downvote - это подсказка для вас, чтобы исправить ваш ответ, а не признак чего-либо отрицательного.
 Benjamin Gruenbaum19 июн. 2016 г., 18:05
@hippietrail следите за явной конструкцией антипаттерна, упомянутой Берги. Вы можете простоreturn обещания. См. Stackoverflow.com/questions/22539815/arent-promises-just-callbacks.
 user110692519 июн. 2016 г., 18:06
@BenjaminGruenbaum:«Вы не используете обещания, потому что не понимаете их даже малейшим образом». Я понимаю их. Я просто не знаю всех мелочей их синтаксиса, потому что я никогда не встречал ситуации, в которой стоило бы их изучать. Ты не честен; ты самонадеян. Это снова наводит на мысль о менталитете, в котором ваше личное мнение становится «правдой».
 Benjamin Gruenbaum19 июн. 2016 г., 16:40
Вы также, вероятно, хотите, чтобы функция возвращала обещание, чтобы ее можно было продолжить позже.
 Benjamin Gruenbaum19 июн. 2016 г., 18:00
Хотя мы честны - вы не используете обещания, потому что не понимаете их даже в малейшей степени. Я объяснил, почему я нашел ваш комментарийгрубый, а не мой ответ - когда вы попросили меня объяснить, что не так с другим ответом - я так и сделал. Это не фанатизм вообще.
 user110692519 июн. 2016 г., 17:53
@BenjaminGruenbaum:аргумент от власти Ошибка должна закончиться."... сотни ответов ... тысячи часов ... участие в библиотеках и узлах ... участие в спецификации", Ни один из них не уместен. Вы говорите, что это «плохо», но ваше определение «плохо» просто основано на вашей личной предвзятости. Это яркая демонстрация фанатизма. Я не использую Обещания, потому что я нахожу их совершенно ненужными, но я уверен, что не стоит принижать людей только потому, что они их используют.
 user110692519 июн. 2016 г., 17:33
@BenjaminGruenbaum: это правда. Случаетсявсе время с людьми здесь. Мне все равно, если люди используют обещания или нет, но куча людей прыгают на пустом месте«если ты не делаешь это по-моему, ты делаешь это неправильно» подножка. Фанатизм в программировании просто глуп.
 user110692519 июн. 2016 г., 17:37
@hippietrail: представь, что у тебя не было обещаний. Что бы вы сделали? Вы, вероятно, просто перезвонитеasyncCheck, Тогда это так же, как ваше первое решение, но без всей проблемы«исправить решение», Поскольку это универсальная функция, она закрываетсяsc1 и избежать асинхронного вызова таким же образом. Или вы можете передать условие и иметь возможность использовать его таким образом в других местах. Мне все равно, что вы используете, но будьте непредвзяты к простым решениям, которые не следуют последним тенденциям.
 Bergi19 июн. 2016 г., 17:17
Ваша вторая реализация должна избегатьPromise конструктор антипаттерн!
 Benjamin Gruenbaum19 июн. 2016 г., 17:24
@ Squint Честно говоря, я считаю ваш комментарий грубым. Может быть, это не то, что яхочу чтобы понизить голосование, может быть, я ненавижу понижение голоса и сделал только так, чтобы он мог решить проблему? Может быть, мои знания основаны не на том, что мне понравилось, а на сотнях ответов и тысячах часов на изучение предмета, а также на участие в спецификации и участие в двух наиболее перспективных библиотеках и самом узле? Возможно ли, что я простоне соглашаться с вами о том, является ли это хорошим решением? Это пришло тебе в голову, я пытаюсьПомогите ОП достичь хорошего решения, а не страдать с плохим?
 user110692519 июн. 2016 г., 17:55
@hippietrail: это не столько голосование; это помпезный"мой путь или шоссе" отношение, и если вы вызываете их на это, вдруг, вы«Грубый», Такое высокомерие.
 Benjamin Gruenbaum19 июн. 2016 г., 18:12
@hippietrail ваше последнее решение выглядит корректно, вы можете немного изменить его и получитьconst ifConditionsMet = (sc1, fn) => Promise.resolve(sc1 || fn()); а затем сделатьifConditionsMet(sc1, asyncCheck).then(... для более короткого кода. Первое решение все еще неверно, потому что еслиasyncCheck Бросает ваш код, не обрабатывает его - обещание отклонить, и никто не слушает, как необработанное исключение.
 user110692519 июн. 2016 г., 18:15
@BenjaminGruenbaum: некомпетентность требует еще одной глупой попытки установить власть. Я прямо признал, что не использую обещания. Это делает кого-то некомпетентным? Если бы я пытался проинструктировать кого-то о том, как и когда их использовать, и делал ошибки при этом, это было бы иначе. Я просто говорю, что пользуйтесь ими, если хотите, но держите себя открытым. Тот факт, что вы обвиняете меня в некомпетентности только потому, что я предлагаю альтернативные решения, еще раз подтверждает мою точку зрения.
 hippietrail19 июн. 2016 г., 18:00
На самом деле в этом конкретном случае я не нашел никакого отношения, хотя я встречал такое во многих других случаях на SO и других форумах. На самом деле я воспринял это как продолжение работы над моим кодом до такой степени, что он заслуживает одобрения. Я действительно ценю, как в печатном тексте коннотации и отношения настолько субъективны.
 hippietrail19 июн. 2016 г., 18:15
На самом деле, я всегда боролся с цепочкой обещаний в своем собственном коде, хотя это, казалось, имело смысл в коде других людей. При написании этой версии с помощью паттерна я почувствовал некоторый запах кода, и помощь от вас обоих помогла мне точно определить и понять это (-: теперь я могу выбросить версию обратного вызова, и моя версия обещания - только незначительные мутации / рефакторинги из представленного идиоматического решения я чувствую ...
 user110692519 июн. 2016 г., 16:51
Вот что происходит ... люди хотят отстаивать Обещания как решение всех проблем, поэтому они придумывают воображаемые проблемы в качестве обоснования для отказа в голосовании любого простого, чистого решения, которое их не использует. ЕслиasyncCheck отклоняется с ошибкой, тогда, очевидно, условие не выполнено ... и может случиться так, что он обрабатывает ошибку в этой функции в общем виде.
 Benjamin Gruenbaum19 июн. 2016 г., 17:38
@squint Я был здесь, следя за тегом обещания (и Берги), по крайней мере, 3 года. Я буквально никогда не видел, чтобы это случилось. Отсылать все асинхронные действия к обещаниям - это не просто фанатизм, это явно неправильно и демонстрирует отсутствие фундаментального понимания обещаний и того, чем они являются. Обещания сияют как DSL для составления асинхронных действий - они значительно облегчают вашу жизнь в сложных потоках и всеми средствамиделать рассмотрите возможность их изучения - но они ничего не заменяют и не упрощают этот случай, поскольку здесь есть только одно асинхронное действие.

Ваш ответ на вопрос