国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

京東單品頁前端開發那些不得不說的事兒

FleyX / 1903人閱讀

摘要:是負責展示京東商品的落地頁面。比如京東首頁,正常情況加載完頁面一共有多個節點,基本上全部用于展示商品信息廣告圖和內容布局,頁面上的三方異步服務也比較少。

原文:https://keelii.github.io/2016/07/31/something-have-to-say-with-JD-item

簡介

詳情頁也叫做單品頁,域名以「item.jd.com/skuid.html」為格式的頁面。是負責展示京東商品 SKU 的落地頁面。主要任務是展示和商品相關的信息,如:價格、促銷、庫存、推薦,從而引導用戶進入購買流程。同時單品頁有很多版本。一般分為兩類。一類我們通常看到的「通用類目詳情頁」—— 所有類目都可以使用,一類是不經常看到的「垂直屬性詳情頁」—— 一些有特殊屬性的商品集合。

首先。由于詳情頁大量(sku上億)、高并發(日 pv 約 5000 萬)等特性,在很長的一段時間里,單品頁面都是后端程序生成靜態頁面使用 CDN 來解決大量、高并發的問題。

其次。單品頁涉及的「三方」系統特別多,比如:促銷、庫存、合約、秒殺、預售、推薦、IM、店鋪、評價社區。而單品頁的主要任務就是展示這些系統的信息,并且適當的處理他們之間的沖突關系,而這些系統的接口一般都使用 異步 Ajax 來完成,因為 其一 CDN 無法做到頁面的動態化,其二 一些系統的信息對實時性要求特別高(價格、秒殺),即使使用后端動態渲染也很難做到無緩存 0 延遲。

基于上面兩個原因,注定了單品頁是一種重多系統業務邏輯展示型頁面。重前端頁面。我大概匯總了一下頁面上異步接口,總共約有 30 個,頁首屏的接口特別重要,接口之間幾乎都有耦合關系。

前端的發展歷程 混沌時期

混沌時期的單品頁并沒有前端開發的概念。核心的功能腳本只有三個:促銷價格(promotion.js)、庫存地區(iplocation.js)、其它邏輯(pshow.js)。這三個腳本分別是三個不同團隊的同事負責維護,當時我剛進入京東的時候在 UED 部門,負責頁面腳本整體的維護工作和 pshow的開發。那時候我自己維護的 pshow.js 腳本壓縮后只有 80 kb,所有的代碼都是過程式的,沒有任何使用模式和代碼技巧,JS 最多也只被用來做個判斷渲染 DOM。那時候的前端工作內容只在 UI 層面,寫樣式和一些交互腳本。

這個階段給我最深刻的感覺是單品頁后端模板很少維護(后端架構是最老的 aspx 版本)。大多數的改動都要用 JavaScript 去動態渲染。因為后端頁面是一個生成器生成的。如果頁面后端模板有改動那么就需要全量的生成一次,過程可能需要幾個小時。

初見端倪

當我接手這個項目時剛好有一次大改版,就在這時候老大說頁面上的腳本都要放在我們手里維護。然后就是一大波的重構、重寫。基本上 pshow 被重寫了大概 80% 其它的因為業務邏輯的問題并沒有完全重寫,只是做了些代碼層面的優化。

有一個模板引擎叫 trimPath,知道這個的估計都算老前端的了。最早的客戶端 JavaScript MVC 模式代表作品,只到現在還是使用。這個階段像評價這種完全異步加載的模塊特別適合使用模板引擎來減少維護的工作量。這個時候雖然頁面上的代碼并不都是我們寫的,但基本上前端對頁面的 JavaScript 有了控制權,接下來的事情就是尋找機會逐個優化。

這段時間是最痛苦的時候,維護的工作統一到前端。然后后端幾乎沒有變化,只是在一段時間將后臺的架構從 aspx 過渡到了 java。本質上并沒有什么改變。前端卻做了比以前更多的事情,也是在這個時候我接手了大量的維護工作(包含全站公共庫的維護)使得我意識到了一些自動化、工程化方面的重要性,后文會主要講解,順便說下,那時候前端自動化工具 Grunt 剛面世,但是我自己卻用的是 apache ant,不過不久就切換到了 Grunt 來構建項目。

