91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Javascript模塊化發展,前端的血淚史。

發布時間:2020-07-13 06:56:15 來源:網絡 閱讀:564 作者:wx5dd7f4973a7ca 欄目:web開發
前言

?
Javascript 模塊的演化歷史一定程度上代表了前端的發展史。從早期的 對象字面量IIFE 到后來的 commonjs, AMD 等, 再到如今的 ES Module。這些模塊化方案在互聯網技術發展需求下不斷革新,演進。

本文從四個階段來講述 JS 模塊化的發展歷程,旨在讓大家了解 JS 模塊化是如何發展到今天,每個模塊方案在當時又解決了什么問題。

認知革命

?
Javascript模塊化發展,前端的血淚史。

Javascript 早期誕生的目的用于客戶端驗證表單,提高用戶體驗。站在今天的解決方案角度去回顧,在那個無樣式,無交互的,簡單的不能再簡單的 Web 頁面,很難想 JS 的模塊化意義在哪里。

如果非要達到一定程度代碼復用,對象字面量完全可以滿足 Web 互聯網早期的需求。
?

//Person.js
var Person = {
    say: function(words) {
        //code
    },
    run: function() {
        //code
    }
};

Person.say('say somthing');
Person.run();

歷史總會進步,互聯網上 Web 頁面越來越多樣化,好在人們會不斷的根據變化的需求調整模塊化的方式。
?
當團隊相互合作,去完成某一個項目時,對象字面量缺點就一覽無遺。命名沖突、作用域隔離等問題就不可避免的會發生,只是一個時間早與晚的問題。
?
javascript 函數,擁有者天然的局部作用域,外界是訪問不到函數內部的作用域。自然而然過渡到IIFE模塊化。
?


(function(global){
    var Person = global.Person || {};
    var pritiveFn = function(){
        //other code
    };
    var pritiveName = 'Tom';
    Person.say = function(words) {
        pritiveFn();
        console.log( pritiveName + 'say: ' + words);
        //other code
    }
    Person.run = function() {
        pritiveFn();
        //other code
    }
})(window);

Person.say();
Person.run();

這種模式,能任意定義不會被外界訪問到局部變量,也不會污染全局作用域,同時還能訪問全局中的一些變量。通過傳參命名空間,可將模塊掛在到全局 Person 命名空間上。

IIEF的模塊化方式,早已***到前端開發的基因。直到今天,在我們的日常開發中,都能見到或用到這種方式。

農業革命

Web2.0時代的到來,網站應用更加注重用戶與服務的雙向交互,前端開發也逐漸承擔更多的責任。一個網站,可能有成百上千的頁面,而且,javascrpt 不局限于客戶端。

commonjs

推崇 commonjs 模塊化規范的 Nodejs ,將模塊化推向了一個新的高度。

// path/ModuleA.js
var ModuleA = function(){
    //code
}
module.exports = ModuleA;

//-------------------------

// path/ModuleB.js
var ModuleB = function(){
   //code
}

module.exports = ModuleB;

//------------------------

// path/index.js
var ModuleA = require('./path/ModuleA');
var ModuleB = require('./path/ModuleB');

ModuleA();
ModuleB();

commonjs規范提供 module.exports(或者 exports)接口用于對外暴露模塊。require加載模塊。
仔細想想,日常開發中我們理所應當只關心模塊的自由導出和加載。而加載速度、依賴順序、作用域隔離等問題應該交給框架或者其他科學技術來系統解決,讓我們無感知。
但,nodejs 畢竟是運行在服務端的 javascript。
nodejs 中每個文件具有獨立的作用域,所以每個文件可認為是一個模塊。除非你顯示的定義在全局 global 對象上,否則其他文件是訪問不到該作用域的定義的任何數據。
在 nodejs 中,一個 js 文件擁有訪問其他模塊(文件)能力,這就很好的解決模塊間相互依賴的問題。并且所有文件都是在服務器本地加載,速度極快。
但瀏覽器客戶端的現狀是殘酷的。看下面例子,如果某個頁面依賴Slider, Dialog, Tab模塊,而這三個模塊又有一些自身的依賴。

