Elm ile Web Ön Uçunuzu Güvenilir Hale Getirin

Yayınlanan: 2022-03-11

Web ön uçunuzda kaç kez hata ayıklamaya çalıştınız ve kendinizi karmaşık olay zincirleriyle uğraşan kodlara karışmış buldunuz?

Hiç jQuery, Backbone.js veya diğer popüler JavaScript çerçeveleriyle oluşturulmuş birçok bileşenle ilgilenen bir kullanıcı arayüzü için kodu yeniden düzenlemeyi denediniz mi?

Bu senaryolarla ilgili en acı verici şeylerden biri, birden çok belirsiz olay dizisini takip etmeye çalışmak ve tüm bu davranışları öngörmek ve düzeltmektir. Sadece bir kabus!

Her zaman web ön uç geliştirmenin bu cehennemi yönünden kaçmanın yollarını aradım. Backbone.js, web ön uçlarına uzun zamandır özledikleri yapıyı vererek bu konuda benim için iyi çalıştı. Ancak en önemsiz şeylerden bazılarını yapmak için gereken ayrıntı düşünüldüğünde, çok daha iyi olmadığı ortaya çıktı.

Elm ile Web Ön Uçunuzu Güvenilir Hale Getirin

Sonra Elm ile tanıştım.

Elm, Haskell programlama diline dayalı, ancak daha basit bir spesifikasyona sahip, statik olarak yazılmış bir işlevsel dildir. Derleyici (ayrıca Haskell kullanılarak oluşturulmuştur) Elm kodunu ayrıştırır ve JavaScript'te derler.

Elm başlangıçta ön uç geliştirme için tasarlandı, ancak yazılım mühendisleri onu sunucu tarafı programlama için de kullanmanın yollarını buldular.

Bu makale, Elm'in web ön uç geliştirme hakkındaki düşüncelerimizi nasıl değiştirebileceğine dair bir genel bakış ve bu işlevsel programlama dilinin temellerine bir giriş sağlar. Bu eğitimde, Elm kullanarak basit bir alışveriş sepeti benzeri uygulama geliştireceğiz.

Neden Karaağaç?

Elm, çoğu temiz bir web ön uç mimarisi elde etmede son derece yararlı olan birçok avantaj vaat ediyor. Elm, diğer popüler çerçevelere (hatta React.js) göre daha iyi HTML oluşturma performansı avantajları sunar. Ayrıca Elm, geliştiricilerin, JavaScript gibi dinamik olarak yazılan dilleri rahatsız eden çoğu çalışma zamanı istisnası üretmeyen kod yazmasına izin verir.

Derleyici, türleri otomatik olarak çıkarır ve kolay hatalar yayarak geliştiricinin çalışma zamanından önce olası herhangi bir sorundan haberdar olmasını sağlar.

NoRedInk'in 36.000 Elm hattı vardır ve üretimde bir yıldan fazla olmasına rağmen hala tek bir çalışma zamanı istisnası üretmemiştir. [Kaynak]

Elm'i deneyebilmeniz için mevcut JavaScript uygulamanızın tamamını dönüştürmeniz gerekmez. JavaScript ile mükemmel birlikte çalışabilirliği sayesinde, mevcut uygulamanızın sadece küçük bir bölümünü bile alabilir ve Elm'de yeniden yazabilirsiniz.

Elm ayrıca, size sunduğu şeylerin tam bir tanımını vermekle kalmayıp, aynı zamanda Elm Mimarisini izleyerek web ön uç oluşturmak için uygun bir kılavuz sağlayan mükemmel belgelere sahiptir - modülerlik, kodun yeniden kullanımı ve test için harika bir şey .

Basit Bir Sepet Yapalım

Elm kodunun çok kısa bir parçasıyla başlayalım:

 import List exposing (..) cart = [] item product quantity = { product = product, qty = quantity } product name price = { name = name, price = price } add cart product = if isEmpty (filter (\item -> item.product == product) cart) then append cart [item product 1] else cart subtotal cart = -- we want to calculate cart subtotal sum (map (\item -> item.product.price * toFloat item.qty) cart)

Başında -- olan herhangi bir metin Elm'deki bir yorumdur.

