最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript開發(fā)簡單易懂的Svelte實(shí)現(xiàn)原理詳解

 更新時間:2021年11月25日 15:39:13   作者:廈門在乎科技  
這篇文章主要為大家介紹了JavaScript開發(fā)簡單易懂的Svelte實(shí)現(xiàn)原理的內(nèi)容詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步

Svelte問世很久了,一直想寫一篇好懂的原理分析文章,拖了這么久終于寫了。

Demo1

首先來看編譯時,考慮如下App組件代碼:

<h1>{count}</h1>
<script>
  let count = 0;
</script>

這段代碼經(jīng)由編譯器編譯后產(chǎn)生如下代碼,包括三部分:

create_fragment方法

count的聲明語句

class App的聲明語句

// 省略部分代碼…
function create_fragment(ctx) {
  let h1; 
  return {
    c() {
      h1 = element("h1");
      h1.textContent = `${count}`;
    },
    m(target, anchor) {
      insert(target, h1, anchor);
    },
    d(detaching) {
      if (detaching) detach(h1);
    }
  };
} 
let count = 0; 
class App extends SvelteComponent {
  constructor(options) {
    super();
    init(this, options, null, create_fragment, safe_not_equal, {});
  }
} 
export default App;

create_fragment

首先來看create_fragment方法,他是編譯器根據(jù)AppUI編譯而成,提供該組件與瀏覽器交互的方法,在上述編譯結(jié)果中,包含3個方法:

c,代表create,用于根據(jù)模版內(nèi)容,創(chuàng)建對應(yīng)DOM Element。例子中創(chuàng)建H1對應(yīng)DOM Element

h1 = element("h1");
h1.textContent = `${count}`;

m,代表mount,用于將c創(chuàng)建的DOM Element插入頁面,完成組件首次渲染。例子中會將H1插入頁面:

insert(target, h1, anchor);

insert方法會調(diào)用target.insertBefore

function insert(target, node, anchor) {
  target.insertBefore(node, anchor || null);
}

d,代表detach,用于將組件對應(yīng)DOM Element從頁面中移除。例子中會移除H1

if (detaching) detach(h1);

detach方法會調(diào)用parentNode.removeChild

function detach(node) {
  node.parentNode.removeChild(node);
}

仔細(xì)觀察流程圖,會發(fā)現(xiàn)App組件編譯的產(chǎn)物沒有圖中fragment內(nèi)的p方法。

這是因?yàn)?code>App沒有變化狀態(tài)的邏輯,所以相應(yīng)方法不會出現(xiàn)在編譯產(chǎn)物中。

可以發(fā)現(xiàn),create_fragment返回的cm方法用于組件首次渲染。那么是誰調(diào)用這些方法呢?

SvelteComponent

每個組件對應(yīng)一個繼承自SvelteComponentclass,實(shí)例化時會調(diào)用init方法完成組件初始化,create_fragment會在init中調(diào)用:

class App extends SvelteComponent {
  constructor(options) {
    super();
    init(this, options, null, create_fragment, safe_not_equal, {});
  }
}

總結(jié)一下,流程圖中虛線部分在Demo1中的編譯結(jié)果為:

fragment:編譯為create_fragment方法的返回值

UIcreate_fragment返回值中m方法的執(zhí)行結(jié)果

ctx:代表組件的上下文,由于例子中只包含一個不會改變的狀態(tài)count,所以ctx就是count的聲明語句

可以改變狀態(tài)的Demo

現(xiàn)在修改Demo,增加update方法,為H1綁定點(diǎn)擊事件,點(diǎn)擊后count改變:

<h1 on:click="{update}">{count}</h1> 
<script>
  let count = 0;
  function update() {
    count++;
  }
</script>

編譯產(chǎn)物發(fā)生變化,ctx的變化如下:

// 從module頂層的聲明語句
let count = 0; 
// 變?yōu)閕nstance方法
function instance($$self, $$props, $$invalidate) {
  let count = 0; 
  function update() {
    $$invalidate(0, count++, count);
  } 
  return [count, update];
}

countmodule頂層的聲明語句變?yōu)?code>instance方法內(nèi)的變量。之所以產(chǎn)生如此變化是因?yàn)?code>App可以實(shí)例化多個:

// 模版中定義3個App
<App/>
<App/>
<App/>
// 當(dāng)count不可變時,頁面渲染為:<h1>0</h1>
<h1>0</h1>
<h1>0</h1>

