ホームページ  >  記事  >  ウェブフロントエンド  >  Haosou モバイル ページ Research_html/css_WEB-ITnose

Haosou モバイル ページ Research_html/css_WEB-ITnose

WBOY
WBOYオリジナル
2016-06-24 11:14:53812ブラウズ

まず、私は Haosou の社員ではないことをお断りしておきます。ソース コードの研究は単なる趣味であり、それ以外の意味はありません。次のコードは、PC-Chrome がモバイルをシミュレートするときに m.so.com から取得したものです。電話でアクセスできるように、いくつかの変数名を追加しました (ソース コードが難読化され、圧縮されているため)。もしあなたの会社に不快感を与えるようなことがあれば、[私に連絡してください]。できるだけ早く削除してください~

まず、キャッシュせずにソースコード全体を見てください: ソースコード内のいくつかの変数を変更し、コンテキストに基づいてコメントが追加されています~

html<!Doctype html><!-- g-loading类让页面默认有个全局的loading图标,体验更友好,在下面页面会隐藏 --><!-- home_next应该属于某个js的埋点 --><html id=home_next class="g-loading" lang="zh-CN"><head><meta charset="UTF-8"><title>360搜索,SO靠谱</title><!-- 应该是速度上报勾子 --><script>wpo={p:"m_so",start:+(new Date),page:"home"}</script><!-- 页面全局变量 --><script> MSO = {}; SOH = {}; ENV = {}; <!-- 看样子应该部分变量是server端从ua中读取 --> ENV.android = '6_0'; ENV.webp = '1'; ENV.domain = 'so.com'; ENV.abv = 'a'; ENV.nat = '1'; ENV.brandname = '360'; ENV.sitename = '360搜索';</script><!-- 下面是ls缓存读取的核心js,会跟后端服务(判断是否有缓存而输出不同的html片段)有耦合 --><script>(function (e, document) { // 查找id元素 function getId(e) { return document.getElementById(e) } // 给cookie上打个标识,来设置浏览器不支持缓存 function setNotSupportLS() { setCookie("stc_nls", 1, 1) } /** * 读取ls的数据 */ function i(n, r) { var i = ""; // 容错,主要是怕读取出错 try { i = LS[n] || "", // 如果小于99则认为是error,则清空ls版本号 i.length < 99 && (setCookie(r, 0), // 设置页面不可见,然后强制刷新下页面 document.documentElement.style.display = "none", l(), e.onbeforeunload = null, location.reload(!0)) } catch (s) { // 出错时清空版本号 clearLS() } return i } /** * 设置ls数据 */ function setLS(key, t) { try { // 先设置数据到ls // 再读取设置后的内容是否跟源数据相等,如果不相等则清空ls版本,这里主要处理可能ls超大设置失败 LS[key] = t, t !== LS[e] && clearLS() } catch (n) { clearLS() } } /** * 获取cookie */ function o(e) { var n = document.cookie.split("; "); for (var r = 0, i = n.length, s; r < i; r++) { s = n[r].split("="); if (s[0] === e) return s[1] } return "" } /** * 轻量级设置cookie */ function setCookie(key, value, r) { // 默认60天 r = r || 60, // 如果没有值则为-1,也就是清空 value || (r = -1), // 过期时间,单位为天 r = (new Date(+(new Date) + r * 86400000)).toGMTString(); // 生成cookie var i = key + "=" + value + "; path=/; expires=" + r; // 如果是https则加密cookie location.protocol.indexOf("https") > -1 && (i += "; Secure"), // 写入吧,少年 document.cookie = i } /** * 读取id=e的元素内容,写入ls * @param {string} e ls里的key名 * @param {string} t 元素id名 */ function html2ls(e, t) { // 如果元素存在,就获取内容,并去两端空格 var r = getId(t) && getId(t).innerHTML.trim(); setLS(e, r) } /** * 读取ls数据,并生成标签到页面中 */ function ls2html(e, n, r) { var s = i(e, r), o = document.createElement(n); o.innerHTML = s, document.head.appendChild(o) } /** * 清除cookie里的ls版本号 */ function clearLS() { var e = /(?:;)?stc_[^=]*=[^;]*;?/g, n = document.cookie.match(e) || [], r = n.length; while (r) --r, setCookie(n[r].split("=")[0], 0) } /** * 更新版本号,这个很牛b */ function updateVersion(e, t, n) { var r = o(e).split(""), i = !1; // cookie里是以2位版本号紧邻存储,比如: // a文件的一位版本是a,二位版本是b: xxoo=ab // b文件的一位版本是1,二位版本是2: xxoo=ab12 //  // 后端在判断是否有缓存时应该也是这样循环,判断b文件版本对否时循环1,然后判断紧邻的版本是不是2,如果是则认为有缓存,否则认为缓存失败 //  // 这样的好处是cookie值非常的小,因为最多2个版本,比md5要小 // 但由于位数限制,和只能用 数字+字母+部分符号 做为版本 可能文件数量上有些问题,但对于移动端来说应该完全足够 for (var s = 0, a = r.length; s < a; s += 2) // 如果查找到该标识则设置 if (r[s] === t) { r[s + 1] = n, i = !0; break } // 如果找了一圈发现没有标识说明没有设置过cookie则直接添加2位版本号 i || r.push(t, n), // 写入吧 setCookie(e, r.join("")) } var noop = function () {}, LS, d = 0, // 先全部设置空方法 v = e.LS = { html2ls: noop, ls2html: noop, updateVersion: noop }; // 尝试设置ls,如果失败则打上浏览器不支持ls的标识 stc_nls try { LS = localStorage, v.html2ls = html2ls, v.ls2html = f, v.updateVersion = c } catch (m) { setNotSupportLS() }})(this, document)</script><!-- 由于第一次进入页面,则输出html真实代码,并设置到ls里,更新版本号,这里是 !U --><style id="stc_home_next_css"> /*css*/</style><script>LS.html2ls("stc_home_next_css","stc_home_next_css");LS.updateVersion('stc_ls_p_s','!','U')</script><link rel="apple-touch-icon-precomposed"href="/favicon.png"><!-- dns预解析 --><link rel="dns-prefetch"href="//p.ssl.qhimg.com"><link rel="dns-prefetch"href="//s.ssl.qhimg.com"><link rel="dns-prefetch"href="//ps.ssl.qhimg.com"><meta name=viewport content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"><meta name="format-detection" content="telephone=no"><meta name=keywords content="360搜索,网页搜索,视频搜索,图片搜索,音乐搜索,新闻搜索,软件搜索,学术搜索"><meta name=description content="360搜索是安全、精准、可信赖的新一代搜索引擎,依托于360母品牌的安全优势,全面拦截各类钓鱼欺诈等恶意网站,提供更放心的搜索服务。 360搜索 so靠谱。"><meta content=always name=referrer><!-- 看下面代码是日志上报方法,并且截获了error报错上报、alert上报,alert上报这个很不错,因为在移动端alert不友好,用上报+统计查看可以知道开发者有没有添加alert,很赞,但我在chrome-pc里测试并没有上报,可能跟环境有关 --><script>(function (e, t, n) { var r = alert, i = encodeURIComponent, // ... e.onerror = function (e, t, n, r, i) { for (var o = 0; o < u.length; ++o) if (s(u[o], e)) return; setTimeout(function () { if (c > 4 || l[e]) return; p({ code: "notice", msg: e }), l[e] = 1, ++c }, 1e3) }, e.alert = function (e) { p({ code: "warning", msg: "alert " + e }), !arguments.length && (e = ""), r(e) }})(this, ENV)</script><!-- 禁用js时隐藏页面,并跳转到极速版本 --><noscript>    <style>body{display:none}</style>    <meta http-equiv=refresh content="0; URL=/s?mode=jisu&noscript=1"></noscript><script>try { // 设置页面样式,应该有版本区分 document.documentElement.className += " w-" + (localStorage.home_w || 0)}catch (e) {}// 速度打点wpo.head = +(new Date) - wpo.start</script><style>html{background:#fff}</style></head><body><header class="i-hd" id=hd>    ...</header><script id="stc_home_next_base">// 这里引用了es6-promise库,可见用了很多promise的api// 这里引用了zepto库和一些常用模块// 这里写了个monitor,主要是日志上报模块</script><script>LS.html2ls("stc_home_next_base","stc_home_next_base");LS.updateVersion('stc_ls_p_s','T','R')</script><script id="stc_common">// 这里是webpack.js// 这里是webpack打包后的一些常用模块,应该是so的公用lib:模板引擎、 能用滚动事件、解析url参数、webp图片适配(切图)、图片延迟加载(跟dom有耦合)、节流、https代理(但我试了几个图片发现不管用,应该做了域名白名单或者我姿势不对)// 这里是基于webpack生成的MSO.observer,看代码应该是整个页面的事件驱动,应该有些固定的勾子,比如scroll、show之类,好处是事件统一接管,提供页面hook// 下面有一个牛b的东西登场:window._loader,看意思是个加载器,但她不只是加载器,在代码大概意思是:// 在使用时 _loade.use(uri),然后会首先判断该uri模块有没有被执行:// 如果执行过:则直接执行回调// 如果未执行过:// 读取ls里是否有该uri:// 有:// 判断版本:// 匹配:读取ls并执行回调// 不匹配:执行加载远程操作// 没有:// 直接加载文件,文件的内容类似jsonp,加载成功后会执行回调,并把文件md5+内容写入ls以方便后续使用// 再往下就是些逻辑代码不说了</script><script>LS.html2ls("stc_common","stc_common");LS.updateVersion('stc_ls_p_s','(','(')</script></body></html>

概要

開発モード

探していますコード部分ではes6を使って開発する必要があり、webpackを使ってブラウザ側で実行可能なバージョンにパッケージ化しているので開発効果は非常に高いですが、es6の全機能が使えていないように感じます。実行環境が必要であり、この環境の shim は小さくありませんが、promise-shim があるのを見たので、一部の機能だけを使用して変換する必要があると感じました。しかし、開発効率もある程度向上します ~

localStorage の応用

静的ファイルをキャッシュするために localStorage を使用するのは非常に一般的ですが、その方法は非常に斬新です:

  1. 2 桁のバージョン番号を使用して保存します特にトラフィックの多いサイトでは、Cookie のサイズを大幅に削減できます
  2. 一般的に使用されるモジュールも、localStorage を使用して存在します。これにより、iscroll などのトラフィックも節約されます。 、都市コードデータ、ご存知ですか〜

前に書いたもの: localStorage を自動的に更新するように設計する

イベント管理

ページ全体が MSO.observer によって均一に引き継がれ、共通イベントは統合トリガー (と呼ばれます)ここで公開します)。SO.Document内にこの側面があるはずであり、一般的なイベントの詳細な説明が含まれています~

たとえば、ページが読み込まれるときはloadイベントがあり、検索ボックスが読み込まれるときはsearch:focusイベントがあります。このようなイベントフックは、異なるモジュール間の通信と判断を容易にすることができます

その他

たとえば、フォールトトレランスは非常に優れており、Cookie や ls をオフにしてもエラーは報告されません。そして、そこに window.ENV 変数があることがわかりました。ua 情報の出力を決定するのはサーバー側であるはずです

もちろん、多くのユニークな発見があります~

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。