Burada, her öğenin iki değere (karşılık gelen ürün ve miktar) sahip bir kayıt olduğu bir ürün listesi olarak bir sepeti tanımlıyoruz. Her ürün, adı ve fiyatı olan bir rekordur.

Sepete bir ürün eklemek, ürünün sepette zaten var olup olmadığını kontrol etmeyi içerir.

Olursa, hiçbir şey yapmayız; aksi takdirde ürünü sepete yeni bir ürün olarak ekliyoruz. Listeyi filtreleyerek, her bir öğeyi ürünle eşleştirerek ve sonuçta ortaya çıkan filtrelenmiş listenin boş olup olmadığını kontrol ederek ürünün sepette olup olmadığını kontrol ediyoruz.

Ara toplamı hesaplamak için, sepetteki ürünler üzerinde yinelenir, karşılık gelen ürün miktarını ve fiyatını bulur ve hepsini toplarız.

Bu, bir araba ve ilgili işlevlerin alabileceği kadar minimalisttir. Bu kodla başlayacağız ve onu eksiksiz bir web bileşeni veya Elm'in terimleriyle bir program haline getirerek adım adım geliştireceğiz.

Programımızdaki çeşitli tanımlayıcılara türler ekleyerek başlayalım. Elm, kendi başına türler çıkarma yeteneğine sahiptir, ancak Elm ve derleyicisinden en iyi şekilde yararlanmak için, türlerin açıkça belirtilmesi önerilir.

 module Cart1 exposing ( Cart, Item, Product , add, subtotal , itemSubtotal ) -- This is module and its API definition {-| We build an easy shopping cart. @docs Cart, Item, Product, add, subtotal, itemSubtotal -} import List exposing (..) -- we need list manipulation functions {-| Cart is a list of items. -} type alias Cart = List Item {-| Item is a record of product and quantity. -} type alias Item = { product : Product, qty : Int } {-| Product is a record with name and price -} type alias Product = { name : String, price : Float } {-| We want to add stuff to a cart. This is a function definition, it takes a cart, a product to add and returns new cart -} add : Cart -> Product -> Cart {-| This is an implementation of the 'add' function. Just append product item to the cart if there is no such product in the cart listed. Do nothing if the product exists. -} add cart product = if isEmpty (filter (\item -> item.product == product) cart) then append cart [Item product 1] else cart {-| I need to calculate cart subtotal. The function takes a cart and returns float. -} subtotal : Cart -> Float {-| It's easy -- just sum subtotal of all items. -} subtotal cart = sum (map itemSubtotal cart) {-| Item subtotal takes item and return the subtotal float. -} itemSubtotal : Item -> Float {-| Subtotal is based on product's price and quantity. -} itemSubtotal item = item.product.price * toFloat item.qty

Tür ek açıklamalarıyla, derleyici, aksi takdirde çalışma zamanı istisnalarına neden olabilecek sorunları artık yakalayabilir.

Ancak, Elm burada bitmiyor. Elm Mimarisi, geliştiricilere web ön uçlarını yapılandırmak için basit bir model aracılığıyla rehberlik eder ve bunu çoğu geliştiricinin zaten aşina olduğu kavramlar aracılığıyla yapar:

  • Model: Modeller programın durumunu tutar.
  • Görünüm: Görünüm, durumun görsel bir temsilidir.
  • Güncelleme: Güncelleme, durumu değiştirmenin bir yoludur.

Kodunuzun güncellemelerle ilgili kısmını denetleyici olarak düşünüyorsanız, eski Model-View-Controller (MVC) paradigmasına çok benzer bir şeye sahipsiniz.

Elm tamamen işlevsel bir programlama dili olduğundan, tüm veriler değişmezdir, bu da modelin değiştirilemeyeceği anlamına gelir. Bunun yerine, güncelleme işlevleri aracılığıyla yaptığımız bir önceki modele dayalı yeni bir model oluşturabiliriz.

Bu neden bu kadar harika?

Değişmez verilerle, işlevlerin artık yan etkileri olamaz. Bu, Elm'in birazdan tartışacağımız zamanda yolculuk hata ayıklayıcısı da dahil olmak üzere bir olasılıklar dünyasının kapılarını açar.