撥云見日

單品頁不僅重系統邏輯,也重維護。

在這段時間里一方面有正常的維護類需求要做,一方面自己也不斷的學習新知識為以后的改版做鋪墊。不過就在這時單品頁有歷史意義的一次技改出現了 —— 單品頁動態化技改。關于后端部分的改造細節可以去 開濤的文章 了解。

總的來說這次的改版后很多數據直接從后端讀取,不再從前端異步獲取而且我們也做過一些異步加載的優化,多接口 combo 從統一服務吐出給前端使用。這時前端就不用再為異步接口的加載時苦腦了,只需要專注系統接口的邏輯。

隨著這次技改,前端的代碼也迎來了模塊化的時代。我們把所有的前端代碼都進行了模塊化然后基于 SeaJS 重寫,配合 Nginx concat 功能實現了本地模塊化開發,線上服務端合并。

單品頁前端模塊的結構與劃分 概覽

上圖可以看出,基本上最核心的模塊都在首屏。每個模塊都有多帶帶的一/多個腳本。代碼行數(LOC)由 230+ ~ 1200+ 不等。通常來說代碼行數越多代碼復雜性就越高,邏輯越復雜。很難想象「購買方式」這種只有一行屬性選擇功能的代碼行數卻 高達 1200 多行。其主要原因就在于購買方式所在的系統和其它首屏核心系統(庫存、促銷、地址選擇、白條)都有邏輯上的耦合。

看著不錯,然而在一個前端工程師眼里至少應該是這樣的(我只取了一些典型的模塊,并不是全部):

這就可以解釋為什么有的時候只是加一個很小的東西我們都為考慮再三然后通過 AB 測試提取相關數據,最后后再進行決策。單品頁的首屏可以說是寸土寸金。

按什么維度劃分模塊

起初我按模塊的屬性劃分,比如:核心、公共腳本、模塊腳本。但用了一段時候以后發現這樣劃分在單品這種大型系統中并不科學,因為這樣劃分出來的代碼只有劃分的人知道是什么規則,其它人接手代碼很難快速掌握代碼架構,而且尤其在模塊比較多的時候不方便維護。

后來我嘗試完全以功能模塊在頁面上出現的位置維度劃分。這樣以來維護起來方便多了,需要修改某個模塊代碼只需要對照著圖里面標識的模塊信息就能輕易找到代碼。

整體核心模塊

我們按頁面上的模塊結構首屏劃分出來這幾個核心模塊:

curmb - 面包屑

concat - 聯系咨詢相關店鋪信息

prom - 價格促銷信息

address - 地區庫存選擇,配送服務

color - 顏色尺碼

buytype - 合約機購買方式

suits - 套裝購買

jdservice - 增值服務

baitiao - 白條支付

buybtn - 購買按鈕

info - 地區提示信息

項目的整體樹形結構是這樣的:

模塊內部結構

比如下面這個大圖預覽的功能,我全部放在一個文件夾里面維護,但是邏輯上的 JavaScript 模塊是分離的,只是說文件夾(preview)就代表頁面上的某一部分功能集合。

注意文件夾的命名有一定的規則:

模塊腳本與樣式名必須一樣

需要制作 sprite 的圖片統一放在 module/i 目錄下面,生成的 sprite 圖片也在其中

生成的 mixin 在模塊根目錄下,便于其它樣式文件調用

我們再來看下自動生成生成的 __sprite.scss 是什么內容:

/* __sprite.scss 自動生成 */
@mixin sprite-arrow-next {
    width: 22px;
    height: 32px;
    background-image: url(i/__sprite.png);
    background-position: -0px -30px;
}

/* preview.scss 手動添加 */
@import "./__sprite";
.sprite-arrow-next {
    @include sprite-arrow-next;
}

注意引用的 mixin 名稱和我們需要手動添加的樣式類名一致。當然也可以直接生成一個類名對應的樣式,但是靈活性不好。比如 hover 的時候是另外一張圖片就沒法自動生成了。

前端技能樹 HTML DOM 節點數

