Js Deferred/Promise/Future по сравнению с функциональными языками, такими как Scala
Я в основном использую языки программирования, такие как Scala и JavaScript. Я пытаюсь понять сходства и различия в том, как асинхронное реактивное программирование используется на обоих языках. Вы можете мне помочь?
Я не принимаю какие-либо конкретные Js Promise
Framework, потому что, кажется, многие реализуют аналогичные спецификации (например, Promise/A). Я только использовал Q до сих пор.
Кажется, что в Javascript мы называем Deferred
объект, который мы решили завершить Promise
, В Scala, кажется, Promise
это объект, который вы решили получить Future
монада.
Может кто-нибудь сказать мне, если это правильно? Есть ли веская причина для другого использования термина Promise
между Джи и Скалой?
Кроме того, в Скала мы обычно цепочки Future
монады с дальнейшими вычислениями с использованием таких операторов, как map
а также flatMap
(также называемый bind
в Хаскеле). Что является эквивалентом этого в Js?
Я могу ошибаться, но мне кажется, что в Js then
на Promise
вид ручки как map
а также flatMap
операторы верно? Если это так, возможно ли получить promise of promise of result
в Js? Как мы можем получить Future[Future[Result]]
в Scala (который может быть сведен к Future[Result]
тем не мение).
Это Js Promise
монада? Это выглядит так, даже если имена методов не совпадают с теми, которые мы встречаем в литературе по монадам.
3 ответа
И да и нет.
Пока крайне похоже. С обещаниями JavaScript, соответствующими спецификации Promises/A+ .then
на самом деле не монадическая привязка и делает .map
а также .flatMap
и то и другое. Внутри .then
Обработчик, когда вы вернете обещание, он будет рекурсивно развернут.
Promise.delay(1000).then(function() {
return Promise.delay(1000).then(function () {
return Promise.delay(2000);
}).then(function () {
return Promise.delay(5000)
});
}).then(function () {
alert("This is only shown after 8 seconds and not one");
});
Вы правы, что стандартные библиотеки обещаний JS и спецификация A + не содержат монадических обещаний. Они были обсуждены, и реализации как обещания фантазии существуют. Они следуют отличающимся спецификациям и имеют небольшое принятие. Также посмотрите это. Об этом продолжалось обсуждение на форуме по языковой разработке - esdiscuss и monadic. .chain
метод, который не отображает и допускает монадические обещания, рассматривается, но вряд ли удастся это сделать.
Это по прагматическим причинам. Нынешний способ выполнения обещаний чрезвычайно полезен. Редкие случаи, когда вы действительно хотите Future[Future
и обычно вы хотите, чтобы продолжения просто работали на языке. Обещания "заимствуют" у монад и в некотором смысле являются "монадическими". .then
очень близко, чтобы связать, и в моей голове я использую их взаимозаменяемо:)
Невозможно иметь Promise[Promise[Value]]
как Future[Future[Value]]
в Scala с большинством многообещающих библиотек. Вы должны были бы обернуть это в объект и иметь Promise[Container[Promise[Value]]]
,
Promise.delay(1000).then(function () {
return Promise.delay(1000).then(function () {
return {
wrap: Promise.delay(2000).then(function () {
return Promise.delay(5000);
})
};
});
}).then(function () {
alert("This logs after 1 second");
// I've also not seen a really solid use case
// except TypeScript type inference which is meh
});
Существует также ряд других небольших различий между ними, но в целом вы правы в своих утверждениях.
Похоже, что в Javascript мы называем Deferred объект, который решаем, чтобы завершить Обещание. В Scala кажется, что Promise - это объект, который вы решаете получить в будущем.
Может кто-нибудь сказать мне, если это правильно? Есть ли веская причина для> разного использования термина Promise между Js и Scala?
В Scala Promise и Future разделили функциональность, Future - это контейнер асинхронных вычислений, который возвращает вам какое-то значение в будущем, а Promise - часть написания асинхронных вычислений, которую вы можете сделать следующим образом.
val promise = Promise[String]
val future1 = promise.future
val future2 = future1.map { case s => println(s); s }
future2.onSuccess { case s => println(s + " 2nd time") }
promise.success("promise completed")
Как только вы выполните последнюю инструкцию, вывод будет
promise completed
promise completed 2nd time
В Scala вы читаете значение из Future, используя onComplete, или цепуете его, используя map, и пишете в Future, используя его аналог Promise.
В спецификации JS Promise A+ они объединены, Promise.then
используется как для цепочки, так и для получения значения для побочного эффекта (например, console.log), для записи вы будете использовать resolve
как фрагмент кода ниже
var promise = new Promise(function(resolve, reject){
Thread.sleep(10000);
resolve("promise completed");
}
Я пытаюсь понять сходства и различия в том, как асинхронное реактивное программирование используется на обоих языках.
Этот документ здесь не сравнивает обещания Javascript со Scala, но вместо этого обещания Javascript с C++ C# и Python: https://github.com/KjellSchubert/promise-future-task. Я знаю, что это не совсем то, о чем вы просили, но, тем не менее, это может дать вам несколько интересных советов.
В отличие от Scala, JS Promise не является монадой из-за неявного "затем доступного" развертывания, нарушающего монадический закон. Однако вы можете реализовать монадическую семантику и функциональность на основе обратных вызовов, служа той же цели.
См, например, cpsfy
библиотека.
Кроме того, есть структурная разница из-за .then
принимает 2 функции, в то время как .chain
принимает только один. Однакоchain
принятие 2 или даже любого количества функций аргумента может быть реализовано, например, с CPS
обертка от cpsfy
:
//function returning CPS function with 2 callbacks
const readFileCps = file => (onRes, onErr) =>
require('fs').readFile(file, (err, content) => {
err ? onErr(err) : onRes(content)
})
// CPS wraps a CPS function to provide the API methods
const getLines = CPS(readFileCps('name.txt'))
// map applies function to the file content
.map(file => file.trim())
.filter(file => file.length > 0)
// chain applies function that returns CPS function
.chain(file => readFileCps(file))
.map(text => text.split('\n'))
// => CPS function with 2 callbacks
// To use, simply pass callbacks in the same order
getLines(
lines => console.log(lines), // onRes callback
err => console.error(err) // onErr callback
)