「懶」在軟件設計中,有着重大的意義。最多見的兩種「懶」,即是:css
懶得計算git
懶得加載github
「懶得計算」常見於服務器端:web
好比Multiplayer Online Role-PlayingGame,客戶端主動計算,遊戲服務器平滑過渡,在性能、遊戲同步性找一個合適恰當的點。其目的是節約服務器端CPU、內存等的消耗,把許多消耗性能的計算分佈在玩家電腦上;promise
好比cache,任何cache的目的都是:懶得從新計算,由於我已經計算過了。瀏覽器
好比web應用的表單校驗,在數據提交給服務器前進行數據有效性校驗,固然這樣的目的不是爲了省去服務器端的校驗,客戶端與服務器雙校驗是必須的,只是過濾一部分正常手段提交錯了的格式信息,從而偷必定程度的懶;服務器
「懶得加載」常見於瀏覽器端:好比圖片、視頻、音頻、css、js等的加載。架構
拿最多見的焦點圖滾動來講:焦點圖何時初始化完畢?等全部圖片加載完成仍是第一張圖片加載完成?這裏能夠好好考慮延遲加載。app
好比一三屏的網頁,用戶打開時候處於第一屏?第二屏和第三屏的圖片是否要加載?仍是根據用戶所處的viewport去加載viewport內部的圖片?oop
OK,上面說的都跟本文無關,本文主要講的是js按需加載。
有這樣一個頁面:
如你所見,用戶打開網站,頁面有一個a標籤,點擊可跳轉到美女網站,頁面還有一個按鈕,點擊可產生一個運動的小球。以下圖所示:
因此專門正對小球抽象出一個對象Ball.js:
define("Ball", { init: function (x,y,r,vx,vy,text) { this.x = x; this.y = y; this.r = r; this.d = 2 * r; this.vx = vx; this.vy = vy; this.text = text; this.element = document.createElement("div"); this.element.innerHTML = text; this.element.style.cssText = "text-align:center;position:absolute; -moz-border-radius:" + this.d + "px; border-radius: " + this.d + "px; width: " + this.d + "px; height: " + this.d + "px;background-color:green;line-height:" + this.d + "px;color:white;"; document.body.appendChild(this.element); var self = this; this.loop = setInterval(function () { self.tick(); }, 15) }, tick: function () { this.x += this.vx; this.y += this.vy; this.element.style.left = this.x + "px"; this.element.style.top = this.y + "px"; } })
後來,網站架構師通過隨機抽樣統計,發現打開這個頁面的10000人當中,其中有9999人點擊了美女網站直接跳轉去看美女了,而僅剩的1人仍是個女同胞,打開該頁面後立馬直接關閉,生怕本身老公發現這塊寶地。最後統計的結果就是:那個create a ball 的就根本沒有人按過。
既然create a ball從未有人點擊,那麼這個Ball.js就白白加載了,浪費了用戶帶寬。
這種場景在各類網站中太多了,好比youku登陸相關的彈出層的js,彈出層裏表單驗證的js。用戶進入頁面的時候可能僅僅只是想要看視頻。因此登陸相關的js能夠延遲到用戶點擊登陸以後再進行加載和執行。固然這個是js很是小,影響甚微,可是若是某一項目板塊特別大粒度,按需加載執行就特別重要。
KMDjs做爲JS工程化終極解決方案,以Kill AMD和CMD爲己任,確定會提供相關的解決方案。
先說一下,KMDjs的懶執行。這點KMDjs開銷真的是過小了,由於大部分邏輯都在init才真正執行,因此KMDjs模塊ready的開銷僅僅是建立類。
KMDjs又是怎麼解決懶加載的呢?不賣關子,直接上碼:
var crtBtn = document.getElementById("crtBtn"); var balls = []; crtBtn.onclick = function () { kmdjs.get("HelloKMD.Ball", function (Ball) { var ball = new Ball(100, 100, 28, 1, 2, "KMD.js"); balls.push(ball); }); }
固然,也支持 promise style:
kmdjs.get("HelloKMD.Ball").then(function (Ball) { var ball = new Ball(100, 100, 28, 1, 2, "KMD.js"); balls.push(ball); });
其實,上面不是我最初想要的lazy方式。我最初想要的是這樣的結果:
kmdjs.config({ name:"HelloKMD", baseUrl: "js", classes: [ { name: "HelloKMD.Ball", lazy:true }, { name: "Util.Bom",url:"Util" } ] }); define("Main",["Util"], { init: function () { var crtBtn = document.getElementById("crtBtn"); var balls = []; crtBtn.onclick = function () { var ball = new Ball(100, 100, 28, 1, 2, "KMD.js"); balls.push(ball); } var vp = Bom.getViewport(); setInterval(function () { for (var i = 0, len = balls.length; i < len; i++) { var ball = balls[i]; (ball.x + ball.r * 2 > vp[2] || ball.x < 0) && (ball.vx *= -1); (ball.y + ball.r * 2 > vp[3] || ball.y < 0) && (ball.vy *= -1); } }, 100) } })
能夠看到代碼沒有任何更改,只不過在config裏稍微配置了一番,但這幾乎要把wind.js集成進來,把
var ball = new Ball(100, 100, 28, 1, 2, "KMD.js");
變成
var ball=$await(new Ball(……..));
並且要去分析ast,還要去分析current scope,還要遍歷scope tree,還要去考慮build的問題,還要去…
最終我放棄!選擇了這種kmdjs.get的還不錯的方式。若是你有更好的想法、建議或意見,請第一時間告訴我,我會將其糅合進0.0.3版本當中。
https://github.com/kmdjs/kmdjs
目前仍是0.02版本,kmdjs.get將在0.0.3出現…