當(dāng)count不可變時,所有App可以復(fù)用同一個count。但是當(dāng)count可變時,根據(jù)不同App被點(diǎn)擊次數(shù)不同,頁面可能渲染為:

<h1>0</h1>
<h1>3</h1>
<h1>1</h1>

所以每個App需要有獨(dú)立的上下文保存count,這就是instance方法的意義。推廣來說,Svelte編譯器會追蹤<script>內(nèi)所有變量聲明:

  • 是否包含改變該變量的語句,比如count++
  • 是否包含重新賦值的語句,比如count = 1
  • 等等情況

一旦發(fā)現(xiàn),就會將該變量提取到instance中,instance執(zhí)行后的返回值就是組件對應(yīng)ctx。

同時,如果執(zhí)行如上操作的語句可以通過模版被引用,則該語句會被$$invalidate包裹。

Demo2中,update方法滿足:

  • 包含改變count的語句 ——?count++
  • 可以通過模版被引用 —— 作為點(diǎn)擊回調(diào)函數(shù)

所以編譯后的update內(nèi)改變count的語句被$$invalidate方法包裹:

// 源代碼中的update
function update() {
  count++;
} 
// 編譯后instance中的update
function update() {
  $$invalidate(0, count++, count);
}
  • 更新ctx中保存狀態(tài)的值,比如Demo2count++
  • 標(biāo)記dirty,即標(biāo)記App UI中所有和count相關(guān)的部分將會發(fā)生變化
  • 調(diào)度更新,在microtask中調(diào)度本次更新,所有在同一個macrotask中執(zhí)行的$$invalidate都會在該macrotask執(zhí)行完成后被統(tǒng)一執(zhí)行,最終會執(zhí)行組件fragment中的p方法

p方法是Demo2中新的編譯產(chǎn)物,除了p之外,create_fragment已有的方法也產(chǎn)生相應(yīng)變化:

c() {
  h1 = element("h1");
  // count的值變?yōu)閺腸tx中獲取
  t = text(/*count*/ ctx[0]);
},
m(target, anchor) {
  insert(target, h1, anchor);
  append(h1, t);
  // 事件綁定
  dispose = listen(h1, "click", /*update*/ ctx[1]);
},
p(ctx, [dirty]) {
  // set_data會更新t保存的文本節(jié)點(diǎn)
  if (dirty & /*count*/ 1) set_data(t, /*count*/ ctx[0]);
},
d(detaching) {
  if (detaching) detach(h1);
  // 事件解綁
  dispose();
}

p方法會執(zhí)行$$invalidate中標(biāo)記為dirty的項(xiàng)對應(yīng)的更新函數(shù)。

Demo2中,App UI中只引用了狀態(tài)count,所以update方法中只有一個if語句,如果UI中引用了多個狀態(tài),則p方法中也會包含多個if語句:

// UI中引用多個狀態(tài) 
<h1 on:click="{count0++}">{count0}</h1>
<h1 on:click="{count1++}">{count1}</h1>
<h1 on:click="{count2++}">{count2}</h1>

對應(yīng)p方法包含多個if語句:

p(new_ctx, [dirty]) {
  ctx = new_ctx;
  if (dirty & /*count*/ 1) set_data(t0, /*count*/ ctx[0]);
  if (dirty & /*count1*/ 2) set_data(t2, /*count1*/ ctx[1]);
  if (dirty & /*count2*/ 4) set_data(t4, /*count2*/ ctx[2]);
},

Demo2完整的更新步驟如下:

  1. 點(diǎn)擊H1觸發(fā)回調(diào)函數(shù)update
  2. update內(nèi)調(diào)用$$invalidate,更新ctx中的count,標(biāo)記countdirty,調(diào)度更新
  3. 執(zhí)行p方法,進(jìn)入dirty的項(xiàng)(即count)對應(yīng)if語句,執(zhí)行更新對應(yīng)DOM Element的方法

