Svelte 前端框架探索

Svelte 的做者也是 rollup 的做者 Rich Harris,前端界的輪子哥。sevlte 項目首次提交於 2016 年 11 月 16 日,目前版本是 3.6.1(2019-06-27),v3 版本進行了大改動,跟以前的版本有很大的差異(v一、v2 版本 API 用法跟 vue 很像,v3 徹底屬於本身的風格)。html

看下 2016-12-02,尤雨溪大神對此框架的評價(固然已通過時了,可是核心的思想仍是一致的):前端

這個框架的 API 設計是從 Ractive 那邊傳承過來的(天然跟 Vue 也很是像),但這不是重點。Svelte 的核心思想在於『經過靜態編譯減小框架運行時的代碼量』。舉例來講,當前的框架不管是 React Angular 仍是 Vue,無論你怎麼編譯,使用的時候必然須要『引入』框架自己,也就是所謂的運行時 (runtime)。可是用 Svelte 就不同,一個 Svelte 組件編譯了之後,全部須要的運行時代碼都包含在裏面了,除了引入這個組件自己,你不須要再額外引入一個所謂的框架運行時!

什麼是 Svelte?

Svelte 跟 vue 和 react同樣,是一個數據驅動組件框架。可是也有很大的不一樣,它是一個運行時框架,無需引入框架自己,同時也沒用到虛擬 DOM(運行時框架特性決定了這個框架跟虛擬 DOM 無緣)。vue

Svelte runs at build time, converting your components into highly efficient imperative code that surgically updates the DOM. As a result, you're able to write ambitious applications with excellent performance characteristics.

雖然沒使用到虛擬 DOM,但同樣能夠達到出色的性能,並且對開發者編寫代碼是十分便捷。react

與 React 和 Vue 有和不一樣?

那麼咱們先看下 svelte 的由於意思:苗條的。苗條的框架正是做者的初始目的,苗條包括代碼編寫量、打包大小等等。webpack

總結一下這個框架的優點,即做者開發新框架的目的。git

  • 靜態編譯,無需引入框架自身

    一個 Svelte 組件是靜態編譯,全部須要的運行時代碼都包含在裏面了,除了引入這個組件自己,你感受不到框架存在。github

  • 編寫更少代碼

    svelte 模板提供一些簡便的用法,在維護和編寫上都變得更簡單,代碼量更少(維護的代碼),這些模板會編譯爲最終的js 代碼。web

  • 只會打包使用到的代碼

    即 tree shaking,這個概念原本也是做者首先提出來的,webpack 是參考了 rollup。前端框架

  • 無需虛擬 DOM 也可進行響應式數據驅動
  • 更便捷的響應式綁定

    既有響應式數據的優勢,v3 版本也解決了 vue 數據綁定缺點,用起來十分方便。app

簡單用法對比

react hook

import React, { useState } from 'react';
export default () => {
  const [a, setA] = useState(1);
  const [b, setB] = useState(2);
  function handleChangeA(event) {
    setA(+event.target.value);
  }
  function handleChangeB(event) {
    setB(+event.target.value);
  }
  return (
    <div>
      <input type="number" value={a} onChange={handleChangeA}/>
      <input type="number" value={b} onChange={handleChangeB}/>
      <p>{a} + {b} = {a + b}</p>
    </div>
  );
};

vue

<template>
  <div>
    <input type="number" v-model.number="a">
    <input type="number" v-model.number="b">
    <p>{{a}} + {{b}} = {{a + b}}</p>
  </div>
</template>

<script>
  export default {
    data: function() {
      return {
        a: 1,
        b: 2
      };
    }
  };
</script>

svelte

<script>
  let a = 1;
  let b = 2;
</script>

<input type="number" bind:value={a} />
<input type="number" bind:value={b} />
<p>{a} + {b} = {a + b}</p>

都不用多說,一眼就看出來,svelte 簡單多了。

爲何不使用虛擬 DOM?

在 react 和 vue 盛行的時代,你會據說虛擬 DOM 速度快,並且還可能被灌輸一個概念,虛擬 DOM 的速度比真實 DOM 的速度要快。

因此若是你有這個想法,那麼你確定疑惑 svelte 沒用到虛擬 DOM,它的速度爲何會快?

其實虛擬 DOM 並非何時都快,看下粗糙的對比例子。

對比例子

這裏並無直接統計渲染的時間,經過不少條數據咱們就能夠感覺出來他們直接的性能。特別是點擊每條數據的時候,明顯感受出來(因爲是在線上的例子,因此首次渲染速度不許確,主要看點擊的響應速度)。

固然這僅僅是在 50000 條數據下的測試,對比一下框架所謂的速度,實際的狀況下咱們是不會一次性展現這麼多數據的。因此在性能還可行的狀況下,更多的選擇是框架所帶來的的便利,包括上手難度、維護難度、社區大小等等條件。

svelte

https://svelte.dev/repl/367a2...

<script>
  import { onMount } from "svelte";

  const  = [];
  for (let i = 0; i < 50000; i++) {
    list.push(i);
  }
  const beginTime = +new Date();
  let name = "world";
  let data = list;
  function click(index) {
    return () => {
      data[index] = "test";
    };
  }
  onMount(() => {
    const endTime = +new Date();
    console.log((endTime - beginTime) / 1000, 1);
  });
</script>