<!-- 模塊自身的依賴 -->
<script src="./util/Animation.js"></script>
<script src="./util/Mask.js"></script>

<!-- 模塊依賴 -->
<script src="./Slider/index.js"></script>
<script src="./Dialog/index.js"></script>
<script src="./Tab/index.js"></script>

<script>
    Slider();
    Dialog();
    Tab();
</script>

上面的例子可以看出:

  1. 全局作用域被污染
  2. 開發人員必須手動解決模塊依賴關系(順序)。
  3. 同步遠程加載過多的文件,也會造成嚴重的頁面性能問題。
  4. 在大型,多人合作項目中,會導致整體架構混亂。
    而通過工具browserify,可將commonjs規范移植到瀏覽器端,本質上。browserify 是將所有被依賴commonjs的模塊,打包到當前業務代碼中。
    AMD

    瀏覽器中的 js,本身并無加載其他文件(模塊)的接口。聰明的人們用動態創建 script 節點實現了動態加載模塊。
    AMD, 異步模塊定義,采用的是異步加載模塊方式。依賴模塊是異步加載,不會阻塞頁面的渲染。
    AMD規范中最核心的接口是definerequire,顧名思義:定義和加載模塊。
    其中以requirejs代表,是AMD規范的實現。

// 定義模塊
define(['path/util/Animation'], function(Animation){
    // Slider code
    return Slider;
});

// 加載執行模塊
require(['path/Slider'], function(Slider){
    Slider();
})

可以看出,接口的第一個參數,代表模塊的依賴路徑。模塊或業務的代碼,放在 callback 中,其中 callback 參數提供暴露出了各依賴模塊的接口。

UMD

此時,模塊規范分成了commonjsAMD兩大陣營。天下大勢分久必合,需要一種解決方案同時兼容這兩種規范。而UMD規范的誕生就是解決該問題。

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD 規范
        define([], factory);
    } else if (typeof exports === 'object') {
        // commonjs 規范
        module.exports = factory();
    } else {
        // 掛載到全局
        root.globalVar = factory();
  }
}(this, function () {
    return {};
}));

從上面可以看出 UMD 是通過判斷運行環境中是否存在各模塊化的接口來實現的。

ES2015 Module

不管是 commonjs, AMD, UMD,都是畢竟是為了彌補 javascript 模塊缺陷而衍生出的民間解決方案。2015年es6的發布,讓javascript終于在語言層面上實現了模塊化。
?

// path/ModuleA.js
var ModuleA = function(){
    //code
}
exports default ModuleA;

//-------------------------

// path/ModuleB.js
var ModuleB = function(){
   //code
}

exports default ModuleB;

//------------------------

// path/index.js
import ModuleA from './path/ModuleA';
import ModuleB from './path/ModuleB';

ModuleA();
ModuleB();

commonjs 已經發展很成熟,也能滿足日常需求。初略看,es module “就像是語法糖”,我們為何還要去使用它呢,換句話說,我們是用它能為我們帶來哪些收益?
不管是 commonjs, AMD,他們的模塊架構是 “動態架構”,換句話說,模塊依賴是在程序運行時才能確定。而es module“靜態架構”,也就是模塊依賴在代碼編譯時就獲取到。所以在 commonjs 里能進行 “動態引入” 模塊。

if ( Math.random() > 0.5 ) {
    require('./ModuleA');
} else {
    require('./ModuleB');
}

而在 es module 中是無法進行類似操作的。從這個角度來看,es6 module 靈活性還不如 commonjs。但事物具有兩面性。es6 module 其實能為我們帶來以下幾個收益。
tree shaking
在我們部署項目時,常常需要將各個模塊文件打包成單個文件,以便瀏覽器一次性加載所有模塊,減少 reqeust 數量。因為在 HTTP/1 中,瀏覽器 request 并發數量有限制。不過隨之帶來的問題是,多個模塊打包成單文件,會造成文件 size 過大。
如果我們能在編譯期時確定好模塊依賴,就可以消除沒有用到的模塊,以便達到一定程度的優化,來看看下面例子。