Görünümler, modeldeki her değişiklik görünümde bir değişiklik gerektirdiğinde oluşturulur ve modeldeki aynı veriler için her zaman aynı sonucu alırız - tıpkı bir salt fonksiyonun her zaman aynı sonucu döndürmesi gibi. aynı girdi argümanları.

Ana İşlevle Başlayın

Devam edelim ve sepet uygulamamız için HTML görünümünü uygulayalım.

React'e aşina iseniz, bu takdir edeceğiniz bir şey: Elm'in sadece HTML öğelerini tanımlamak için bir paketi var. Bu, harici şablonlama dillerine güvenmek zorunda kalmadan görüşünüzü Elm kullanarak uygulamanıza olanak tanır.

HTML öğeleri için sarmalayıcılar, Html paketinin altında bulunur:

 import Html exposing (Html, button, table, caption, thead, tbody, tfoot, tr, td, th, text, section, p, h1)

Tüm Elm programları ana işlevi yürüterek başlar:

 type alias Stock = List Product type alias Model = { cart : Cart, stock : Stock } main = Html.beginnerProgram { model = Model [] [ Product "Bicycle" 100.50 , Product "Rocket" 15.36 , Product "Biscuit" 21.15 ] , view = view , update = update }

Burada ana işlev, bazı modellerle, bir görünümle ve bir güncelleme işleviyle bir Elm programını başlatır. Birkaç çeşit ürün ve fiyatlarını tanımladık. Basitlik için, sınırsız sayıda ürünümüz olduğunu varsayıyoruz.

Basit Bir Güncelleme İşlevi

Güncelleme işlevi, uygulamamızın hayat bulduğu yerdir.

Bir mesaj alır ve mesajın içeriğine göre durumu günceller. Bunu iki parametre (bir mesaj ve mevcut model) alan ve yeni bir model döndüren bir fonksiyon olarak tanımlıyoruz:

 type Msg = Add Product update : Msg -> Model -> Model update msg model = case msg of Add product -> { model | cart = add model.cart product }

Şimdilik, mesajın product birlikte cart add yöntemini çağırdığımız Add product olduğunda tek bir vakayı ele alıyoruz.

Elm programının karmaşıklığı arttıkça güncelleme işlevi de büyüyecektir.

Görünüm İşlevini Uygulama

Ardından, sepetimiz için görünümü tanımlarız.

Görünüm, modeli HTML temsiline çeviren bir işlevdir. Ancak, yalnızca statik HTML değildir. HTML oluşturucu, çeşitli kullanıcı etkileşimlerine ve olaylara dayalı olarak uygulamaya mesaj gönderme yeteneğine sahiptir.

 view : Model -> Html Msg view model = section [style [("margin", "10px")]] [ stockView model.stock , cartView model.cart ] stockView : Stock -> Html Msg stockView stock = table [] [ caption [] [ h1 [] [ text "Stock" ] ] , thead [] [ tr [] [ th [align "left", width 100] [ text "Name" ] , th [align "right", width 100] [ text "Price" ] , th [width 100] [] ] ] , tbody [] (map stockProductView stock) ] stockProductView : Product -> Html Msg stockProductView product = tr [] [ td [] [ text product.name ] , td [align "right"] [ text ("\t$" ++ toString product.price) ] , td [] [ button [ onClick (Add product) ] [ text "Add to Cart" ] ] ]

Html paketi, bilinen adlara sahip işlevler olarak yaygın olarak kullanılan tüm öğeler için sarmalayıcılar sağlar (örneğin, işlev section bir <section> öğesi oluşturur).

Html.Attributes paketinin bir parçası olan style işlevi, elde edilen öğede stil özniteliğini ayarlamak için section işlevine iletilebilen bir nesne oluşturur.

Daha iyi yeniden kullanılabilirlik için görünümü ayrı işlevlere bölmek daha iyidir.

İşleri basit tutmak için, CSS ve bazı düzen niteliklerini doğrudan görünüm kodumuza yerleştirdik. Ancak, HTML öğelerinizi Elm kodundan şekillendirme sürecini kolaylaştıran kitaplıklar mevcuttur.

