Last active
October 19, 2016 13:08
-
-
Save benbai123/ebb40e9aa6d6a731ffa015a3af5ffeaf to your computer and use it in GitHub Desktop.
給前公司 找產品心得功能的修改建議
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
gzip 測試使用線上 gzip 網站 | |
可以直接估狗 gzip online 就找得到了 | |
http://www.txtwizard.net/compression | |
sample JSON 為連到 | |
https://www.urcosme.com/find-product/1 | |
開啟 Chrome Developer Tools 的 console | |
執行以下 SampleJSON.js 內的 JavaScript *1 | |
即會從當前頁面爬內容生成 JSON string | |
*1 只在剛連入時可用, 點選選項後因 s_href 變更就無法正確運作 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
此 Demo 為 Ctrl + Click 僅更新選項狀態, 選單不變動的狀況 | |
目前搜尋多個選項的狀況 | |
https://youtu.be/4HxmtMEwYQc | |
改成 Ctrl+Click 只在 Client 端更新選項狀態的情形 | |
https://youtu.be/HD58lU7C01A | |
傳送完整 HTML 與傳送 JSON 的差別 | |
https://youtu.be/V_IzBwBFNtI | |
連到頁面在 Chrome Console 執行下方 DemoImpl.js 內容 | |
即可測試效果 *1 *2 | |
*1 只有剛連入未點選任何選項前可用 | |
*2 選單不會變動, 更新內容時也仍是生完整內容且非 JSON 格式 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Ctrl + Click - 只更新 Client 端選項的選取/未選取狀態, 無傳輸 *1 | |
Alt + Click - 更新選取狀態外也更新選單內容, 僅傳輸選單內容 *2 | |
Click - 更新選取狀態外也更新產品內容, 僅傳輸產品內容 | |
雖然會有多選時可能無結果的問題, | |
但就是提供多一個操作選擇 | |
希望一定有結果的人也可以不按 Ctrl | |
以上是主要部份 | |
另一種可能是在多選無結果時, 提供建議結果 | |
簡單點的話是 | |
找 "產品+品牌+效果" 沒結果 | |
-> 找 "產品+品牌" 看有沒有結果 (可先 count 就好) | |
-> 再沒有就找 "產品" 的結果 | |
回傳 "沒有 OOO 的搜尋結果, 以下是搜尋 XXX 的結果 | |
(OOO XXX 為條件內容) | |
要再細還可以試著找到符合最多選項的結果 | |
簡單些就先 count 產品+品牌 再一個一個加上其它條件 | |
要效率更好可套用二分搜尋的做法 | |
或者更單純些, | |
把有結果的部份依由新到舊排序篩前二十筆, | |
在前二十筆中找有符合搜尋選項的屬性列出 | |
*1 右方動態出現的選項亦可直接由 Client 端同步調整 | |
另外可於此操作時隱藏之前的產品內容, | |
改為顯示 "以目前選項做查詢" 的按鈕 | |
*2 假若只有特定選項會變動選單, 可取消此操作, | |
直接在選特定選項時更新選單內容 | |
若有實作 "推薦搜尋" 功能 | |
也可直接列出完整選單只更新產品內容即可 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
只更新選項選取狀況只需要 Client 端操作, 對伺服器完全沒負擔 | |
更新選項清單, 會有生成及傳送選項清單的負擔, | |
但只會有一個 request | |
更新產品內容, 傳輸內容本身比選項清單少, | |
但是有額外的產品圖片等要讀取, | |
會多十多個 request (不含廣告) | |
假設使用者進行五次操作, | |
其中三次只變更選取狀況, 一次更新了選單, 最後一次更新了產品, | |
總共會是 1 個選單傳輸量 + 1 個產品傳輸量 + 十多個 request | |
相比原先 5 個選單傳輸量 + 5 個產品傳輸量 + 十多個 request * 5 | |
就改善了五倍 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
首先要知道的是, 這會是後端最主要的 loading 之一, | |
雖然 DB, Redis 也會有 CPU Memory 負載, | |
但它們很多時候是 "被共用" 的, 尤其是 Memory | |
但 "各 Request 組字串回應" 基本上各自獨立, | |
少有能共用的部份 | |
原本的回傳內容 HTML 的部份 及其 gzip 後的狀況為 | |
Original size: 137364 bytes Result size: 12329 bytes | |
若用 JSON 則是 | |
Original size: 16918 bytes Result size: 8589 bytes | |
可以看到壓縮前 size 差距約 8 倍 | |
這表示若是即時組成 | |
在 後端 要花 8 倍的 CPU/Memory 去組出內容及進行壓縮 | |
有可能會更多, | |
因為在 template 插入內容及壓縮通常需要額外的資源 | |
需求資源的成長通常不會是線性的 | |
如果是用 Redis Cache 則是 Cache 8 倍的內容 | |
且如果對它們使用 Cache, | |
不是很快被洗掉而效果不好 (Cache Size 有限制時) | |
就是要花很多空間 (Cache Size 無限制時) | |
而且注意到這是在 JSON 包含所有選單選項及產品的情形 | |
假如選單部份是只有傳 要隱藏的項目 | |
甚至選單是固定的可以完全 Client 端調整狀態 | |
那會少更多 | |
只傳所有產品的情形下是 | |
Original size: 4356 bytes Result size: 1232 bytes | |
可以看到未壓縮前 size 差 30 倍, 壓縮後差 10 倍 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
綜合以上, 除操作上更為順暢外, | |
對伺服器的負擔以及傳輸量等分別可改善數倍到上百倍 | |
如 5 次操作只傳一次 產品 JSON | |
在傳輸量上可改善 50 倍 (5*產品 JSON 壓縮後差 10 倍) | |
組裝回傳結果的 CPU/MEM 上可改善 5*30 = 150 倍 | |
另外也可以避免 | |
無法區分使用者點擊只是要選選項還是要查內容 | |
的問題, 讓操作的 GA 資料更有意義 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
目前選項是帶 s_href | |
每次點選透過 Server 端去重新生成所有選項的 s_href | |
若調整成 Client 端可這麼做 | |
不要由 s_href 帶完整 request url | |
改為帶該選項的查詢項目 及 查詢值 如下 | |
data-key="cat4" data-val="1" | |
點擊時若為要更新內容的操作再組 url | |
組 url 的部份見以下 BuildURL.js 內容 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var allC = {}, | |
allP = {}, | |
sampleJSON; | |
$('.group-box-body a').each(function () { | |
var self = $(this); | |
var lb = self.find('.custom-checkbox .label').html(), | |
key = self.attr('s_href').replace('/find-product/1?', '').split('=')[0], | |
val = self.attr('s_href').replace('/find-product/1?', '').split('=')[1]; | |
if (!allC[key]) allC[key] = {}; | |
allC[key][val] = lb; | |
}); | |
$('.product-list .item').filter(function () { | |
return !$(this).closest('.single-selector-pp-real')[0] | |
}).each(function () { | |
var prod = {}, | |
self = $(this), | |
ucph = self.find('.uc-point').html(), | |
uoc = self.find('.uo-stat'), | |
pid = self.find('a.img-block').attr('href').replace('/products/',''); | |
ucph = ucph.substring(0, ucph.indexOf('<')); | |
allP[pid] = { | |
img: [self.find('a.img-block img').attr('alt'), | |
self.find('a.img-block img').attr('src') | |
], | |
dt: self.find('.date-place').html().replace('上市', ''), | |
n: self.find('.item-name a').html(), | |
ucp: ucph.replace('UrCosme指數 ', ''), | |
rv: uoc.html().substring(0, uoc.html().indexOf('<')).replace('使用心得', '').replace('篇', ''), | |
p: uoc.find('.price').html().replace('NT$ ', ''), | |
br: [ | |
self.find('a.item-brand').attr('href').replace('/find-brand/', ''), | |
self.find('a.item-brand').html() | |
], | |
} | |
}); | |
// 包含左側選單及所有產品 | |
sampleJSON = JSON.stringify({ | |
cb:allC, | |
p:allP | |
}); | |
/* 只有所有產品的情形 | |
sampleJSON = JSON.stringify(allP); | |
*/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var baseURL = window.location.href, | |
ajaxurl = baseURL, | |
cond = {}, | |
data = [], | |
$sel = $('.group-box-body a').filter(function () { | |
return $(this).find('.custom-checkbox-checked')[0]; | |
}); | |
if ($sel.length) { | |
ajaxurl += '?'; | |
$sel.each(function () { | |
var s = $(this); | |
if (!cond[s.data('key')]) { | |
cond[s.data('key')] = []; | |
} | |
cond[s.data('key')].push(s.data('val')); | |
}); | |
for (var key in cond) { | |
data.push(key+'='+cond[key].join(',')); | |
} | |
ajaxurl += data.join('&'); | |
} | |
// 到此 ajaxurl 組合完成 | |
console.log(ajaxurl); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function buildOptUrl () { | |
var baseURL = window.location.href, | |
ajaxurl = baseURL, | |
cond = {}, | |
data = [], | |
$sel = $('.group-box-body a').filter(function () { | |
return $(this).find('.custom-checkbox-checked')[0]; | |
}); | |
if ($sel.length) { | |
ajaxurl += '?'; | |
$sel.each(function () { | |
var s = $(this); | |
if (!cond[s.data('key')]) { | |
cond[s.data('key')] = []; | |
} | |
cond[s.data('key')].push(s.data('val')); | |
}); | |
for (var key in cond) { | |
data.push(key+'='+cond[key].join(',')); | |
} | |
ajaxurl += data.join('&'); | |
} | |
return ajaxurl; | |
} | |
function newLoading (ajaxurl) { | |
loading(); | |
$.ajax({ | |
url: ajaxurl, | |
type: "GET", | |
data: { | |
is_ajax: !0 | |
}, | |
success: function(res) { | |
var $res = $(res); | |
closeLoading(), | |
// 換掉產品內容 | |
$(".product-filter-list .product-list").replaceWith($res.filter('.product-list')); | |
// 換掉分頁 | |
$(".product-filter-list .paging-wrapper").replaceWith($res.filter('.paging-wrapper')); | |
// 綁定分頁事件 | |
$('.pagination a').click(function(e){ | |
e.preventDefault(); | |
newLoading($(this).attr('href')); | |
}); | |
// 載入廣告 | |
googletag.pubads().refresh(); | |
$("body,html").animate({ | |
scrollTop: 200 | |
}, 800) | |
}, | |
error: function() {} | |
}); | |
} | |
// 給每個選項加上 data-key 和 data-val | |
$('.group-box-body a').each(function () { | |
var self = $(this); | |
var lb = self.find('.custom-checkbox .label').html(), | |
key = self.attr('s_href').replace('/find-product/1?', '').split('=')[0], | |
val = self.attr('s_href').replace('/find-product/1?', '').split('=')[1]; | |
self.attr('data-key', self.attr('s_href').replace('/find-product/1?', '').split('=')[0]); | |
self.attr('data-val', self.attr('s_href').replace('/find-product/1?', '').split('=')[1]); | |
}); | |
// 停用原本綁定的方法 | |
$('.group-box-body a').off('click'); | |
// 綁定新方法 | |
$('.group-box-body a').on('click', function (e) { | |
// 改 checked 的狀態 | |
// 也改 show 的狀態 | |
e.preventDefault(); | |
$(this).find('.custom-checkbox') | |
.toggleClass('custom-checkbox-checked') | |
.toggleClass('show'); | |
// 如果沒有按 Ctrl Key 就換內容 | |
if (!e.ctrlKey) { | |
newLoading(buildOptUrl()); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment