- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
有同步 promise 的概念吗?使用promise语法编写同步代码是否有好处?
try {
foo();
bar(a, b);
bam();
} catch(e) {
handleError(e);
}
then
的同步版本);
foo()
.then(bar.bind(a, b))
.then(bam)
.fail(handleError)
最佳答案
Is there such a concept as a synchronous promise?
One instance I can think of is chaining promises together with sync code. While finding an answer for this question: Generating AJAX Request Dynamically Based on Scenario I wrapped a synchronous call in a promise in order to be able to chain them with other promises.
var run = function() {
getScenario()
.then(mapToInstruction)
.then(waitForTimeout)
.then(callApi)
.then(handleResults)
.then(run);
};
run
函数返回一个 promise ,该 promise 由链在一起的
getScenario
,
mapToInstruction
,
waitForTimeout
,
callApi
,
handleResults
和
run
本身返回的 promise 组成。
run :: Unit -> Deferred a
getScenario :: Unit -> Deferred Data
mapToInstruction :: Data -> Deferred Instruction
waitForTimeout :: Instruction -> Deferred Instruction
callApi :: Instruction -> Deferred Data
handleResults :: Data -> Deferred Unit
::
符号的意思是“属于该类型”,而->
符号的意思是“至”。因此,例如run :: Unit -> Deferred a
读为“run
的类型为Unit
到Deferred a
”。 run
是一个函数,它接受Unit
值(即没有参数)并返回Deferred a
类型的值。 a
表示任何类型。我们不知道a
是什么类型,也不在乎a
是什么类型。因此,它可以是任何类型。 Deferred
是一个promise数据类型(具有不同的名称),而Deferred a
意味着当promise解析后,它会产生a
类型的值。 run :: Unit -> Deferred a
getScenario :: Unit -> Deferred Data
getScenario :: Unit -> Deferred Data
mapToInstruction :: Data -> Deferred Instruction
mapToInstruction :: Data -> Deferred Instruction
waitForTimeout :: Instruction -> Deferred Instruction
waitForTimeout :: Instruction -> Deferred Instruction
callApi :: Instruction -> Deferred Data
callApi :: Instruction -> Deferred Data
handleResults :: Data -> Deferred Unit
handleResults :: Data -> Deferred Unit
run :: Unit -> Deferred a
then
方法。例如:
getScenario().then(mapToInstruction)
getScenario :: Unit -> Deferred Data
mapToInstruction :: Data -> Deferred Instruction
getScenario() :: Deferred Data -- because when called, getScenario
-- returns a Deferred Data value
getScenario().then(mapToInstruction) :: Deferred Instruction
then :: Deferred a -> (a -> Deferred b) -> Deferred b
then
是一个接受两个参数(
Deferred a
类型的值和
a -> Deferred b
类型的函数)并返回
Deferred b
类型的值的函数。”因此:
then :: Deferred a -> (a -> Deferred b) -> Deferred b
getScenario() :: Deferred Data
-- Therefore, since a = Data
getScenario().then :: (Data -> Deferred b) -> Deferred b
mapToInstruction :: Data -> Deferred Instruction
-- Therefor, since b = Instruction
getScenario().then(mapInstruction) :: Deferred Instruction
then :: Deferred a -> (a -> Deferred b) -> Deferred b
bind :: Monad m => m a -> (a -> m b) -> m b
bind
函数与
Function.prototype.bind
没有关系。此
bind
函数是
then
函数的概括。然后
then
函数特定于promise。但是,
bind
函数是通用的。它可以用于任何monad
m
。
=>
表示
bounded quantification。如果
a
和
b
可以是任何类型,则
m
可以是实现monad接口(interface)的任何类型。我们不关心
m
是什么类型,只要它实现monad接口(interface)即可。
bind
函数的方式:
function bind(m, f) {
return m.then(f);
}
bind(getScenario(), mapToInstruction);
then
函数的新数据类型:
// Identity :: a -> Identity a
function Identity(value) {
this.value = value;
}
// then :: Identity a -> (a -> Identity b) -> Identity b
Identity.prototype.then = function (f) {
return f(this.value);
};
// one :: Identity Number
var one = new Identity(1);
// yes :: Identity Boolean
var yes = bind(one, isOdd);
// isOdd :: Number -> Identity Boolean
function isOdd(n) {
return new Identity(n % 2 === 1);
}
bind(one, isOdd)
,我还可以轻松编写
one.then(isOdd)
(实际上更容易阅读)。
Identity
数据类型也是monad的一种类型。实际上,它是所有单子(monad)中最简单的。之所以称为
Identity
,是因为它对输入类型没有任何作用。它保持原样。
Identity
monad无效。这是原始数据类型。
bind
函数。还有一项操作尚待发现。实际上,用户
spike在他前面提到的评论中提到了它:
I wrapped a synchronous call in a promise in order to be able to chain them with other promises.
then
函数的第二个参数必须是返回promise的函数:
then :: Deferred a -> (a -> Deferred b) -> Deferred b
|_______________|
|
-- second argument is a function
-- that returns a promise
then
链接在一起。为此,我们将同步函数的返回值包装在promise中。例如,这是
spike所做的:
// mapToInstruction :: Data -> Deferred Instruction
// The result of the previous promise is passed into the
// next as we're chaining. So the data will contain the
// result of getScenario
var mapToInstruction = function (data) {
// We map it onto a new instruction object
var instruction = {
method: data.endpoints[0].method,
type: data.endpoints[0].type,
endpoint: data.endpoints[0].endPoint,
frequency: data.base.frequency
};
console.log('Instructions recieved:');
console.log(instruction);
// And now we create a promise from this
// instruction so we can chain it
var deferred = $.Deferred();
deferred.resolve(instruction);
return deferred.promise();
};
mapToInstruction
函数的返回值为
instruction
。但是,我们需要将其包装在一个Promise对象中,这就是我们这样做的原因:
// And now we create a promise from this
// instruction so we can chain it
var deferred = $.Deferred();
deferred.resolve(instruction);
return deferred.promise();
handleResults
函数中也做同样的事情:
// handleResults :: Data -> Deferred Unit
var handleResults = function(data) {
console.log("Handling data ...");
var deferred = $.Deferred();
deferred.resolve();
return deferred.promise();
};
// unit :: a -> Deferred a
function unit(value) {
var deferred = $.Deferred();
deferred.resolve(value);
return deferred.promise();
}
unit
函数,我们可以按以下方式重写
mapToInstruction
和
handleResults
:
// mapToInstruction :: Data -> Deferred Instruction
// The result of the previous promise is passed into the
// next as we're chaining. So the data will contain the
// result of getScenario
var mapToInstruction = function (data) {
// We map it onto a new instruction object
var instruction = {
method: data.endpoints[0].method,
type: data.endpoints[0].type,
endpoint: data.endpoints[0].endPoint,
frequency: data.base.frequency
};
console.log('Instructions recieved:');
console.log(instruction);
return unit(instruction);
};
// handleResults :: Data -> Deferred Unit
var handleResults = function(data) {
console.log("Handling data ...");
return unit();
};
unit
函数是monad接口(interface)的第二个缺失操作。概括后,可以将其可视化如下:
unit :: Monad m => a -> m a
unit
允许您将同步函数提升到该异步上下文中。同样,其他monad提供其他效果。
unit
与函数组合在一起,可以将函数提升到Monadic上下文中。例如,考虑我们之前定义的
isOdd
函数:
// isOdd :: Number -> Identity Boolean
function isOdd(n) {
return new Identity(n % 2 === 1);
}
// odd :: Number -> Boolean
function odd(n) {
return n % 2 === 1;
}
// unit :: a -> Identity a
function unit(value) {
return new Identity(value);
}
// isOdd :: Number -> Identity Boolean
function idOdd(n) {
return unit(odd(n));
}
compose
函数,它将看起来更好:
// compose :: (b -> c) -> (a -> b) -> a -> c
// |______| |______|
// | |
function compose( f, g) {
// compose(f, g) :: a -> c
// |
return function ( x) {
return f(g(x));
};
}
var isOdd = compose(unit, odd);
bind :: Monad m => m a -> (a -> m b) -> m b
unit :: Monad m => a -> m a
// Given:
// x :: a
// f :: Monad m => a -> m b
// h :: Monad m => m a
// g :: Monad m => b -> m c
// we have the following three laws:
// 1. Left identity
bind(unit(x), f) === f(x)
unit(x).then(f) === f(x)
// 2. Right identity
bind(h, unit) === h
h.then(unit) === h
// 3. Associativity
bind(bind(h, f), g) === bind(h, function (x) { return bind(f(x), g); })
h.then(f).then(g) === h.then(function (x) { return f(x).then(g); })
then
和
unit
函数,这些函数违反了这些法律。在那种情况下,
then
和
unit
的那些特定实现是不正确的。
unit
函数(数组的
bind
函数正确):
// unit :: a -> Array a
function unit(x) {
return [x, x];
}
// concat :: Array (Array a) -> Array a
function concat(h) {
return h.concat.apply([], h);
}
// bind :: Array a -> (a -> Array b) -> Array b
function bind(h, f) {
return concat(h.map(f));
}
unit
的此错误定义违反了第二定律(正确的标识):
// 2. Right identity
bind(h, unit) === h
// proof
var h = [1,2,3];
var lhs = bind(h, unit) = [1,1,2,2,3,3];
var rhs = h = [1,2,3];
lhs !== rhs;
unit
的正确定义是:
// unit :: a -> Array a
function unit(x) {
return [x];
}
bind
函数是根据
concat
和
map
实现的。但是,数组不是唯一拥有此属性的monad。每个monad
bind
函数都可以按照
concat
和
map
的广义monadic版本来实现:
concat :: Array (Array a) -> Array a
join :: Monad m => m (m a) -> m a
map :: (a -> b) -> Array a -> Array b
fmap :: Functor f => (a -> b) -> f a -> f b
fmap
函数的数据类型。根据定义,每个monad也是一个函子。
fmap
和
join
怎么等同于
bind
。您可以在
Wikipedia page上阅读有关它们的信息。
unit
函数称为
of
,而
bind
函数称为
chain
。这将允许您编写如下代码:
Identity.of(1).chain(isOdd);
Would there be any benefit to writing synchronous code using the syntax of promises?
Maybe
monad(用于可能失败的计算,类似于浮点数中的
NaN
)和
monadic parser combinators。
try {
foo();
bar(a, b);
bam();
} catch(e) {
handleError(e);
}...could be written something like (but using a synchronous version of
then
);foo()
.then(bar.bind(a, b))
.then(bam)
.fail(handleError)
fail
方法的任何内容。原因是您根本不需要特殊的
fail
方法。
function CanFail() {}
// Fail :: f -> CanFail f a
function Fail(error) {
this.error = error
}
Fail.prototype = new CanFail;
// Okay :: a -> CanFail f a
function Okay(value) {
this.value = value;
}
Okay.prototype = new CanFail;
// then :: CanFail f a -> (a -> CanFail f b) -> CanFail f b
CanFail.prototype.then = function (f) {
return this instanceof Okay ? f(this.value) : this;
};
foo
,
bar
,
bam
和
handleError
:
// foo :: Unit -> CanFail Number Boolean
function foo() {
if (someError) return new Fail(1);
else return new Okay(true);
}
// bar :: String -> String -> Boolean -> CanFail Number String
function bar(a, b) {
return function (c) {
if (typeof c !== "boolean") return new Fail(2);
else return new Okay(c ? a : b);
};
}
// bam :: String -> CanFail Number String
function bam(s) {
if (typeof s !== "string") return new Fail(3);
else return new Okay(s + "!");
}
// handleError :: Number -> Unit
function handleError(n) {
switch (n) {
case 1: alert("unknown error"); break;
case 2: alert("expected boolean"); break;
case 3: alert("expected string"); break;
}
}
// result :: CanFail Number String
var result = foo()
.then(bar("Hello", "World"))
.then(bam);
if (result instanceof Okay)
alert(result.value);
else handleError(result.error);
CanFail
monad实际上是功能编程语言中的
Either
monad。希望能有所帮助。
关于javascript - 使用promise的语法编写同步代码会不会有任何好处,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28937788/
如何从 promise 中退出 promise ? perl6 文档没有提供简单的方法。例如: my $x = start { loop { # loop forever until "qui
我的用户 Controller 中有一个索引操作,其中我试图连续做两件事,并且在它们都有机会完成之前不执行所需的 res.json() 方法。 我有一个加入用户的友谊加入模型。一列是 friender
请帮我解释一下为什么日志结果有两种不同: 方式 1:每 1 秒顺序记录一次 方式 2:1 秒后记录所有元素。 // Way 1 let sequence = Promise.resolve(); [1
我的问题很简单。 Promise.all() 方法可以返回 Promise 吗?让我解释一下: function simpleFunction() { let queue = [];
我正在使用 Promise 从存储中读取文件并转换为 base64 字符串。我有图像数组,使用 RNFS 读取图像 const promise_Images = _Images.map(async (
如果使用非空数组调用 Promise.all 或 Promise.race,它们将返回一个待处理的 Promise: console.log(Promise.all([1])); // prints
Promise.all 是否可以在没有包装 promise 的情况下返回链的最后一个值? 如果不使用 await,它在我的上下文中不起作用 没有包装的例子: function sum1(x){ r
我一直在玩 promise,通常能想出如何处理好它们,但在这种情况下,我不知道如何删除一个 promise-wrapping level。 代码如下: let promise2 = promise1.
考虑以下嵌套的Promises结构: const getData = async() => { const refs = [{ name: "John33", age: 3
我已经阅读了 Promise/A+ 规范,但据我了解,还有诸如 Promise/A 和 Promise 之类的东西。它们之间有什么区别? Promise 和 Promise/A 规范也是如此吗?如果是
当我运行以下代码时: my $timer = Promise.in(2); my $after = $timer.then({ say "2 seconds are over!"; 'result'
以下简单的 promise 是发誓的,我不允许打破它。 my $my_promise = start { loop {} # or sleep x; 'promise re
我正在尝试扩展Promise: class PersistedPromise extends Promise { } 然后在派生类上调用静态resolve以直接创建一个已解决的Promise: Per
我有两个返回 promise 的函数,我独立使用它们作为: getLocal().then(...) 和 getWeb().then(...) 但是现在我遇到了一个奇怪的问题: 1) 我需要第三个
我不知道 promise.all 解决方案中的 promise.all 是否是一个好的实践。我不确定。 我需要从一组用户获取信息,然后通过此信息响应,我需要发送消息通知。 let userList =
我一直在尝试使用 queueMicrotask() 函数,但我没有弄清楚当回调是微任务时回调的优先级如何。查看以下代码: function tasksAndMicroTasks() { const
我一直在尝试使用 queueMicrotask() 函数,但我没有弄清楚当回调是微任务时回调的优先级如何。查看以下代码: function tasksAndMicroTasks() { const
今年早些时候,我在 Pharo Smalltalk 参与了一个 promise 项目。这个想法是为了实现以下行为: ([ 30 seconds wait. 4 ]promiseValue )then:
大家好,提前感谢您的帮助。 下面是我正在尝试做的事情 function1(){ throw some error(); } function2() { // dosomething suc
我有以下未解析的代码。f2 解决了,所以我不会添加该代码,它是 f1 我有问题。 我调用函数,它到达最里面如果,它调用函数“find”,它执行函数 findId,完美返回 Id,然后执行 editId
我是一名优秀的程序员,十分优秀!