// moduleA.js
export function moduleX(){
    //some code
}

export function moduleY(){
     //some code
}

// index.js
import { moduleX,  moduleY } from './moduleA';

moduleX();

通過工具 Rollup, 可將 index.js 打包成如下代碼:

'use strict';

function moduleX(){
    //some code
}

moduleX();

可以看出,打包的代碼只包含 moduleX,最大限度的減少了打包文件 size,這就是所謂的 'tree shaking', 讀者可以好好品味下這個詞,很傳神。
模塊變量靜態檢查
es6 module由于是“靜態架構”,在編譯時就能確定模塊的依賴樹以及確保模塊一定是被正確的 import/export ,這就為項目質量帶來很大的保障。看下面例子:

// module1.mjs
export function moduleX(){
    console.log(1);
}

// index.mjs
// 注意:module1.mjs 中并沒有 export 出 moduleY
import { moduleX, moduleY } from './module1.mjs';

moduleX();

//注意 
let randomNum = Math.random();
if (randomNum) > 0.3 && randomNum < 0.4 ) {
    moduleY();
}

?

如果沒有靜態檢查,在上面代碼中的條件判斷得出,代碼運行期間,執行 moduleY() 函數報錯的概率是10%,這種風險在線上環境就是一個非常大的隱患,一旦命中條件判斷,你一整年的績效可能就都沒了。
那如果有編譯期間靜態檢查,會是怎樣的結果?
運行 node --experimental-modules index.mjs 命令時,控制臺會報錯:

import { moduleX, moduleY } from './module1.mjs';
                  ^^^^^^^
SyntaxError: The requested module does not provide an export named 'moduleY'
    at ModuleJob._instantiate (internal/loader/ModuleJob.js:88:21)
    at <anonymous>

這種編譯時靜態檢查對項目的質量把控非常有用。
但 es6 module 有時候也讓我很憂傷。因為它很“靈活”,所以給我帶來了困擾。
來看看 import 語法:
Javascript模塊化發展,前端的血淚史。
再來看看 export 語法
Javascript模塊化發展,前端的血淚史。
額,其實我就想簡單的 import/export 而已,“少即使多”
農業革命是前端史的重大進步,社區各種模塊化解決方案以及事實上的標準,從另一方面也推動著 Javascript 從語言層面對模塊化進行支持。這為我們架構大型項目,保證項目質量提供了機會。

三:工業革命

模塊的兼容問題以及重復勞動應該交給工具去做,我們應該留出更多的時間享受”美好生活“。所以,涌現了一大批模塊化工具以及周邊的模塊管理工具。如Browserifyr.jsWebpackRollupjspmnpmyarn等等。
各種工具極大的提高了我們的工作效率,也我們對模塊化有了更多的選擇。
快樂同時也帶來很多的痛,就是因為可選擇工具太多,配置太多,讓你深陷其中無法自拔。要么忙著寫bug, 要么忙著寫配置。

結語

科學革命的時代,還未到來。也許到那時候,模塊化的使用就像var m = 1;語法一樣,它在我們腦海里本應該就是理所當然的存在,而不需借助其他編譯、運行等工具來實現。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

中卫市| 库尔勒市| 年辖:市辖区| 双牌县| 宁远县| 南通市| 永嘉县| 墨玉县| 福鼎市| 新巴尔虎右旗| 合山市| 都昌县| 孟连| 青州市| 阿合奇县| 宜黄县| 民乐县| 东方市| 体育| 德钦县| 巴彦县| 鹤壁市| 子洲县| 阿尔山市| 夏津县| 潮安县| 孟津县| 綦江县| 灌南县| 加查县| 巫溪县| 新建县| 孟连| 城固县| 绩溪县| 和田县| 绥棱县| 油尖旺区| 花莲县| 扎兰屯市| 盐源县|