Отличие в том, что сам по себе синтаксис и конструкции языка не форсируют такой подход. Да, приведенный пример показывает, что можно явно разделить асинхронный и синхронный код и всё будет хорошо. Но это не значит что нельзя не разделять асинхронный и синхронный код. Получается страховка от ошибок на уровне договоренностей, а не на уровне конструкций языка. И именно в этом проблема.
В Scala (и scala.js) существуют и промисы (только используется другой нейминг, вместо Promise они называются Future) и async/await. И все предпочитают использовать именно промисы (фьючи). Причина в том, что async/await создает ложную иллюзию синхронности происходящего. Это может привести к тому, что синхронная и асинхронная логика будут смешаны вместе и в какой-то момент await потеряется перед асинхронной функцией. Или наоборот, await "на всякий случай" будет приписываться везде, даже если функция не асинхронная. При использовании промисов синхронные и асинхронные потоки явно отделены друг от друга. Глазами сразу видно, где тут у нас асинхронное выполнение, а где синхронное. И это потенциально более безопасно и не приведет к ошибкам, которые я выше описал.
Чтобы асинхронный код не превращался в кашу в Scala используется for-comprehension. И такой асинхронный код выглядит почти как синхронный, но при этом явно видно, где тут синхронные части, а где асинхронные.
В Scala/Scala.js коде пример выше выглядел бы примерно следующим образом:
def handleRequestArrows(user: User, sender: ResultSender): Future[SendingResult] {
val res = for {
_ <- isUserValidAsync(user)
(data, rate) <- Future.sequence(Seq(getUserDataAsync(user), getRateAsync("service")))
savedData <- updateUserDataAsync(user, updateData(data, rate))
sendingResult <- sender.send(savedData)
} yield sendingResult
res.andThen { // обычно это делают на уровне выше, но я добавил сюда, чтобы не отступать от примера
case Failure(e) => logger.log("An error ocurred", e)
}
}
Код вполне наглядный. Видно, что за чем идет. Если какой-то шаг вернет ошибку, то выполнение всего блока for-comprehension прервется.
В старой опере на жесты мышью можно было наложить намного больше действий. В Vivaldi количество доступных действий сильно ограничено. Например, я по движению влево/вправо перехожу на соседнюю (левую/правую) открытую вкладки. В текущей версии Vivaldi я не нашел такого действия для жестов. Есть ли это в новой версии? Планируется ли расширить набор действий для жестов?
Такая проблема встречается не только у вас. В комментах в блоге подсказывают, что если сменить встроенную JVM на стороннюю, то рендеринг шрифтов будет аналогичен 15 версии.
Хотелось бы услышать какой-то комментарий от представителей JetBrains по этому поводу. В блоге мне так и не ответили.
Я не говорил, что все нововведения в новых версиях JS — это сахар. Я сказал, что большинство — это синтаксический сахар. То есть это конструкции, которые можно выразить и в ES5, и в ES6. Яркий пример сахара — лямбды. Но, к примеру, символы — это не сахар, потому что в ES5 их не выразишь имеющимися средствами языка.
Обычное использование JS, и использование JS как compilation target — это совершенно разные вещи. Какая разница для компилятора, скомпилировать колбэк в обычную функцию, или в лямбду? Если бы лямбды работали быстрее, смысл был бы. Но на текущий момент ES6 работает медленнее, и у него худшая поддержка браузерами. Именно эту мысль я хотел донести.
Ребята, которые разрабатывают Scala.js экспериментировали с компиляцией в ES6. На текущий момент эти эксперименты показали, что скомпилированный в ES5 код работает быстрее. Для Kotlin, скорее всего, ситуация будет аналогична. К тому же, если использовать JavaScript как compilation target, то особого смысла в ES6/ES7 нет, там большинство нововведений — синтаксический сахар.
Если коротко, в Selenide каждый метод умеет немножко подождать, если надо. Люди называют это «умными ожиданиями».
Правильно я понимаю, что это должно полностью избавить от проблем со stale element reference exception? И каким образом реализовано это умное ожидание?
Отличие в том, что сам по себе синтаксис и конструкции языка не форсируют такой подход. Да, приведенный пример показывает, что можно явно разделить асинхронный и синхронный код и всё будет хорошо. Но это не значит что нельзя не разделять асинхронный и синхронный код. Получается страховка от ошибок на уровне договоренностей, а не на уровне конструкций языка. И именно в этом проблема.
Все асинхронные функции явно вынесены внутрь for блока. В случае с async/await синхронные и асинхронные функции перемешаны на одном уровне.
В Scala (и scala.js) существуют и промисы (только используется другой нейминг, вместо
Promiseони называютсяFuture) и async/await. И все предпочитают использовать именно промисы (фьючи). Причина в том, что async/await создает ложную иллюзию синхронности происходящего. Это может привести к тому, что синхронная и асинхронная логика будут смешаны вместе и в какой-то момент await потеряется перед асинхронной функцией. Или наоборот, await "на всякий случай" будет приписываться везде, даже если функция не асинхронная. При использовании промисов синхронные и асинхронные потоки явно отделены друг от друга. Глазами сразу видно, где тут у нас асинхронное выполнение, а где синхронное. И это потенциально более безопасно и не приведет к ошибкам, которые я выше описал.Чтобы асинхронный код не превращался в кашу в Scala используется for-comprehension. И такой асинхронный код выглядит почти как синхронный, но при этом явно видно, где тут синхронные части, а где асинхронные.
В Scala/Scala.js коде пример выше выглядел бы примерно следующим образом:
Код вполне наглядный. Видно, что за чем идет. Если какой-то шаг вернет ошибку, то выполнение всего блока for-comprehension прервется.
Хотелось бы услышать какой-то комментарий от представителей JetBrains по этому поводу. В блоге мне так и не ответили.
Обычное использование JS, и использование JS как compilation target — это совершенно разные вещи. Какая разница для компилятора, скомпилировать колбэк в обычную функцию, или в лямбду? Если бы лямбды работали быстрее, смысл был бы. Но на текущий момент ES6 работает медленнее, и у него худшая поддержка браузерами. Именно эту мысль я хотел донести.
Правильно я понимаю, что это должно полностью избавить от проблем со stale element reference exception? И каким образом реализовано это умное ожидание?
И все, что внутри пакета my.package, будет видеть это приватное свойство. В том числе и вложенные пакеты, типа my.package.inside.