以上就是JavaScript開發(fā)Svelte實(shí)現(xiàn)原理詳解的詳細(xì)內(nèi)容,更多關(guān)于Svelte實(shí)現(xiàn)原理的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 讓mayfish支持mysqli數(shù)據(jù)庫驅(qū)動的實(shí)現(xiàn)方法

    讓mayfish支持mysqli數(shù)據(jù)庫驅(qū)動的實(shí)現(xiàn)方法

    mysql 是非持繼連接函數(shù)而 mysqli 是永遠(yuǎn)連接函數(shù)。也就是說 mysql 每次鏈接都會打開一個連接的進(jìn)程而 mysqli 多次運(yùn)行 mysqli 將使用同一連接進(jìn)程,從而減少了服務(wù)器的開銷。
    2010-05-05
  • 微信小程序Echarts覆蓋正常組件問題解決

    微信小程序Echarts覆蓋正常組件問題解決

    這篇文章主要介紹了微信小程序Echarts覆蓋正常組件問題解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-07-07
  • JavaScript閉包函數(shù)訪問外部變量的方法

    JavaScript閉包函數(shù)訪問外部變量的方法

    這篇文章主要介紹了JavaScript閉包函數(shù)訪問外部變量的方法,本文使用匿名函數(shù)來實(shí)現(xiàn)在閉包中訪問外部變量,需要的朋友可以參考下
    2014-08-08
  • 微信小程序?qū)崿F(xiàn)水平垂直滾動

    微信小程序?qū)崿F(xiàn)水平垂直滾動

    這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)水平垂直滾動,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-03-03
  • JS中frameset框架彈出層實(shí)例代碼

    JS中frameset框架彈出層實(shí)例代碼

    這篇文章主要介紹了JS中frameset框架彈出層實(shí)例代碼 的相關(guān)資料,需要的朋友可以參考下
    2016-04-04
  • javascript與webservice的通信實(shí)現(xiàn)代碼

    javascript與webservice的通信實(shí)現(xiàn)代碼

    關(guān)于javascript與webservice的通信,從理論上來說實(shí)現(xiàn)應(yīng)該不難,主要是將服務(wù)器端的xml數(shù)據(jù)進(jìn)行一個簡單的處理然后以一種適當(dāng)?shù)男问秸宫F(xiàn)成來。
    2010-12-12
  • 基于JS實(shí)現(xiàn)任務(wù)隊(duì)列的示例代碼

    基于JS實(shí)現(xiàn)任務(wù)隊(duì)列的示例代碼

    顧名思義,任務(wù)隊(duì)列就是存放任務(wù)的隊(duì)列,隊(duì)列中的任務(wù)都嚴(yán)格按照進(jìn)入隊(duì)列的先后順序執(zhí)行,所以下面我們就來看看如何基于JS實(shí)現(xiàn)任務(wù)隊(duì)列吧
    2023-08-08
  • 同一個網(wǎng)頁中實(shí)現(xiàn)多個JavaScript特效的方法

    同一個網(wǎng)頁中實(shí)現(xiàn)多個JavaScript特效的方法

    這篇文章主要介紹了同一個網(wǎng)頁中實(shí)現(xiàn)多個JavaScript特效的方法,實(shí)例分析了多個特效的實(shí)現(xiàn)原理與相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-02-02
  • ECharts坐標(biāo)軸刻度數(shù)值處理方法例子

    ECharts坐標(biāo)軸刻度數(shù)值處理方法例子

    這篇文章主要給大家介紹了關(guān)于ECharts坐標(biāo)軸刻度數(shù)值處理的相關(guān)資料,文章介紹了一個用于圖表Y軸數(shù)值簡寫的函數(shù),它可以將大數(shù)值轉(zhuǎn)換為K、M、B等簡寫形式,從而使圖表更加美觀和易讀,需要的朋友可以參考下
    2024-11-11
  • D3.js中強(qiáng)制異步文件讀取同步的幾種方法

    D3.js中強(qiáng)制異步文件讀取同步的幾種方法

    這篇文章主要給大家介紹了d3.js中強(qiáng)制異步文件讀取同步的幾種方法,文中給出了詳細(xì)的介紹和解決方法,對大家具有一定的參考價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-02-02

最新評論

南安市| 泰和县| 海安县| 涪陵区| 工布江达县| 江源县| 米脂县| 宁国市| 诸暨市| 黄骅市| 杭州市| 凤凰县| 康马县| 靖安县| 洛隆县| 银川市| 岫岩| 缙云县| 同德县| 新民市| 青州市| 三台县| 娱乐| 繁峙县| 体育| 太康县| 松滋市| 阿鲁科尔沁旗| 赤峰市| 肃北| 达日县| 吴江市| 皮山县| 清镇市| 翼城县| 新化县| 广西| 康马县| 白山市| 竹溪县| 牟定县|