1. 程式人生 > >sea.js的同步魔法

sea.js的同步魔法

前些時間也是想寫點關於CMD模組規範的文字,以便幫助自己理解。今天看到一篇知乎回答,算是給了我一點啟發。

同步寫法卻不阻塞?

先上一個sea.js很經典的模組寫法:

// 定義一個模組
define(function(require, exports, module) {
  // 載入jquery模組
  var $ = require('jquery');
  // 直接使用模組裡的方法
  $('#header').hide();
});

按道理載入模組,就是需要等jquery.js載入完畢才能使用,應該是一個非同步的過程,為什麼可以寫成同步的形式呢?這是用了什麼黑科技?

原來作者玉伯大佬用了一個小魔法來“欺騙”我們。而盧勃大神在知乎給了一個很精彩的解釋,這裡直接分享下:

也就是說,require.jssea.js都是在執行模組前預載入了依賴的模組,並沒有比require.js顯得更“懶載入”,只是所依賴模組的程式碼執行時機不同。require.js載入時執行,而sea.js是使用時執行。

其實從程式碼的寫法也看得出來,require.js的依賴模組在載入後便有了執行結果,並作為回撥函式的實參傳入。

  • reuiqre.js寫法:
// 載入完jquery.js後,得到的執行結果$作為引數傳入了回撥函式
define(['jquery'], function($) {
  $('#header').hide();
});
  • sea.js寫法:
// 預載入了jquery.js
define(function(require, exports, module) {
  // 執行jquery.js模組,並得到結果賦值給$
  var $ = require('jquery');
  // 呼叫jquery.js模組提供的方法
  $('#header').hide();
});

從這一點上來看,兩者在效能上並沒有太多差異。因為最影響頁面渲染速度的當然是資源的載入速度,既然都是預載入,那麼載入模組資源的耗時是一樣的(網路情況相同時)。

而模組程式碼的執行時機並沒有那麼影響效能(除非你的模組太大),現在的js引擎如V8引擎足夠強,沒什麼壓力。

懶載入是否存在?

懶載入是存在的。我剛才說的sea.js並沒有比require.js更顯得“懶載入”是指模組載入的時機上兩者是一致的,都是預先載入,而不是說不能懶載入。

比如說,有一個模組,頁面渲染時,我不需要載入使用,但是在做了某種互動時(比如點了按鈕),才需要載入使用,這個時候“懶載入”的作用就體現了。下面以require.js

舉個例項:

require.config({
    baseUrl: './assets/js/',
    paths: {
        modulea: 'module-a',
        moduleb: 'module-b'
    }
})

require(["modulea"], function(modulea) {
    var btnNode = document.querySelector('#btn-load');
    var node1 = document.createElement('span');
    node1.innerText = '模組A已經載入!'
    btnNode.insertAdjacentElement('beforebegin',  node1)
    btnNode.addEventListener('click', function() {
        require(["moduleb"], function(moduleb) {
            var node2 = document.createElement('span');
            node2.innerText = '模組B已經載入!'
            btnNode.insertAdjacentElement('afterend',  node2)
        });
    })
});
  • 頁面渲染時只加載模組A

  • 點選按鈕後加載模組B

總結

雖然AMDCMD兩種思想有一些差異,但都不失為一種優秀的模組化方案,為大佬們打call!

首發連結