Snippet'in sonuna yakın olan button ve düğmenin click olayına Add product mesajını nasıl ilişkilendirdiğimize dikkat edin.

Elm, bir geri arama işlevini gerçek olayla bağlamak için gerekli tüm kodu üretme ve ilgili parametrelerle güncelleme işlevini oluşturma ve çağırma ile ilgilenir.

Son olarak, görüşümüzün son parçasını uygulamamız gerekiyor:

 cartView : Cart -> Html Msg cartView cart = if isEmpty cart then p [] [ text "Cart is empty" ] else table [] [ caption [] [ h1 [] [ text "Cart" ]] , thead [] [ tr [] [ th [ align "left", width 100 ] [ text "Name" ] , th [ align "right", width 100 ] [ text "Price" ] , th [ align "center", width 50 ] [ text "Qty" ] , th [ align "right", width 100 ] [ text "Subtotal" ] ] ] , tbody [] (map cartProductView cart) , tfoot [] [ tr [style [("font-weight", "bold")]] [ td [ align "right", colspan 4 ] [ text ("$" ++ toString (subtotal cart)) ] ] ] ] cartProductView : Item -> Html Msg cartProductView item = tr [] [ td [] [ text item.product.name ] , td [ align "right" ] [ text ("$" ++ toString item.product.price) ] , td [ align "center" ] [ text (toString item.qty) ] , td [ align "right" ] [ text ("$" ++ toString (itemSubtotal item)) ] ]

Burada, sepetimizin içeriğini oluşturduğumuz görüşümüzün diğer bölümünü tanımladık. Görünüm işlevi herhangi bir mesaj göndermese de, görünüm olarak nitelendirilmesi için yine de Html Msg dönüş tipine sahip olması gerekir.

Görünüm yalnızca alışveriş sepetinin içeriğini listelemekle kalmaz, aynı zamanda alt toplamı alışveriş sepetinin içeriğine göre hesaplar ve işler.

Bu Elm programının tam kodunu burada bulabilirsiniz.

Elm programını şimdi çalıştıracak olsaydınız, şöyle bir şey görürdünüz:

Hepsi nasıl çalışıyor?

Programımız, main işlevden oldukça boş bir durumla başlar - birkaç sabit kodlanmış ürün içeren boş bir sepet.

"Sepete Ekle" butonuna her tıklandığında, güncelleme fonksiyonuna bir mesaj gönderilir, bu mesaj daha sonra sepeti uygun şekilde günceller ve yeni bir model oluşturur. Model her güncellendiğinde, HTML ağacını yeniden oluşturmak için görünüm işlevleri Elm tarafından çağrılır.

Elm, React'e benzer bir Sanal DOM yaklaşımı kullandığından, kullanıcı arayüzündeki değişiklikler yalnızca gerektiğinde gerçekleştirilir ve hızlı performans sağlanır.

Sadece Tip Denetleyicisi Değil

Karaağaç statik olarak yazılmıştır, ancak derleyici türlerden çok daha fazlasını kontrol edebilir.

Msg bir değişiklik yapalım ve derleyicinin buna nasıl tepki verdiğini görelim:

 type Msg = Add Product | ChangeQty Product String

Başka bir mesaj türü tanımladık - sepetteki bir ürünün miktarını değiştirecek bir şey. Ancak, güncelleme işlevinde bu mesajı işlemeden programı yeniden çalıştırmaya çalışmak aşağıdaki hatayı verecektir:

Daha İşlevsel Bir Arabaya Doğru

Önceki bölümde, nicelik değeri için tür olarak bir dize kullandığımızı unutmayın. Bunun nedeni, değerin dize türünde olacak bir <input> öğesinden gelmesidir.

Cart modülüne yeni bir fonksiyon changeQty . Modül API'sini değiştirmeden gerekirse daha sonra değiştirebilmek için uygulamayı modülün içinde tutmak her zaman daha iyidir.

 {-| Change quantity of the product in the cart. Look at the result of the function. It uses Result type. The Result type has two parameters: for bad and for good result. So the result will be Error "msg" or a Cart with updated product quantity. -} changeQty : Cart -> Product -> Int -> Result String Cart {-| If the quantity parameter is zero the product will be removed completely from the cart. If the quantity parameter is greater then zero the quantity of the product will be updated. Otherwise (qty < 0) the error will be returned. -} changeQty cart product qty = if qty == 0 then Ok (filter (\item -> item.product /= product) cart) else if qty > 0 then Result.Ok (map (\item -> if item.product == product then { item | qty = qty } else item) cart) else Result.Err ("Wrong negative quantity used: " ++ (toString qty))