{#each data as d, i}
  <h1 on:click={click(i)}>
    <span>
      <span>
        <span>
          <span>Hello {name} {i} {d}!</span>
        </span>
      </span>
    </span>
  </h1>
{/each}

vue

http://jsrun.net/kFyKp/edit

<div id="component-demo" class="demo">
  <div v-for="(d, i) in list" @click="click(i)"> 
    <span>
      <span> 
        <span>
          <span>
            Hello {{name}} {{i}} {{d}}!
          </span>
        </span>
      </span>
    </span>
  </div>
</div>
const list  = []
for(let i = 0; i < 50000; i++) {
  list.push(i);
}
const beginTime = +new Date();
new Vue({
  el: '#component-demo',
  data: {
    list: list,
    name: 'Hello'
  },
  methods:{
    click(index){
      const list = new Array(50000);
      list[index] = 'test'
      this.list = list
    }
  },
  mounted(){
    const endTime = +new Date();
      console.log((endTime - beginTime) / 1000,1);
  }
})

react

http://jsrun.net/TFyKp/edit

const list  = []
for(let i = 0; i < 50000; i++) {
  list.push(i);
}
class App extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      list
    } 
  }
  click(i) {
    return ()=>{
      list[i] = 'test'
      this.setState({
        list,
      })
    }
  }
  render() {
    return (
      <div>
        {this.state.list.map((v,k)=>{
          return(
            <h1 onClick={this.click(k)}>
              <span>
                <span>
                  <span>
                    <span>
                      Hello wolrd {k} {v}!
                    </span>
                  </span>
                </span>
              </span>
            </h1>
          )
        })}
      </div>
    )
  }
}

function render() {
  ReactDOM.render(
    <App />,
    document.getElementById('root')
  );
}

render();

總結

首先虛擬 DOM 不是一個功能,它只是實現數據驅動的開發的手段,沒有虛擬 DOM 咱們也能夠實現數據驅動的開發方式,svelte 正是作了這個事情。

單純從上面的對比例子來看,svelte 的速度比虛擬 DOM 更快(不一樣框架虛擬 DOM 實現會有差異)。雖然沒有進行更深層次的對比,可是若是認爲虛擬 DOM 速度快的觀點是不徹底對的,應該說虛擬 DOM 能夠構建大部分速度還能夠的 Web 應用。

Svelte 有哪些好用的特性?

  • 徹底兼容原生 html 用法

    編寫代碼是那麼的天然,以下面就是一個組件。

    <script>
      const content = 'test';
    </script>
    <div>
      { test }
    </div>
  • 響應式也是那麼的天然

    <script>
        let count = 0;
        function handleClick () {
            // calling this function will trigger an
            // update if the markup references `count`
            count = count + 1;
        }
    </script>
    <button on:click="handleClick">+1</button>
    <div>{ count }</div>
  • 表達式也能夠是響應式的

    這個就牛逼了,更加的天然,這種特性只有靜態編譯才能作到,這個就是 svelte 目前獨有的優點。

    <script>
        let numbers = [1, 2, 3, 4];
        function addNumber() {
            numbers.push(numbers.length + 1);
        }
        $: sum = numbers.reduce((t, n) => t + n, 0);
    </script>
    <p>{numbers.join(' + ')} = {sum}</p>
    <button on:click={addNumber}>Add a number</button>
  • 自動訂閱的 svelte store

    這個其實就是訂閱發佈模式,不過 svelte 提供了自身特有的便捷的綁定方式(自動訂閱),用起來是那麼的天然,那麼的爽。

    這種特性只有靜態編譯才能作到,這個就是 svelte 目前獨有的優點。

    stores.js

    import { writable } from 'svelte/store';
    export const count = writable(0);

    A.svelte

    <script>
        import { count } from './stores.js';
    </script>
    <h1>The count is {$count}</h1>

    B.svelte

    <script>
        import { count } from './stores.js';
      function increment() {
            $count += 1;
        }
    </script>
    <button on:click={increment}>增長</button>
  • 全部組件均可以單獨使用

    能夠直接在 react、vue、angular 等框架中使用。

    // SvelteComponent.js 是已經編譯後的組件
    import SvelteComponent from './SvelteComponent';
    
    const app = new SvelteComponent({
        target: document.body,
        props: {
            answer: 42
        }
    });

Svelte 有什麼缺點?

svelte 是一個剛起步不久的前端框架,不管在維護人員仍是社區上都是大大不如三大框架,這裏列舉一下本人認爲的 svelte 存在的缺點。

  • props 是可變的

    固然這也是這個框架故意這樣設計的,這樣 props 也是能夠響應式的。

    <script>
      export let title;
      title = '前綴' + title
    </script>
    <h1>
      { title }
    </h1>
  • props 目前沒法驗證類型

    <script>
      export let propOne;
      export let propTwo = 'defaultValue';
    </script>
  • 沒法經過自定義組件自己直接訪問原生 DOM

    須要利用 props 的雙向綁定特性,這就可能致使深層次組件的須要層層傳遞 DOM 對象(是子父傳遞,不是父子傳遞)。

    App.svelte

    <script>
      export let customDOM;
    </script>
    <A bind:dom={customDOM} />
    <!--bind:this 是無用的,只有再原生纔有用-->

    A.svelte

    <script>
      export let dom;
    </script>
    
    <div bind:this={dom}>
      test
    </div>
  • 只有組件才支持 svelte 的靜態模板特性

    js 文件是不支持 sevelte 靜態模板特性的,像下面這樣是會報錯的。

    import { count } from './stores.js';
    function increment() {
      $count += 1;
    }
  • 組件不支持 ts 用法

    找了一下,沒找到能夠支持 ts 的解決方案,若是有解決方案能夠評論下。


學習和總結文章同步發佈於 https://github.com/xianshanna...,有興趣能夠關注一下,一塊兒學習和進步。
相關文章
相關標籤/搜索