将 Http 请求与其余更新集成
Integrate Http requests with the rest of the updates
我正在使用以下模型制作一个简单的 Elm 应用程序:
type alias Model =
{ num : Float
, str : String
, list : List Float
, serverResponse : String
}
我正在关注 Todo-MVC 示例并且我有一个类似的架构:
type Action
= NoOp
| ChangeNum String
| ChangeStr String
...
view : Model -> Html
view model =
...
update : Action -> Model -> Model
update action model =
case action of
...
main : Signal Html
main = Signal.map view model
model : Signal Model
model = Signal.foldp update initialModel (Signal.subscribe updates)
initialModel : Model
initialModel =
...
updates : Signal.Channel Action
updates = Signal.channel NoOp
我正在尝试添加一个按钮,该按钮将 POST 模型添加到某个页面,并在 return 中使用服务器的响应更新 model.serverResponse。但是我完全难住了。
谁能帮我填补这段代码中的空白:http://pastebin.com/1irNqh3S
简介
目前这比应该做的要难一些。下一个 Elm 版本 (0.15) 应该通过新的语言特性和对 Http
和 Websocket
库的改造来解决这些尴尬问题。
基本问题是信号中的循环依赖性。您希望根据您的程序状态 ("the current model") 创建 HTTP 请求并根据 HTTP 响应更新程序状态。这应该是完全可能的,因为在两者之间有这种异步 HTTP 处理,而不是一些不可能的无意义的递归定义。
解决方法(破解):JavaScript 回显服务
但由于我们仍处于 Elm 0.14,我将向您展示一个解决方法。 请注意,这是一个危险的 hack!我将根据您提供的定义编写此代码,并且只在我重新定义的地方重复名称。评论解释了正在发生的事情。
榆树代码
-- These are the Http response strings, but coming from JavaScript through a port
port asyncResponses : Signal String
responseActions : Signal Action
responseActions = responseToAction <~ asyncResponses
-- The order of these two parameters of merge may matter. Check which should take precedence.
input : Signal Action
input = Signal.merge responseActions (Signal.subscribe updates)
-- note the redefinition:
main : Signal Html
main = Signal.foldp update initialModel input
-- These are the same Http response strings, but we're sending them out so JavaScript can listen to them.
port responses : Signal String
port responses = Http.send requests |> Signal.keepIf isSuccess (Success "") |> Signal.map (\Success s -> s)
isSuccess response = case response of
Success _ -> True
_ -> False
JS代码
您应该有一个 HTML 文件,您可以在其中使用 Elm.fullscreen
或 Elm.embed
启动 Elm 程序。我假设您使用的是全屏版本:
// Catching the returned object from Elm.fullscreen:
var program = Elm.fullscreen(Elm.Main, {asyncResponses : ""})
// JS Echo Service:
program.ports.responses.subscribe(function(s) {
program.ports.asyncResponses.send(s);
})
危险
我希望很明显,跳过这些圈圈是烦人和混乱的,而不是正常的 Elm 代码风格。我希望这足以阻止人们滥用它。我再说一遍,这将在即将推出的 Elm 0.15 中以更好的方式得到修复。
此方法的危险在于,您向 Elm 程序发送的事件多于您在 JavaScript 中获得的事件。这可能并不明显,这可能发生在这样一个简单的 JS 片段上,它会回应它得到的东西。但问题可能来自您的 Elm 程序。如果您的 Elm 程序针对它通过另一个端口获得的每个字符串从该端口发送一个 Http 响应字符串,并且(例如)在其他输入更改您的模型时重复该响应,那么您将开始累积得到回显的事件。通常 Elm 在事件同步方面可以很聪明,但是对于端口,所有的赌注都没有了,您可以通过累积事件使系统负担过重,从而使程序延迟和浏览器占用内存。所以请小心,不要将此技巧宣传为好东西。这只是权宜之计。
资源
- Ports
的文档
- Example project 用于使用端口
- 关于相同问题和解决方案的简短 mailing list discussion。
- 一个example Elm game from the ludum dare mini, which uses the same technique for playing and stopping audio. I explained this solution to one of the creators on the #elm IRC channel。请注意,他们必须在传出端口上使用
dropRepeats
以防止来自 JavaScript 的回显事件堆积。
- Tentative new APIs 对于 Elm 0.15 中的这些东西。
我正在使用以下模型制作一个简单的 Elm 应用程序:
type alias Model =
{ num : Float
, str : String
, list : List Float
, serverResponse : String
}
我正在关注 Todo-MVC 示例并且我有一个类似的架构:
type Action
= NoOp
| ChangeNum String
| ChangeStr String
...
view : Model -> Html
view model =
...
update : Action -> Model -> Model
update action model =
case action of
...
main : Signal Html
main = Signal.map view model
model : Signal Model
model = Signal.foldp update initialModel (Signal.subscribe updates)
initialModel : Model
initialModel =
...
updates : Signal.Channel Action
updates = Signal.channel NoOp
我正在尝试添加一个按钮,该按钮将 POST 模型添加到某个页面,并在 return 中使用服务器的响应更新 model.serverResponse。但是我完全难住了。
谁能帮我填补这段代码中的空白:http://pastebin.com/1irNqh3S
简介
目前这比应该做的要难一些。下一个 Elm 版本 (0.15) 应该通过新的语言特性和对 Http
和 Websocket
库的改造来解决这些尴尬问题。
基本问题是信号中的循环依赖性。您希望根据您的程序状态 ("the current model") 创建 HTTP 请求并根据 HTTP 响应更新程序状态。这应该是完全可能的,因为在两者之间有这种异步 HTTP 处理,而不是一些不可能的无意义的递归定义。
解决方法(破解):JavaScript 回显服务
但由于我们仍处于 Elm 0.14,我将向您展示一个解决方法。 请注意,这是一个危险的 hack!我将根据您提供的定义编写此代码,并且只在我重新定义的地方重复名称。评论解释了正在发生的事情。
榆树代码
-- These are the Http response strings, but coming from JavaScript through a port
port asyncResponses : Signal String
responseActions : Signal Action
responseActions = responseToAction <~ asyncResponses
-- The order of these two parameters of merge may matter. Check which should take precedence.
input : Signal Action
input = Signal.merge responseActions (Signal.subscribe updates)
-- note the redefinition:
main : Signal Html
main = Signal.foldp update initialModel input
-- These are the same Http response strings, but we're sending them out so JavaScript can listen to them.
port responses : Signal String
port responses = Http.send requests |> Signal.keepIf isSuccess (Success "") |> Signal.map (\Success s -> s)
isSuccess response = case response of
Success _ -> True
_ -> False
JS代码
您应该有一个 HTML 文件,您可以在其中使用 Elm.fullscreen
或 Elm.embed
启动 Elm 程序。我假设您使用的是全屏版本:
// Catching the returned object from Elm.fullscreen:
var program = Elm.fullscreen(Elm.Main, {asyncResponses : ""})
// JS Echo Service:
program.ports.responses.subscribe(function(s) {
program.ports.asyncResponses.send(s);
})
危险
我希望很明显,跳过这些圈圈是烦人和混乱的,而不是正常的 Elm 代码风格。我希望这足以阻止人们滥用它。我再说一遍,这将在即将推出的 Elm 0.15 中以更好的方式得到修复。
此方法的危险在于,您向 Elm 程序发送的事件多于您在 JavaScript 中获得的事件。这可能并不明显,这可能发生在这样一个简单的 JS 片段上,它会回应它得到的东西。但问题可能来自您的 Elm 程序。如果您的 Elm 程序针对它通过另一个端口获得的每个字符串从该端口发送一个 Http 响应字符串,并且(例如)在其他输入更改您的模型时重复该响应,那么您将开始累积得到回显的事件。通常 Elm 在事件同步方面可以很聪明,但是对于端口,所有的赌注都没有了,您可以通过累积事件使系统负担过重,从而使程序延迟和浏览器占用内存。所以请小心,不要将此技巧宣传为好东西。这只是权宜之计。
资源
- Ports 的文档
- Example project 用于使用端口
- 关于相同问题和解决方案的简短 mailing list discussion。
- 一个example Elm game from the ludum dare mini, which uses the same technique for playing and stopping audio. I explained this solution to one of the creators on the #elm IRC channel。请注意,他们必须在传出端口上使用
dropRepeats
以防止来自 JavaScript 的回显事件堆积。 - Tentative new APIs 对于 Elm 0.15 中的这些东西。