Fonksiyonun nasıl kullanılacağı hakkında herhangi bir varsayımda bulunmamalıyız. qty parametresinin bir Int içereceğinden emin olabiliriz ancak değer herhangi bir şey olabilir. Bu nedenle değeri kontrol eder ve geçersiz olduğunda bir hata bildiririz.

update işlevimizi de buna göre güncelliyoruz:

 update msg model = case msg of Add product -> { model | cart = add model.cart product } ChangeQty product str -> case toInt str of Ok qty -> case changeQty model.cart product qty of Ok cart -> { model | cart = cart } Err msg -> model -- do nothing, the wrong input Err msg -> model -- do nothing, the wrong quantity

Kullanmadan önce mesajdaki string quantity parametresini bir sayıya dönüştürüyoruz. Dize geçersiz bir sayı içeriyorsa, bunu bir hata olarak bildiririz.

Burada, bir hata oluştuğunda modeli değiştirmeden tutuyoruz. Alternatif olarak, modeli, hatayı kullanıcının görmesi için görünümde bir mesaj olarak bildirecek şekilde güncelleyebiliriz:

 type alias Model = { cart : Cart, stock : Stock, error : Maybe String } main = Html.beginnerProgram { model = Model [] -- empty cart [ Product "Bicycle" 100.50 -- stock , Product "Rocket" 15.36 , Product "Bisquit" 21.15 ] Nothing -- error (no error at beginning) , view = view , update = update } update msg model = case msg of Add product -> { model | cart = add model.cart product } ChangeQty product str -> case toInt str of Ok qty -> case changeQty model.cart product qty of Ok cart -> { model | cart = cart, error = Nothing } Err msg -> { model | error = Just msg } Err msg -> { model | error = Just msg }

Modelimizdeki error özniteliği için Maybe String tipini kullanıyoruz. Belki, Nothing veya belirli bir türün değerini tutabilen başka bir türdür.

Görünüm işlevini aşağıdaki gibi güncelledikten sonra:

 view model = section [style [("margin", "10px")]] [ stockView model.stock , cartView model.cart , errorView model.error ] errorView : Maybe String -> Html Msg errorView error = case error of Just msg -> p [style [("color", "red")]] [ text msg ] Nothing -> p [] []

Bunu görmelisiniz:

Sayısal olmayan bir değer (örneğin “1a”) girmeye çalışmak, yukarıdaki ekran görüntüsünde gösterildiği gibi bir hata mesajıyla sonuçlanacaktır.

Paketler Dünyası

Elm'in kendi açık kaynak paketleri deposu vardır. Elm paket yöneticisi ile bu paket havuzundan yararlanmak çok kolay. Deponun boyutu Python veya PHP gibi bazı diğer olgun programlama dilleriyle karşılaştırılamaz olsa da, Elm topluluğu her gün daha fazla paket uygulamak için çok çalışıyor.

Görüşümüze göre verilen fiyatlardaki ondalık basamakların nasıl tutarsız olduğuna dikkat edin?