與重業務邏輯的頁面不同,重展示的頁面一般具有很高的 DOM 節點數。比如京東首頁,正常情況加載完頁面一共有 3500 多個 DOM 節點,基本上全部用于展示商品信息、廣告圖和內容布局,頁面上的三方異步服務也比較少。尤其像頻道頁基本上沒有什么業務上的邏輯,全部是靜態頁面。這種頁面的特點是更新換代頻率高,一年兩三次改版很正常,CMS 做模塊化后兩天換個皮膚都是沒問題的。但是這種思路并不適合單品頁。單品頁更重業務邏輯,同時展示層 UI 邏輯也有很多關系。

我自己的經驗是:頁面上的 DOM 節點數絕對不能超過 5000 個,否則頁面滾動的時候就會出現卡頓的情況,尤其是移動端。

同步渲染還是異步加載

理論情況下最好做法是后端同步動態渲染頁面,但是由于 Web 應用中很多功能都是用戶行為驅動的。同步加載不可避免的消耗了后端服務資源。比如:非首屏模塊(公共頭尾、評價)、點擊事件觸發的 DOM 內容(異步 tab)。

所以我的經驗是:能放到后端做判斷渲染的 DOM 就盡量放在后端(尤其是首屏)。這樣做的好處有四點好處

后端渲染頁面相對穩定,不像前端 JavaScript 動態渲染 DOM,可能因為腳本報錯或者不可用造成模塊都無法展示

可訪問性、SEO 及用戶體驗也比較好。不會產生腳本的渲染抖動問題

一定程度上減少了前端渲染頁面的復雜性,減少前端代碼復雜度

邏輯統一到一個地方維護起來也方便,而且后端應該為業務邏輯負責,前端應該為展示UI 交互負責

對于異步渲染的模塊來說,后端通常需要判斷 「頁面有什么元素」,以及元素之間的依賴對應關系;而前端需要專注于 「元素應該怎么展示」,UI 層面的交互以及模塊與模塊之前的邏輯關系。

其實更多的時候 異步是一種沒有辦法的辦法,也就是說異步是其它方案都解決不了的情況下才考慮的。

外鏈靜態資源

盡量使用外鏈 CSS 和 JavaScript 資源,一方面便于緩存,減少服務同步輸出的資源浪費。IE 6 里面會有一些可怪的 bug,比如有內聯樣式 style 標簽的頁面 A 如果在另外一個頁面 B 中的 link 標簽中引用,那么這段 style 會在 B 頁面也起作用。

使用雙協議的 URL

使用 // 來代替http:https: 瀏覽器會自動適應兩種協議的資源訪問,兼容性較好。注意 IE 8 下使用腳本更新 src 為雙協議時會出現 bug,建議使用 location.protocol 來判斷然后做兼容處理。

刪除元素默認屬性

比如 script 標簽默認的 type 就是 text/javascript,如果 script 里面的內容是 JavaScript 時可以不用寫 type。另外如果要在頁面里面插入一段不需要瀏覽器解析的 HTML 片段時可以將 type 寫成 text/x-template(任意不存在的 type) 用于放置模板文件,通常用來在腳本中獲取其 innerHTML 而無任何負作用。

給腳本控制元素加上類鉤子

在腳本中取頁面元素使用 J- 前綴類名,與普通樣式類分離。這樣做會生成很多冗余的類名,但卻很好的降低了樣式和腳本的耦合,并且在重構和腳本職位分開團隊里會是一條最佳實踐。

CSS 樣式分類

所有頁面只共享一個 sass Mixin,里面包含了基礎的 sass 語法糖、常用類(清浮動、頁面整體顏色字體等)。

模塊級的樣式分為兩類:

與腳本無關的公共樣式,多帶帶在模塊文件夾中組織。比如:按鈕、標簽頁。全部放在 common 模塊中維護

與腳本相關的模塊級樣式,與對應模塊腳本放在一起,可以引用 common 中的公共樣式,但不可以被其它模塊引用

雪碧圖

關于雪碧圖 我經驗是:永遠不要想把所有的圖標拼合在一起。按模塊而不是按頁面去拼 sprite 更合理,更方便維護,然后配合構建工具自動接合生成樣式文件才是最好的解決方案。當然如果你的頁面比較簡單,那這條規則并不適用。說到這個問題我就得把珍藏多年的圖片拿出來 show 一把,用事實來說明為什么把所有圖片都拼在一張圖上就一定是對的。

