Phoenix LiveView如何运作

2021-06-25 19:11:11

在上一课中,我们有一种LiveView的魔力!在本课程中,我们将看到LiveView如何真正有效,并且在用户连接时幕后会发生什么。

让我们从仪表板的简化版本开始,这是一个只渲染Coinbase BTC-USD交易的视图。

defmodule poeticoinsweb.cryptodashboard do使用poeticoinsweb,:live_view alias poeticoins.product def mount(_params,_session,socket)do io.inspect(self(),标签:" mount")产品= product.new(& #34;乐队"," btc-usd")trade = poeticoins.get_last_trade(产品)#if socket.connection? do#poeticoins.subscribe_to_trades(产品)#结束socket =分配(插座,:贸易,贸易){:确定,套接字}结束def渲染(分配)do io.inspect(self(),标签:" render" render" render" 34;)〜L""" < p>< b>产品< / b&gt ;:<%= @ trade.product.exchange_name%> - <%= @ trade.product.currency_pair%> < / p> < p>< b>在< / b&gt ;:<%= @ trade.traded_at%>< / p> < p>< b>价格< / b&gt ;:<%= @ trade.price%>< / p> < p>< b>体积< / b&gt ;:<%= @ trade.volume%>< / p> """ End Def Handle_Info({:new_trade,trade},插座)do socket =分配(插座,:贸易,贸易){:noreply,socket}结束

通过调用io.inspect(self(),标签:" ...")在inst / 3和render / 1中,我们看到何时调用这些回调以及进程PID是什么时候。

让我们还暂时评论诗歌/ 3中的诗歌ins.subscribe_to_trades(产品)行,以这种方式我们不会得到任何新的贸易信息,因此我们可以更好地关注生命周期的第一部分。

让我们首先对Live&#34做一个简单的HTTP GET请求; /"路线,使用卷曲等工具

$ curl -v" http:// localhost:4000"<!doctype html>< html lang =" en">>> < meta charset =" UTF-8"内容=" dccycuw3ozesc2isvakutdkghydfakzrakic6mpgvj7yyfxaqutbis48" csrf-param =" _csrf_token"方法 - param =" _method"名称=" CSRF-token"> < script defer phx-track-static类型=" text / javascript" src =" /js/app.js& n34;>< / script>< / head><主体> < div data-phx-main ="真" data-phx-session =" sfmynty ..." data-phx-static =" sfmynty ..." data-phx-view =" CryptodashboardLive" id =" phx-flyt1v20d4jijqbg"> <主要角色="主要" Class ="容器"> < p class ="警报提醒信息"角色="警报" PHX点击=" LV:清除闪存" phx-value-key ="信息">< / p> < p class ="警报警报 - 危险"角色="警报" PHX点击=" LV:清除闪存" phx-value-key ="错误">< / p> < p>< b>产品< / b> coinbase - btc-usd< / p> < p>< b>在< / b> 18:05:18.124448z< / b> < p>< b>价格< / b&gt ;:29315.3< / p> < p>< b>体积< / b> 0.00673002< / p> < / main> < / div>< / body>< / html>

我们立即注意到应用程序答案我们的HTTP获取请求与完全呈现的页面!这意味着我们可以支持不一定运行JavaScript的客户端,这使LiveView也非常适合SEO。

我们进行了一个正常的HTTP GET请求,调用挂载/ 3初始化要呈现的数据,然后呈现/ 1返回呈现的内容。

[info] get / [debug]使用phoenix.liveview.plug.elixir.poeticoinsweb.cryptodashlower / 2参数:%{}管道:[:浏览器]挂载:#pID< 0.462.0>渲染:#pID< 0.462。 0> [info]在40ms中发送200

通过打开http:// localhost:4000页使用浏览器,我们看到inst / 3和render / 1称为两次。

挂载:#pID< 0.599.0>渲染:#pID< 0.599.0> [info]在2ms [info]中发送了200个连接到Phoenix.liveview.socket在73μs传输:websocket serializer:phoenix.socket.v2.jsonserializer参数:%{" _csrf_token" => " gqclprujpykadko2agcbkdmpssrun2ysubsgs1lb-gzixvqfulyv5npw&#34 ;," _mounts" => " 0"" _track_static" => %{" 0" => " http:// localhost:4000 / css / app.css&#34 ;," 1" => " http:// localhost:4000 / js / app.js"}," vsn" => " 2.0.0"}安装:#pID< 0.612.0>渲染:#pid< 0.612.0>

第一次是回答HTTP GET请求,使用我们在上一个示例中看到的完全呈现的HTML页面。当浏览器接收到HTML内容时,它会加载App.js应用程序的JS。

//app.jsimport {socket} from"凤凰"从&#34导入{livesoction} from" phoenix_live_view" let csrftoken = document.querySelector(" meta [name =' csrf -Token']")。getAttribute("内容")让livesocket =新的livesocket(" / live" ocket,{params:{_csrf_token:csrftoken}} )// connect如果pagelivesocket.connect()上有任何LiveViews()

运行此脚本,浏览器再次连接到服务器,此时打开WebSocket连接,传递CSRF-令牌,在< meta&gt中呈现。标记在标题中。连接后,服务器启动状态LiveView进程并呼叫第二次时间挂载/ 3并渲染/ 1,通过WebSocket连接按下新呈现页面。

这一新的有状态LiveView流程只要用户保持连接,将状态保持在内存中,从浏览器中侦听事件并向浏览器发送渲染更改,每次更新套接字时都会。

为了更好地了解通过WebSocket连接发生的事情,我们可以使用浏览器检查器来查看交换消息。

在“检查员”中,在“网络”选项卡下,刷新页面,我们会看到一个请求列表

首先,我们将Get请求与服务器响应中的LocalHost和完整的HTML看。

然后,浏览器加载App.js JavaScript并通过WebSocket连接到LiveView。建立WebSocket连接后,浏览器立即发送PHX_JOIN消息。

LiveView使用包含呈现视图的PHX_REPLY消息回复。在此消息中,我们找不到简单的视图的HTML,而是我们找到了动态值和模板的静态部分。静态部件保持在浏览器的内存中,并且只将动态更改从LiveView发送到浏览器。

[..." phx_reply",{"响应&#34 ;: ... {" 0&#34 ;:"冰纳和#34 ;," 1& #34 ;:" BTC-USD&#34 ;," 2&#34 ;:" 2021-01-01 21:48:39.473797z&#34 ;," 3&#34 ;:" 29265.33&#34 ;,#34; 4&#34 ;:" 0.35729453&#34 ;," s&#34 ;: [34;< p< p< ; B>产品< / b>:\ n&#34 ;," - \ n"" \ n<< p>< b>< / b&gt ;:","< / p"""< / p"< / p" ; p>< b>价格< / b&gt ;:""< / p>< b>体积< / b&gt ;:&#34 ;,&#34 ;< / p> \ n" ]}}]

要正确呈现此视图,请在浏览器上运行的LiveView JS代码只需用静态部分内插动态值:

"< p>< b>产品< / b>:\ n" +"斗鸡队和#34; +" - \ n" +" BTC-USD" +" \ n< / p>< p>< b>< / b&gt ;:" +" 2021-01-01 21:48:39.473797Z" + ......

让我们删除Mount / 3中的注释,以便LiveView Process订阅获取新交易,我们可以看到套接字时会发生什么。更新了。

def mount(_params,_session,socket)do io.inspect(self(),标签:" mount" support")产品= product.new(" coinbase"和#34; btc- USD")Trade = poeticoins.get_last_trade(产品)如果socket.connected? do poeticoins.subscribe_to_trades(产品)结束socket =分配(插座,:贸易,贸易){:确定,套接字}结束

我们现在拥有所有元素来理解为什么我们使用if socket.Connection?状况。 socket.Connected?在初始HTTP GET请求期间是假的,在这种情况下,我们不想订阅获取新交易,因为该过程并不意味着在响应之后生活;我们只想用最近的交易渲染视图并关闭连接。

当浏览器通过WebSocket连接到有状态LiveView,Socket.Connected?是真的,现在是时候为Pubsub主题订阅LiveView进程。

def handle_info({:new_trade,trade},socket)do io.inspect(self(),标签:"新贸易")socket =分配(插座,:贸易,贸易){:noreply,socket}结尾

每次进程接收到{:new_trade,trade}消息时调用handle_info / 2。我们在套接字中打印PID并分配/ 3:交易。该视图重新呈现,调用Render / 1,并将更改推送到浏览器。

通过刷新浏览器上的页面,我们看到,正如所预期的那样,每次都有新贸易时,视图现在就正确更新。使用浏览器检查器,我们可以看到在服务器上运行的LiveView进程发送的消息。

在初始PHX_JOIN和PHX_REPLY之后,我们发现DIFF消息,每次收到新交易时从服务器发送的更改。

LiveView能够跟踪更改,并仅将更改的值发送到浏览器。

调查其中一个差异消息,我们没有看到任何静态部分,只有套接字中更改的动态值。通过这种方式,有效载荷是超级紧凑的:我们只需具有Trade.TraD_AT(Diff消息中的位置2),Trade.price(位置3)和交易.Volume(位置编号4)。

每个动态部分都有自己的位置编号,LiveView使用此职位了解DOM中需要更新哪个元素。在浏览器上运行的js代码使用名为mphor的库应用这些更改。

在终端中,我们看到每个新的交易由Supper_Info / 2处理,该套接字更新套接字,然后调用Retains / 1以重新渲染视图并将更改发送到浏览器。

我们还看到,服务我们浏览器的LiveView进程始终相同(每个连接用户的一个过程)。这是一个单一的LiveView进程,它在内存中保持状态并跟踪更改,只要我们保持连接。

我们的浏览器最初连接到服务器,使一个简单的HTTP获取到Live Route。服务器调用inst / 3并渲染/ 1回调,以初始化数据并使用完全呈现的HTML页面答案。浏览器在App.js中加载HTML和应用程序JavaScript,它通过WebSocket连接到服务器。一旦连接,服务器就会产生一个状态的LiveView进程,只要我们连接就会保持活力。在Mount / 3中LiveView流程订阅以获取交易消息。

浏览器使用PHX_REPLY消息发送PHX_JOIN消息和LIVEVIEW答案,其中有呈现视图,具有动态和静态部分。每个动态部分都有一个位置。

每次LiveView进程从Pubsub接收新的交易时,它将它分配/ 3套接字和LiveView的新交易重新渲染呼叫渲染/ 1。只有随着Diff消息发送到浏览器的动态值,以这种方式,有效载荷保持超级紧凑。在浏览器中运行的LiveView JS代码将采用这些新值并使用形体库修补DOM。

此视图是被动的,它只接收来自服务器的新值,而无需任何用户交互。在即将到来的课程中,我们将看到如何使用按钮,绑定和表单将事件从浏览器发送到服务器。

包装有小时的深入教程,提示和应用程序开发。了解如何构建真正的实时应用程序,从Elixir和Phoenix LiveView中获得最大的实时应用程序!