Saf toString kullanımımızı depodan daha iyi bir şeyle değiştirelim: numeral-elm.

 cartProductView item = tr [] [ td [] [ text item.product.name ] , td [ align "right" ] [ text (formatPrice item.product.price) ] , td [ align "center" ] [ input [ value (toString item.qty) , onInput (ChangeQty item.product) , size 3 --, type' "number" ] [] ] , td [ align "right" ] [ text (formatPrice (itemSubtotal item)) ] ] formatPrice : Float -> String formatPrice price = format "$0,0.00" price

Burada Numeral paketindeki format fonksiyonunu kullanıyoruz. Bu, sayıları, genellikle para birimlerini biçimlendirdiğimiz şekilde biçimlendirir:

 100.5 -> $100.50 15.36 -> $15.36 21.15 -> $21.15

Otomatik Dokümantasyon Üretimi

Elm deposuna bir paket yayınlarken, koddaki yorumlara dayalı olarak belgeler otomatik olarak oluşturulur. Sepet modülümüzün belgelerine buradan göz atarak bunu çalışırken görebilirsiniz. Bunların tümü şu dosyada görülen yorumlardan oluşturulmuştur: Cart.elm.

Ön Uç için Gerçek Bir Hata Ayıklayıcı

En belirgin sorunlar, derleyicinin kendisi tarafından algılanır ve raporlanır. Ancak, hiçbir uygulama mantıksal hatalardan güvenli değildir.

Elm'deki tüm veriler değişmez olduğundan ve her şey güncelleme işlevine iletilen mesajlar aracılığıyla gerçekleştiğinden, bir Elm programının tüm akışı bir dizi model değişikliği olarak temsil edilebilir. Hata ayıklayıcı için Elm, sıra tabanlı bir strateji oyunu gibidir. Bu, hata ayıklayıcının zamanda yolculuk yapmak gibi gerçekten şaşırtıcı bazı özellikler gerçekleştirmesini sağlar. Bir programın ömrü boyunca meydana gelen çeşitli model değişiklikleri arasında atlayarak bir programın akışında ileri geri hareket edebilir.

Hata ayıklayıcı hakkında daha fazla bilgiyi buradan edinebilirsiniz.

Bir Arka Uçla Etkileşim

Yani güzel bir oyuncak yaptık diyorsunuz ama Karaağaç ciddi bir şey için kullanılabilir mi? Kesinlikle.

Sepetimizin ön ucunu bazı asenkron arka uçlara bağlayalım. Bunu ilginç kılmak için özel bir şey uygulayacağız. Tüm sepetleri ve içeriklerini gerçek zamanlı olarak incelemek istediğimizi varsayalım. Gerçek hayatta, bu yaklaşımı çevrimiçi mağazamıza veya pazar yerimize bazı ekstra pazarlama/satış yetenekleri getirmek veya kullanıcıya bazı önerilerde bulunmak veya gerekli stok kaynaklarını tahmin etmek ve çok daha fazlası için kullanabiliriz.

Böylece, sepeti istemci tarafında saklarız ve ayrıca sunucuya her bir sepet hakkında gerçek zamanlı olarak bilgi veririz.

İşleri basit tutmak için Python kullanarak arka uçumuzu uygulayacağız. Arka uç için tam kodu burada bulabilirsiniz.

Bir WebSocket kullanan ve alışveriş sepetinin içeriğini bellekte tutan basit bir web sunucusudur. İşleri basit tutmak için, diğer herkesin sepetini aynı sayfada oluşturacağız. Bu, ayrı bir sayfada veya hatta ayrı bir Elm programı olarak kolayca uygulanabilir. Şimdilik, her kullanıcı diğer kullanıcıların sepetlerinin özetini görebilecek.

Arka uç yerindeyken, şimdi sunucuya alışveriş sepeti güncellemeleri göndermek ve almak için Elm uygulamamızı güncellememiz gerekecek. Elm'in mükemmel desteğe sahip olduğu yüklerimizi kodlamak için JSON kullanacağız.

CartEncoder.elm

Elm veri modelimizi bir JSON dize temsiline dönüştürmek için bir kodlayıcı uygulayacağız. Bunun için Json.Encode kütüphanesini kullanmamız gerekiyor.

 module CartEncoder exposing (cart) import Cart2 exposing (Cart, Item, Product) import List exposing (map) import Json.Encode exposing (..) product : Product -> Value product product = object [ ("name", string product.name) , ("price", float product.price) ] item : Item -> Value item item = object [ ("product", product item.product) , ("qty", int item.qty) ] cart : Cart -> Value cart cart = list (map item cart)

Kitaplık, Elm nesnelerini alan ve bunları JSON kodlu dizelere dönüştüren bazı işlevler ( string , int , float , object vb.) sağlar.

CartDecoder.elm

Tüm Elm verilerinin türleri olduğundan ve hangi JSON değerinin hangi türe dönüştürülmesi gerektiğini tanımlamamız gerektiğinden, kod çözücüyü uygulamak biraz daha zordur:

 module CartDecoder exposing (cart) import Cart2 exposing (Cart, Item, Product) -- decoding for Cart import Json.Decode exposing (..) -- will decode cart from string cart : Decoder (Cart) cart = list item -- decoder for cart is a list of items item : Decoder (Item) item = object2 Item -- decoder for item is an object with two properties: ("product" := product) -- 1) "product" of product ("qty" := int) -- 2) "qty" of int product : Decoder (Product) product = object2 Product -- decoder for product also an object with two properties: ("name" := string) -- 1) "name" ("price" := float) -- 2) "price"