早期由于年輕篤信將所有的 icon 拼在一張圖上才是完美的(圖 1)

后來維護起來實在不方便,就把按鈕全部多帶帶接合起來。注意,當時的按鈕都是圖片,設計方面要求的很嚴格。加入購物車按鈕做的也非常漂亮(圖 2)

然后這些都不是最典型的,下面這個 promise icon 才是 (圖 3)

從圖里面可以看到,這個功能在第一個版本的時候只有 7 個 icon,后來不斷增加,最多的時候達到 77 個。以至于當時每周都會添加兩個的頻率。

同時這個 icon 當時接合的時候技術上也有問題:不應該把文字也切到圖片里面,主要原因是早期 icon 比較少加上外邊框樣式對齊的問題綜合選擇了直接使用圖片。

后來我就覺得這樣是不對的。然后通過和產品的溝通,說明我的考慮以及新的解決方案后得到了認同。結果就是對圖片不進行拼合,后臺上傳經過審核的不帶文字 icon,文字由接口輸出,然后在產品上做了約定:icon 最多不能超過 4 個,代碼里也做了相應限制。這樣就能保證頁面上的請求數不會太多同時方便系統維護,問題得到了解決。

適當使用 DataURI

這個在一些小圖片場景方面特別適合,比如 1*1 的占位圖、loading 圖等,不過 IE 6 并不支持這種寫法,需要的時候可以加上一些兼容寫法:

