Elm의 Stream 라이브러리로 화면을 만들면

10983 단어 Chrome스트림Elm

Elm의 Stream 라이브러리를 사용해 보았습니다.



Elm Advent Calender 19일째입니다.

Elm의 Adkale은 활발합니다!

작년의 elm Advent Calender에서는 lm-native-ui로 ios 앱을 만들었습니다 -> 기사

stream


  • github
  • Elm package
  • elm에는 lazy list를 다루는 표준 라이브러리가 없기 때문에 만들었습니다
  • 다른 유사한 기능을 실현하는 라이브러리는 있지만 stack over flow에 취약하다
  • stack over flow하지 않는 lazy list 라이브러리이다
  • 그 외에도 Stream 라이브러리가 많이 있지만, 이것만 시도하십시오

  • 어떤 때에 사용할 수 있을까?


  • 문서에도 있는 대로 무한하게 흐르는 데이터에 대해서 어떻게 할 때 잡을 것 같다
  • elm이 클라이언트 어플리케이션을 만드는데 사용되는 것이라면 무한 스크롤에 표시되는 것 같은 데이터일까? 타임라인 표시와 같은 실시간으로 바시바시 데이터가 흐르고 오는 것?

  • 쉬운 사용법


  • 하나의 요소 스트림
  • singleHoge : Stream String
    singleHoge = Stream.singleton "hoge"
    
  • 리스트로부터 생성되는 Stream
  • streamFromList : Stream String
    streamFromList = Stream.fromList ["hogo", "huga", "hugi"]
    
  • Stream끼리 결합
  • concatStream : Stream String
    concatStream = Stream.concat singleHoge streamFromList
    
  • Stream의 선두로부터 요소를 1개로 요소를 뽑은 Stream을 취한다
  • elementAndTail : (String, Stream String)
    elementAndTail = Stream.next concatStream
    -- -> ("hoge", ["hogo", "huga", "hugi"])
    
  • 스트림을 List로 변환
  • listFromStream : List String
    listFromStream = Stream.toList concatStream
    -- -> ["hoge", "hogo", "huga", "hugi"]
    
  • 기타
  • map, filter, reduce, zip ... List의 함수와 비슷한 것들


  • 타임 라인적인 것을 만들어 보아 검증


  • 서버 측에서 무한대로 데이터가 흐릅니다.
  • 보기는 최근 10건

  • List로 만들어보기


    
    type alias Feed = {
     id: Int,
     subject: String,
     text: String
    }
    
    type alias Model = {
     feeds: List Feed
    }
    
    type Msg =
     ReceiveFeed Feed
    
    update msg model =
        case msg of
            ReceiveFeed feed ->
                ( { feeds = feed :: model.feeds }, Cmd.none )
    
    
    feedView feed = div [] [ text feed.subject ]
    
    feedList = List.map feedView >> List.take 10
    
    view model = div [] (model.feeds |> feedList)
    
    port receiveFeedPort : (Feed -> msg) -> Sub msg
    
    init = ({ feeds = [] }, Cmd.none)
    
    main = 
        Html.program
            { view = view
            , init = init
            , update = update
            , subscriptions = always <| receiveFeedPort ReceiveFeed
            }
    
    

    Stream으로 만들어 본다 (변경 부분 만 기재)


    type alias Model = {
     feeds: Stream Feed
    }
    
    update msg model =
        case msg of
            ReceiveFeed feed ->
                ( { feeds = Stream.concat (Stream.singleton feed) model.feeds }, Cmd.none )
    
    init = ({ feeds = Stream.fromList [] }, Cmd.none)
    
    
    feedList = Stream.map feedView >> Stream.nextN 10 >> Tuple.second
    
    

    움직였다.



    ↓이런 느낌

    피 c. 라고 r. 이 m/f5pC44우 Hfb — 스 (@4245Ryomt) 2017년 12월 19일


    List version



    • 300000 레코드 정도 흘려 넣으면 화면의 갱신이 뻣뻣해진다
    • Perfomance 도구에서 상황을 보면 힙을 엄청난 기세로 소비하고 있습니다 (소비 600MB까지 아가)
    • 그 영향인가 minor gc가 빈발해 시간이 걸려 화면이 가쿠가쿠가 되어 있는 것 같다 (?)


    스트림 버전




      ...
    • heap의 소비를 봐도 100MB 정도로 들어가 있다
    • minor gc에 시간이 걸리지 않는 것 같습니다


    그래프 봐서 움직임 전혀 당연하지. . .



    감상



    • 적당한 샘플에서의 비교로, 이것으로 좋은 것인가‥? 감이 있지만 Stream을 사용하여 장점을 느낄 수 있었다.
    • 왜 Stream이라면 heap를 소비하지 않는가?

      • map이나 filter라든지 읽어도 곧 새로운 인스턴스가 되지 않으니까? Array 낭비 생성되지 않기 때문에?

    • 왜 이 Stream이라면 좋은 느낌인지, 설명이 붙도록 정진하겠습니다.

    좋은 웹페이지 즐겨찾기