Güncellenmiş Karaağaç Uygulaması

Son Elm kodu biraz daha uzun olduğu için burada bulabilirsiniz. Ön uç uygulamasında yapılan değişikliklerin bir özeti aşağıda verilmiştir:

Orijinal update işlevimizi, alışveriş sepeti her güncellendiğinde alışveriş sepetinin içeriğindeki değişiklikleri arka uca gönderen bir işlevle tamamladık:

 updateOnServer msg model = let (newModel, have_to_send) = update msg model in case have_to_send of True -> -- send updated cart to server (!) newModel [ WebSocket.send server (encode 0 (CartEncoder.cart newModel.cart)) ] False -> -- do nothing (newModel, Cmd.none)

Ayrıca, sunucudan güncellemeleri almak ve yerel modeli buna göre güncellemek için ek bir ConsumerCarts String mesaj türü ekledik.

Görünüm, consumersCartsView işlevini kullanarak diğerlerinin sepetlerinin özetini oluşturmak için güncellendi.

Başkalarının sepetlerinde yapılan değişiklikleri dinlemek için arka uca abone olmak için bir WebSocket bağlantısı kuruldu.

 subscriptions : Model -> Sub Msg subscriptions model = WebSocket.listen server ConsumerCarts server = "ws://127.0.0.1:8765"

Ana işlevimizi de güncelledik. Artık Html.program ek init ve subscriptions parametreleriyle kullanıyoruz. init , programın ilk modelini belirtir ve subscription , aboneliklerin bir listesini belirtir.

Abonelik, Elm'e belirli kanallardaki değişiklikleri dinlemesini ve bu mesajları update işlevine iletmesini söylememizin bir yoludur.

 main = Html.program { init = init , view = view , update = updateOnServer , subscriptions = subscriptions } init = ( Model [] -- empty cart [ Product "Bicycle" 100.50 -- stock , Product "Rocket" 15.36 , Product "Bisquit" 21.15 ] Nothing -- error (no error at beginning) [] -- consumer carts list is empty , Cmd.none)

Sonunda, sunucudan aldığımız ConsumerCarts mesajını çözme yöntemimizi ele aldık. Bu, harici kaynaktan aldığımız verilerin uygulamayı bozmamasını sağlar.

 ConsumerCarts message -> case decodeString (Json.Decode.list CartDecoder.cart) message of Ok carts -> ({ model | consumer_carts = carts }, False) Err msg -> ({ model | error = Just msg, consumer_carts = [] }, False)

Ön Uçlarınızı Aklı başında tutun

Elma farklıdır. Geliştiricinin farklı düşünmesini gerektirir.

JavaScript ve benzeri diller alanından gelen herkes, Elm'in bir şeyler yapma şeklini öğrenmeye çalışırken bulacaktır.

Nihayetinde Elm, diğer çerçevelerin - en popüler olanların bile - sıklıkla yapmakta zorlandığı bir şey sunar. Yani, devasa ayrıntılı kodlara takılmadan sağlam ön uç uygulamalar oluşturmak için bir araç sağlar.

Elm, akıllı bir derleyiciyi güçlü bir hata ayıklayıcıyla birleştirerek JavaScript'in ortaya çıkardığı birçok zorluğu da ortadan kaldırır.

Elm, ön uç geliştiricilerin çok uzun zamandır özlem duyduğu şey. Artık onu çalışırken gördüğünüze göre, kendiniz bir deneme yapın ve bir sonraki web projenizi Elm'de oluşturarak avantajlardan yararlanın.