.ELazy-loading {
    background: url(data:image/gif;base64,R0lGODlhKwAeAJEAAP///93d3Xq9VAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFFAAAACwDAA0AJQADAAACEpSPAhDtHxacqcr5Lm416f1hBQAh+QQJFAAAACwDAA0AJQADAAACFIyPAcLtDKKcMtn1Mt3RJpw53FYAACH5BAkUAAAALAMADQAlAAMAAAIUjI8BkL0CoxQtrYrenPjcrgDbVAAAOw==) center center no-repeat;
    *background-image: url(//misc.360buyimg.com/lib/skin/e/i/loading-jd.gif);
}
關于兼容性

兼容性可以說是前端工程師在平常開發中花費很大量無意義工作的地方。關于兼容性我想說的是 如果你不愿意去說服周圍的人放棄或者讓他們意識到兼容性是個不可能完全解決的問題,那么你就得為那些低級瀏覽器給你帶來的痛苦埋單

其實更好的辦法是你和設計、產品溝通然后給出一種分級支持的方案。把每種瀏覽器定義一個級別。然后在開發功能的時候以「漸進增強」的方式。通常來講我們的解決方案是在低級瀏覽器里面保證流程正常進行、模塊可以使用,但忽略一些無關緊要的錯位、不透明等問題,在高級瀏覽器里面需要對設計稿進行精確還原,適當的加上一些井上添花在細節。比如微小的動畫、邏輯細節上的處理等。

舉個例子吧,下面這個進度條表示預約的人數,它是接口異步加載完才展示的。如果加載完就立即設置進度條寬度會顯得生硬無趣,但是如果加上一點動畫效果的話就好多了。然而問題又來了,如果加上動畫那么邏輯上這個進度條應該是一點點的增加,對應的人數也應該是逐個增加。于是我就做了個優化,讓人數在這段時間內均勻的增加。這個細節并不是很容易被人發現,但是這種設計會讓用戶感覺很用心而且有意思。

JavaScript

單品頁的腳本加載/執行順序:

等待頁面準備就緒(DOM Ready)

準備就緒后加載入口腳本(main.js),腳本負責其它功能模塊的調度,動態接合模塊通過 seajs 的 require.async 方法異步調用

公共模塊(common.js)負責加初始化全局變量并掛載到 pageConfig 命名空間

動態模塊數組,這個是后端通過程序判斷處理生成的一個模塊名列表。一般只包含首屏需要加載的模塊

后加載模塊(lazyinit.js)初始化,這個腳本只做一些頁面滾動才加載的模塊事件綁定。當模塊出現在視口內再使用 require.async 異步加載模塊的資源及初始化

入口腳本

大致代碼如下

/**
* 模塊入口(1. 公共腳本 2. 首屏模塊資源 3. 非首屏「后加載模塊」)
*/
var entries = [];

// 頁面公共腳本樣式
entries.push("common");
// 頁面使用到的首屏模塊(后端開發根據頁面不同配置需要調用的模塊)
entries = entries.concat(config.modules);
// 非首屏「后加載模塊」
entries.push("lazyinit");

for (var i = 0; i < entries.length; i++) {
    entries[i] = "MOD_ROOT/" + entries[i] + "/" + entries[i];
}

if (/debug=show_modules/.test(location.href)) console.log(entries);

require.async(entries, function() {
    var modules = Array.prototype.slice.call(arguments);
    var len = modules.length;

    for (var i = 0; i < len; i++) {
        var module = modules[i];

        if (module && typeof module.init === "function") {
            module.init(config);
        } else {
            console.warn("Module[%s] must be exports a init function.", entries[i]);
        }
    }
});

注意模塊路徑中的 MOD_ROOT 是提前在頁面定義好的一個 seajs path。目的是為了把前端版本號更新的控制權釋放給后端,從而解決了前后端依賴上線不同步造成的緩存延遲問題,配置腳本中只有幾個定義好的路徑:

seajs.config({
    paths: {
        "MISC" : "http://misc.360buyimg.com",
        "MOD_ROOT" : "http://static.360buyimg.com/item/default/1.0.12/components",
        "PLG_ROOT" : "http://static.360buyimg.com/item/default/1.0.12/components/common/plugins",
        "JDF_UI"   : "http://misc.360buyimg.com/jdf/1.0.0/ui",
        "JDF_UNIT" : "http://misc.360buyimg.com/jdf/1.0.0/unit"
    }
});

還有一點,在測試環境的頁面中版本號(上面代碼中的 1.0.12 是一個全量的版本號)是后端從 URL 上動態讀取的(使用參數訪問就可以命中對應版本 item.jd.com/sku.html?version=1.0.12)。這樣以來測試環境上就可以并行測試不同版本的需求,而且互不影響。當然如果不同版本的后端代碼也有修改的話這樣是不行的,因為后端代碼也需要有個對應的版本號。

不過我們已經解決了這個問題。后端會在測試環境里 動態加載后端模板 并且可以做到版本號與前端一致。這樣以來配合 git 方便的分支策略就可以同時并行開發測試多個需求,不用多帶帶配多個測試環境。什么?你還在使用 SVN!哦。那當我沒說過。

事件處理模型

客戶端的 JavaScript 代碼基本上都是事件驅動的,代碼的加載解析依賴于瀏覽器提供的 DOM 事件。比如 onload, mouseover, scroll 等。

事件驅動的的模型特別適用于異步編程,而 JavaScript 天生就是異步,所有的異步操作行為都最終會在一個回調函數(callback)中觸發。

比如單品頁中價格接口,加載完成后需要更新 DOM 元素來展示實時價格;地區選擇接口加載完成后會更新配送信息、庫存/商品狀態等,偽代碼如下:

/* onPriceReady 和 onAreaChange 可以認為都是一個 Ajax 異步函數調用
 * code 1 和 code 2 執行到的時間是不確定先后順序的
 */
/* prom.js */
onPriceReady(function(price) {
    // code 1
    $("#price").html(price);
});

/* address.js */
onAreaChange(function(area) {
    // code 2
    $("#stock").html(area.stockInfo);
});

上面的兩段代碼分別在兩個腳本中維護,因為他們的邏輯相對獨立。早期并沒有關聯關系。后來需求有變,他們之間需要共享一些對方的數據(切換地區后需要重新獲取價格數據并展示)。但是物理上又不能放在一起通過使用全局變量的方式共享,而且它們都是異步加載接口后才取到數據的,并不好確定誰先誰后(非要做到那就只能用全局變量雙向判斷)。所以這樣并不能很好的解決問題,而且代碼的耦合度會成倍增加。

這時候我們引入了一種設計模式來解決這種問題 —— 發布者/訂閱者,我們把這種模式抽象成了自定義事件代碼來解決這一問題。這段代碼是由 YUI 核心開發者 Nicholas C. Zakas 實現的。代碼很簡單,事件對象主要有兩個方法 addListener(type, listener)fire(event)

于是我們重構了上面的偽代碼:

/* prom.js */
// 在代碼中注冊一個地區變化事件,獲取變化后的地區 id
// 然后重新請求價格接口并展示
Event.addListener("onAreaChange", function(data) {
    getAreaPrice(data.areaIds)
});

onPriceReady(function(price) {
    $("#price").html(price);

    Event.fire({
        type: "onPriceReady",
        data: "Any data you want"
    })
});

/* address.js */
onAreaChange(function(area) {
    $("#stock").html(area.stockInfo);

    // 在地區變化后除了做自己該做的事情以外
    // 觸發一個名為 onAreaChange 的事件,用來
    // 通知其它訂閱者事件完成,并傳遞地區相關參數
    // 這個時候在 onAreaChange Ajax 回調函數
    // 中就只需要關心自己的邏輯,其它模塊的耦合關系
    // 交給它們自己通過訂閱事件來處理
    Event.fire({
        type: "onAreaChange",
        data: area.ids
    })
});

需要注意的一點是,必須確保事件先注冊后觸發執行,也就是說先 addListener, 再 fire。

一些典型的性能優化點

基本上客戶端的 JavaScript 性能問題都來自于 DOM 查找和遍歷,在用于的時候一定要小心,可能不經意的一個操作就會損失很多性能,尤其在低端瀏覽器中。順便多說一點,現代的 JavaScript 解釋器本身是很快的,語言層面的性能問題很少遇到。DOM 查找慢是因為 瀏覽器給 JavaScript 訪問頁面提供的一套 DOM API 本身慢。

緩存 DOM 查找,同時 DOM 查找不要超過 2000 個,低級瀏覽器會卡頓

不要使用鏈式調用 find,如:find("li").find("a") 而是 find("li a")

在切換元素顯示狀態的時候,如果元素很多。優先使用 show()/hide() 方法,而不是 css("display", "block/none") 前者有緩存,后者會強制觸發 reflow

給節點添加 data-xx 屬性在存放一些數據,通過使用 jQuery 的 data("xx") 方法取更高效,減少 DOM 屬性訪問

高密度事件(scroll, mousemove)觸發場景請使用節流方法

使用事件代理,而不是直接綁定。如果不確定代碼被調用次數,可以先解除綁定再綁定具有命名空間的事件處理函數

盡量少用 DOM 動畫,使用 CSS 3 動畫代替

前端工程化 原由

前端工程化其實并不是最近兩年才有的概念。大約在 2013 年的時候 Grunt 問世的時候就已經有所涉及。這類打包工具主要的目的是自動化一些開發流程,我最早使用 Grunt 來構建代碼的時候只解決了三個問題:

合并壓縮優化樣式腳本

上線完自動備份

單個文件打包到多目錄(歷史原因一個文件線上的路徑有兩種,需要傳兩個目錄)

當時我還在組內做過一個分享,有興趣的可以去圍觀一下 Best Workflow With Grunt。

其實這些工具出現的原因是:當時前端領域的各種基礎設施很缺乏,而前端的工作內容又相對零散。工作時需要開很多的軟件。再加上 JavaScript 語言本身也很弱,就連包管理這種基礎的東西也沒有內置,以至于模塊化要通過一些第三方類庫來實現,比如:RequireJS, SesJS。

工具的重要性可以在我之前的一個分享中找到 前端開發工具系列。

現狀

如今前端工程的生態環境由于 NodeJS 的出現已經變得很好了。你可以根據自己的需求選一個合適的直接用到項目里面。像 Grunt, Gulp, browserify, webpack 等。不過要明白這些工具的出現從另一方面證明了前端開發天生存在很多的問題:

HTML 從誕生到 HTML 5 之前幾乎沒有任何變化,DOM 性能天生缺失。所以才有了 Virtual DOM 這種東西

CSS 只是一門描述型的語言,沒有變量、邏輯控制、語句。所以才出現了 Sass, Less 這種預編譯工具

JavaScript 號稱「高階的(high-level)、動態的(dynamic)、弱類型的(untyped)解釋型(interpreted)編程語言,適合面向對象(oop)和函數式的(functional)編程風格」的編程語言,但是語言本身有很多問題(ES 6 之前)。不適合大型項目的開發、沒有一些高級特性的支持、同時被其它語言詬病的 callback 風格、單線程執行等。所以才出現了像 TypeScript, Babel 這種編譯成 JavaScript 代碼的語言

這些問題幾乎都是歷史性的原因和兼容性因素造成的。作為一名好的前端工程師要看清楚現狀,然后按自己項目的需求去定制一些前端工程化的方案,而不是隨波逐流。

選擇

其實現在自己開發一套前端工程化/自動化流程的成本已經很低了,你只需要學習一些 NodeJS 的知識,配合 NPM 包管理機制,隨手就搞出一個構建工具出來。因為并不需要你去實現什么東西,所有的東西都有現成的包。腳本壓縮有 UglifyJS,CSS 優化有 CSS-min,圖片壓縮優化有 PNG-quant 等等。你只需要想清楚自己要達到什么目的,解決什么問題就可以抄家伙自己寫一套工作流出來。

我自己的經歷也從 Grunt, GulpJS 到現在自造輪子。自己根據需求開發出來一套集成的打包工具,有興趣的可以去圍觀一下 Wooo。

當然你也可以不用任何打包工具,自己寫一些 NPM Script 來完全定制化項目開發/測試/打包流程。我猜這也是為什么現在類似 Grunt 不再那么火,Gulp 遲遲沒有發布 4.0 版本的原因。寫一個構建工具的成本太低了,而且這種集成的工具很難滿足差異的開發需求。君不知已有人意識到了這一點么why-i-left-gulp-and-grunt-for-npm-scripts。

程序、設計、產品

我始終認為程序、設計是為了產品服務的。好的產品是要重視設計的,好的(前端)工程師是要有一些審美素養。

其實很多時候技術解決方案都是要根據產品的定位來設計的,了解產品需求以后才能定制出真正合適的高效的解決方案。好比前面講到的那個 sprite 案例,如果一開始就和產品討論好方案后來也不可能有那種失控的情況發生。在產品形成/上線前期能發現問題比上線后發現問題更容易解決。

這部分內容和代碼無關,就不多說了。然而早年我還有一次分享關于前端、改變。

總結

關于單品頁的前端開發本篇文章只是冰山一角,還有很多沒有提及,每個小東西都可以多帶帶寫一篇文章來分享。隨后希望可以有更多的總結和分享。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/90902.html

相關文章

  • node實現文件下載不得不說那些事兒

    摘要:如果像本例中這樣的場景會遇到這樣一個問題,詳見鏈接當請求參數過長或為了安全,就需要用到下載。寫到這里自己都忍不住想錘自己,給自己挖坑不說,這樣來回請求下載,流量,真的是敗家。 這幾天一直在做遠程文件下載的事,現在總算有了解決,特來記錄一下踩過的坑和想揍自己的心 需求 應用場景是這樣的,底層邏輯數據請求接口是由Java寫的,也就是說原始文件存在Java服務端,返回時有加密措施 由于工作...

    Coly 評論0 收藏0
  • “大促”背后技術 | 當我們說促銷時候,我們在談什么?

    摘要:郭理靖表示,在京東商城的實踐中,針對線上系統選擇構建兩個機房,分別是生產環境以及在災備環境。在監控引擎方面,京東云的嘗試也是比較細致的,其中包括監控服務報警服務等。進一步,根據不同的報警,我們可以定位到 showImg(https://segmentfault.com/img/bVbtNqp?w=688&h=113); showImg(https://segmentfault.com/...

    20171112 評論0 收藏0
  • “大促”背后技術 | 當我們說促銷時候,我們在談什么?

    摘要:郭理靖表示,在京東商城的實踐中,針對線上系統選擇構建兩個機房,分別是生產環境以及在災備環境。在監控引擎方面,京東云的嘗試也是比較細致的,其中包括監控服務報警服務等。進一步,根據不同的報警,我們可以定位到 showImg(https://segmentfault.com/img/bVbtNqp?w=688&h=113); showImg(https://segmentfault.com/...

    張巨偉 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<