我正在尝试将Phoenix文档中 Phoenix.Channel.reply / 2 的示例扩展为异步回复Phoenix通道/套接字推送事件的完整工作示例:
取自https://hexdocs.pm/phoenix/Phoenix.Channel.html#reply/2:
def handle_in("work", payload, socket) do Worker.perform(payload, socket_ref(socket)) {:noreply, socket} end def handle_info({:work_complete, result, ref}, socket) do reply ref, {:ok, result} {:noreply, socket} end
我按如下方式重新编写了这个例子:
...
def handle_in("work", job, socket) do
send worker_pid, {self, job}
{:noreply, socket}
end
def handle_info({:work_complete, result}, socket) do
broadcast socket, "work_complete", %{result: result}
{:noreply, socket}
end
...
...
receive do
{pid, job} ->
result = perform(job) # stub
send pid, {:work_complete, result}
end
...
此解决方案有效,但它不依赖于生成并传递带有socket_ref(socket)
和 Phoenix.Channel.reply / 2 的socket_ref。相反,它依赖于 Phoenix.Channel.broadcast / 3 。
文档暗示 reply / 2 专门用于异步回复套接字推送事件的场景:
回复(arg1,arg2)
以套接字推送异步回复。
当你需要回复一个原本不可能的推送时很有用 使用{:reply,{status,payload},socket}从你的回复处理 handle_in回调。回复/ 3将在您需要的极少数情况下使用 在另一个过程中执行工作并在完成时回复 使用socket_ref / 1生成对push的引用。
当我生成并传递一个socket_ref,并依赖 Phoenix.Channel.reply / 2 来对套接字推送进行异步回复时,我根本不能让它工作:
...
def handle_in("work", job, socket) do
send worker_pid, {self, job, socket_ref(socket)}
{:noreply, socket}
end
def handle_info({:work_complete, result, ref}, socket) do
reply ref, {:ok, result}
{:noreply, socket}
end
...
...
receive do
{pid, job, ref} ->
result = perform(job) # stub
send pid, {:work_complete, result, ref}
end
...
我的room_channels.ex handle_info
函数被调用,但 reply / 2 似乎没有向套接字发送消息。我看到stderr上没有堆栈跟踪或stdout上的任何输出都没有指示错误。更重要的是,跟踪socket_ref似乎只会增加我的代码的开销。
使用广播/ 3 对我的解决方案使用socket_ref和回复/ 2 有什么好处?如何通过回复/ 2获得解决方案工作?
答案 0 :(得分:0)
我错了, Phoenix.Channel.reply / 2 的例子可行:
...
def handle_in("work", job, socket) do
send worker_pid, {self, job, socket_ref(socket)}
{:noreply, socket}
end
def handle_info({:work_complete, result, ref}, socket) do
reply ref, {:ok, result}
{:noreply, socket}
end
...
...
receive do
{pid, job, ref} ->
result = perform(job) # stub
send pid, {:work_complete, result, ref}
end
...
在我的实现中,我错误地将事件推送发送同步回复,返回值为{:reply, :ok, socket}
而不是{:noreply, socket}
。
仔细检查从服务器发送到客户端的websocket框架后,我发现浏览器确实从reply ref, {:ok, result}
收到了我的服务器回复,但是从未调用过关联的回调。
似乎Phoenix的Socket.js客户端库每次推送事件最多只能接受一次回复。
答案 1 :(得分:0)
希望我对这次谈话并不太晚。
我设法使用上面的代码并使回调在javascript中运行。
诀窍是听取phx_reply
事件。在priv/static/app.js
内,每个Channel
javascript对象都有CHANNEL_EVENTS
中预定义的列表(行并设置为在以下代码块中侦听它:
this.on(CHANNEL_EVENTS.reply, function (payload, ref) {
_this2.trigger(_this2.replyEventName(ref), payload);
});
我所做的是在频道on
回调中,我在听phx_reply
事件:
channel.on("phx_reply", (data) => {
console.log("DATA ", data);
// Process the data
}
这已经在Elixir 1.3和Phoenix 1.2上进行了测试
希望有所帮助!