Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
去啊无线前端的一天
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
ningzbruc
February 01, 2016
Programming
200
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
去啊无线前端的一天
去啊无线前端的一天
ningzbruc
February 01, 2016
More Decks by ningzbruc
See All by ningzbruc
如何写出一个优秀的开源库
ningzbruc
0
68
React & Component
ningzbruc
0
47
阿里旅行去啊H5首页总结&Promise
ningzbruc
0
270
KISSY.Base - all about that Base
ningzbruc
0
140
Hammer.js
ningzbruc
1
340
淘宝旅行门票iPad版开发
ningzbruc
0
140
Travel on KISSY mini
ningzbruc
0
210
Events
ningzbruc
2
130
Why YUI3
ningzbruc
0
190
Other Decks in Programming
See All in Programming
Jetpack Compose メカニズム
skydoves
0
400
GKE で Pod の見方を変えたら、スケールアウト時の挙動を真に捉えられた話
stkk
0
120
変化を抱擁するドキュメントの作り方 - ビジネスルール駆動開発がもたらす、コードとの新しい関係
ioki
2
200
テストを司るデーモンに会いに行く 〜隔離した仮想マシンでテストを通すまで〜
h1d3mun3
1
340
Streamlitで実現する自然言語データアプリ開発
ayumu_yamaguchi
0
270
Claude Codeを組織的に動かして月400PRを実現した話
happy_ryo
0
270
FreeBSDでZabbixを動かす.pdf
kenkino
0
240
型解析で実現する Go の言語内 DSL / Conference に Go! タイムテーブルの歩き方 for Gophers
mazrean
0
150
AI × TiDD / 2026.09.05 Redmine 大阪
tokudiro
1
150
AWS DevOps Agentで インシデント対応をAIに任せたい
honmarkhunt
7
2.9k
20260828_品質と開発生産性を両立させる、AI時代のE2Eテストの考え方
magicpod
0
210
速く作れる。その次は、速く確かめられる開発へ 〜AIネイティブ開発を支える、Shift Down〜 / Can build fast. Next, moving to development where we can verify fast.
rkaga
2
810
Featured
See All Featured
YesSQL, Process and Tooling at Scale
rocio
174
15k
A Tale of Four Properties
chriscoyier
163
24k
The #1 spot is gone: here's how to win anyway
tamaranovitovic
3
1.2k
Game over? The fight for quality and originality in the time of robots
wayneb77
1
270
Site-Speed That Sticks
csswizardry
13
1.5k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
249
1.3M
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.9k
Exploring the relationship between traditional SERPs and Gen AI search
raygrieselhuber
PRO
2
4.3k
The untapped power of vector embeddings
frankvandijk
2
1.9k
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
68
57k
How to build an LLM SEO readiness audit: a practical framework
nmsamuel
1
900
Transcript
㣁冠┮䷐䥥⃡Ⰺ D[夯䔺
ň撮宦Ⅷ䠖史猾撮㢑㜎㇛䚐⭤↡℩䥥揞㤐⻰ECUG猳ʼn 09:30
None
None
None
工具集 • git - 版本管理/代码发布 • node - 本地服务/开发工具 •
yo - 项目脚手架 • grunt - 项目构建 • bower - 组件安装 • sass - CSS编译 • generator-clam - 去啊前端脚手架
None
mods: 公用模块 pages: 项目页面 widgets: 公用组件
None
generator-clam ✓ 项目初始化 ✓ 本地调试 ✓ 构建代码 ✓ 发布页面
就是这个feel...倍儿爽~
ň㋌ℱテ∽猾庅䨀ㅓ䀜ʼn 09:40
None
None
None
‧ 日历 ‧ 筛选 ‧ 排序 ‧ 轮播 ‧ 滚动列表
‧ 自动完成 ‧ 横竖屏检测 ‧ … ✓ 组件丰富 ✓ 兼容性强 ✓ 体积轻量 ✓ 体验完美 ✓ 应用广泛 mpi组件列表
‧ 日历 ‧ 筛选 ‧ 排序 ‧ 轮播 ‧ 滚动列表
‧ 自动完成 ‧ 横竖屏检测 ‧ … ✓ 组件丰富 ✓ 兼容性强 ✓ 体积轻量 ✓ 体验完美 ✓ 应用广泛 mpi组件列表
核心代码库 • kissy mini - 基础库 • jsbridge - 与客户端交互
• mpi_css - 样式库 • mtop - 无线标准数据平台 • mpi - 组件库
{ "directory":"./", "shorthand_resolver":"http://gitlab.alibaba-inc.com/ {{{owner}}}/{{{package}}}.git" } ➜ widgets git:(master) ✗ bower
install kissy=kissy/m ➜ widgets git:(master) ✗ bower install mpi/mtop 安装组件 • .bowerrc 项目初始化时会自动安装常用组件~
<!DOCTYPE html> <html lang="zh"> <head> <title>Demo</title> <meta charset="utf-8" /> <!--Global
StyleSheets--> <link rel="stylesheet" href="../../widgets/mpi_css/mpi.css" /> <link rel="stylesheet" href="./index.css"/> <!--Global JavaScripts--> <script src="../../widgets/kissy/build/mini-all.js"></script> <script src="../../widgets/jsbridge/index.js"></script> <script src="../../widgets/mtop/index.js"></script> <script src="../../config.js"></script> <script src="../../map.js"></script> </head> <body> <h1>Demo</h1> <!--TMS--> <!--HTTP:http://trip.taobao.com/go/rgn/trip/act-818-preferential.php,gbk:HTTP--> <script> KISSY.use('h5-test/pages/search/index', function(S, Search) { new Search(); }); </script> </body> </html> • pages/search/index.html
<!DOCTYPE html> <html lang="zh"> <head> <title>Demo</title> <meta charset="utf-8" /> <!--Global
StyleSheets--> <link rel="stylesheet" href="../../widgets/mpi_css/mpi.css" /> <link rel="stylesheet" href="./index.css"/> <!--Global JavaScripts--> <script src="../../widgets/kissy/build/mini-all.js"></script> <script src="../../widgets/jsbridge/index.js"></script> <script src="../../widgets/mtop/index.js"></script> <script src="../../config.js"></script> <script src="../../map.js"></script> </head> <body> <h1>Demo</h1> <!--TMS--> <!--HTTP:http://trip.taobao.com/go/rgn/trip/act-818-preferential.php,gbk:HTTP--> <script> KISSY.use('h5-test/pages/search/index', function(S, Search) { new Search(); }); </script> </body> </html> • pages/search/index.html
/** * @fileoverview pages/search/index.js */ KISSY.add(function (S, Base) { var
Search = Base.extend({ initializer: function() { console.log('search'); } }); return Search; }, { requires: ['base'] }); 还是熟悉的味道 还是原来的配方~
<!DOCTYPE html> <html lang="zh"> <head> <title>Demo</title> <meta charset="utf-8" /> <!--Global
StyleSheets--> <link rel="stylesheet" href="../../widgets/mpi_css/mpi.css" /> <link rel="stylesheet" href="./index.css"/> <!--Global JavaScripts--> <script src="../../widgets/kissy/build/mini-all.js"></script> <script src="../../widgets/jsbridge/index.js"></script> <script src="../../widgets/mtop/index.js"></script> <script src="../../config.js"></script> <script src="../../map.js"></script> </head> <body> <h1>Demo</h1> <!--TMS--> <!--HTTP:http://trip.taobao.com/go/rgn/trip/act-818-preferential.php,gbk:HTTP--> <script> KISSY.use('h5-test/pages/search/index', function(S, Search) { new Search(); }); </script> </body> </html> • pages/search/index.html
<!DOCTYPE html> <html lang="zh"> <head> <title>Demo</title> <meta charset="utf-8" /> <!--Global
StyleSheets--> <link rel="stylesheet" href="../../widgets/mpi_css/mpi.css" /> <link rel="stylesheet" href="./index.css"/> <!--Global JavaScripts--> <script src="../../widgets/kissy/build/mini-all.js"></script> <script src="../../widgets/jsbridge/index.js"></script> <script src="../../widgets/mtop/index.js"></script> <script src="../../config.js"></script> <script src="../../map.js"></script> </head> <body> <h1>Demo</h1> <!--TMS--> <!--HTTP:http://trip.taobao.com/go/rgn/trip/act-818-preferential.php,gbk:HTTP--> <script> KISSY.use('h5-test/pages/search/index', function(S, Search) { new Search(); }); </script> </body> </html> • pages/search/index.html
TMS http://daily.h5.taobao.org/wvdoc/awp/PageTags.html <!--TMS:/rgn/mytaobao_bk.html,utf-8,41:TMS--> <!--HTTP:http://****.html,(utf-8|gbk):HTTP--> 线上页面会将此标签替换成TMS区块内容
MTop.getApi(apiName, apiVersion, data, params, success, failure); MTop • waptest -
日常环境 • wapa - 预发环境 • m - 线上环境 根据URL来获取不同环境的数据
ň奞䐗㓲㺵扤哋⋂猾∧㓲㏔抹㤐槡屢廤庶⃬⃡ʼn 10:30
for mtop $ grunt demo proxy 本地代理 调试服务
for mtop $ grunt demo proxy 本地代理 调试服务
None
dev.m.taobao.com
None
dev.m.taobao.com
None
None
✓ 本地服务 ✓ TMS区块处理 ✓ Juicer数据模拟 ✓ 线上代码调试 ✓ 更多…
$ grunt online 本地未压缩文件 h5.m.taobao.com
$ grunt online 本地未压缩文件 h5.m.taobao.com
前端可以在海滩边晒太阳边写代码
ň浥椔∝䍌猾慢▉榟勱猾➒⇍㩆⃡⚲✈ʼn 14:00
<!DOCTYPE html> <html lang="zh"> <head> <title>Demo</title> <meta charset="utf-8" /> <!--Global
StyleSheets--> <link rel="stylesheet" href="../../widgets/mpi_css/mpi.css" /> <link rel="stylesheet" href="./index.css"/> <!--Global JavaScripts--> <script src="../../widgets/kissy/build/mini-all.js"></script> <script src="../../widgets/jsbridge/index.js"></script> <script src="../../widgets/mtop/index.js"></script> <script src="../../config.js"></script> <script src="../../map.js"></script> </head> <body> <h1>Demo</h1> <!--TMS--> <!--HTTP:http://trip.taobao.com/go/rgn/trip/act-818-preferential.php,gbk:HTTP--> <script> KISSY.use('h5-test/pages/search/index', function(S, Search) { new Search(); }); </script> </body> </html> • pages/search/index.html
构建 • copy - 拷贝文件至build目录 • kmc/kmb - 生成模块依赖关系表(map.js) •
combohtml - 合并请求与公用模块(mods) • uglify - 压缩JS代码 • cssmin - 压缩CSS代码 • replace - 替换版本号 $ grunt build
<!DOCTYPE html> <html lang="zh"> <head> <title>Demo</title> <meta charset="utf-8" /> <link
tag="combocss" href="http://g.tbcdn.cn/??trip/h5-test/0.1.22/widgets/ mpi_css/mpi-min.css,trip/h5-test/0.1.22/pages/search/index-min.css" rel="stylesheet" /> <script tag="combojs" src="http://g.tbcdn.cn/??trip/h5-test/0.1.22/widgets/ kissy/build/mini-all-min.js,trip/h5-test/0.1.22/widgets/jsbridge/index-min.js,trip/h5- test/0.1.22/widgets/mtop/index-min.js,trip/h5-test/0.1.22/config-min.js,trip/h5-test/ 0.1.22/map-min.js"></script> <meta name="pageid" content="on181.h5-test/pages/search/index.html"> </head> <body> <h1>Demo</h1> <!--TMS--> <!--HTTP:http://trip.taobao.com/go/rgn/trip/act-818-preferential.php,gbk:HTTP--> <script> KISSY.use('h5-test/pages/search/index', function(S, Search) { new Search(); }); </script> </body> </html> $ grunt build 构建可发布代码
代码发布 • grunt daily - 替换html资源host为日常 • grunt prepub -
发布日常/预发代码 • grunt publish - 压发布线上代码 g.tbcdn.cn -> g.assets.daily.taobao.net
页面发布 AWP管理平台
页面发布流程 1. 新建页面(填写页面信息) 2. 编辑页面(拷贝html内容) 3. 生成资源列表(监控资源变化) 4. 点击保存预览(检查是否有问题) 5.
提交发布单(性能验收) 6. 点击发布(正式上线)
页面发布流程 1. 新建页面(填写页面信息) 2. 编辑页面(拷贝html内容) 3. 生成资源列表(监控资源变化) 4. 点击保存预览(检查是否有问题) 5.
提交发布单(性能验收) 6. 点击发布(正式上线) 5-10 min/page
页面发布流程 1. 新建页面(填写页面信息) 2. 编辑页面(拷贝html内容) 3. 生成资源列表(监控资源变化) 4. 点击保存预览(检查是否有问题) 5.
提交发布单(性能验收) 6. 点击发布(正式上线) x10 老子要抓狂了!
awpp
awpp 一键发布, 爽!
ň∽ℛ䥥┮䷐猾㌈▀叞⇹◷厐㤐㊦⃮⛐⻲䥥ʼn 14:05 X
为什么 ‧网络速度慢 ‧手机性能差
去啊用户 旅行途中 (别说3G了, 2G网还灭了俩格)
https://speakerdeck.com/lijing00333/css-selector-performance
None
None
怎么做
怎么做 Everything you’ve learned still applies 学到的知识不会过时
https://speakerdeck.com/ningzbruc/mobile-h5-xing-neng-you-hua
客户端3.7性能优化 • 先展示框架 • 样式放在头部 • 脚本放在底部 • 合并/减少请求 •
异步加载脚本 • 删减冗余代码 • 优化图片质量 • 完善客户端缓存机制
None
None
None
None
旅行目的地页面 加载时间 0s 35s 70s 105s 140s 去哪儿iOS 旅行iOS 2
0.5 140 65 140 63 140 9 首屏框架展示 首屏功能可用 首屏全部展示 二次加载 WTF?
大部分客户端在onload之后展示页面 而请求阻塞onload事件
Get.loaded(getCombo([ 'trip/h5-fsticket/widgets/libs/juicer.js', 'trip/h5-fsticket/pages/search/tms.js' ]), function() { //渲染⻚页⾯面 window.TicketTMS.render(); }, !ksdebug,
null, 30); Hack 把所有请求放到onload事件之后
机智的少年
None
4s?
4s? faster?
4s? faster? how about 0.5s?
4s? faster? how about 0.5s? but why?
去啊用户 旅行途中 (别说3G了, 2G网还灭了俩格)
None
• 快速开发 • 冲量引流 • 多端适配 • 产品创新 • 速度慢
• 体验差 • 转化低 少年, 该醒醒了!
ň屢℩悲㉸㧕㋌猾屢℩㹜㉸㧕㋌猳ʼn 16:00
弱网无缝秒出 在追求极致用户的体验上,要么零分,要么满分!
如何实现秒出 • 后端渲染?(每次都需要发起请求) • OPOA?(首页无法秒出, 不便于统计) • 本地缓存+增量更新?(缓存容易被清掉) • AppCache?(功能不稳定,
bug多)
如何实现秒出 • 后端渲染?(每次都需要发起请求) • OPOA?(首页无法秒出, 不便于统计) • 本地缓存+增量更新?(缓存容易被清掉) • AppCache?(功能不稳定,
bug多) ✓ 离线包!!
如何实现离线包
如何实现离线包
放下偏见 我们需要更亲密地合作
高举Hybrid大旗 • 不是H5要挑战Native体验 • 而是Hybrid要挑战Native体验 • 借助Native的力量, 实现弱网无缝秒出 • Hybrid
!== Page + Webview + Bridge
None
离线包关键功能 • 预装载(发版时提前装载H5离线包) • 动态更新(离线包更新时可以静默推送至用户客户端) • 虚拟域(与线上页面保持一致, 方便数据获取与环境切换) • 桥的增强(充分利用Native的功能,
比如mtop请求) • TMS解析(正确解析页面中的TMS区块标签) • 埋点(客户端拦截)
None
<!DOCTYPE html> <html lang="zh"> <head> <title>Demo</title> <meta charset="utf-8" /> <!--Global
StyleSheets--> <link rel="stylesheet" href="../../widgets/mpi_css/mpi.css" /> <link rel="stylesheet" href="./index.css"/> <!--Global JavaScripts--> <script src="../../widgets/kissy/build/mini-all.js"></script> <script src="../../widgets/jsbridge/index.js"></script> <script src="../../widgets/mtop/index.js"></script> <script src="../../config.js"></script> <script src="../../map.js"></script> </head> <body> <h1>Demo</h1> <!--TMS--> <!--HTTP:http://trip.taobao.com/go/rgn/trip/act-818-preferential.php,gbk:HTTP--> <script> KISSY.use('h5-test/pages/search/index', function(S, Search) { new Search(); }); </script> </body> </html> • pages/search/index.html 离线包中如何处理
离线包TMS • 异步jsonp请求? • 如何插入HTML区块? • 如何解决代码依赖问题? • 如何做到同样的区块适用于线上与离线环境? •
如何插入第三方区块并且不阻塞业务流程?
tms-offline-parser 页面 代理区块 区块 包装内容
<!--HTTP:extra.php?async,gbk:HTTP--> <script id="tms_fragment_1">get_tms_fragment("http://proxy.php?src=extra.php", "gbk", "tms_fragment_1");</script> handle_tms_fragment(function() { /*<div>TMS内容</div>*/ }, 2);
function handle_tms_fragment(fn, id) { var content = getComment(fn.toString()); //<div>TMS内容</div> $('tms_fragment_' + id).replaceWith(content); } 异步TMS获取
<!--HTTP:data.php,gbk:HTTP--> <script src=“http://proxy.php?src=data.php&id=tms_fragment_1“></script> <tms id="tms_fragment_1"></tms> handle_tms_fragment(function() { /*<div>TMS内容</div>*/ }, 2);
function handle_tms_fragment(fn, id) { var content = getComment(fn.toString()); //<div>TMS内容</div> $('tms_fragment_' + id).replaceWith(content); } 同步TMS获取
<!--HTTP:data.php,gbk:HTTP--> <script src=“http://proxy.php?src=data.php&id=tms_fragment_1“></script> <tms id="tms_fragment_1"></tms> handle_tms_fragment(function() { /*<div>TMS内容</div>*/ }, 2);
function handle_tms_fragment(fn, id) { var content = getComment(fn.toString()); //<div>TMS内容</div> $('tms_fragment_' + id).replaceWith(content); } 同步TMS获取 保证依赖关系 阻塞页面渲染
万事俱备... 测试结果: 两秒的白屏...
<!DOCTYPE html> <html lang="zh"> <head> <title>Demo</title> <meta charset="utf-8" /> <!--Global
StyleSheets--> <link rel="stylesheet" href="../../widgets/mpi_css/mpi.css" /> <link rel="stylesheet" href="./index.css"/> <!--Global JavaScripts--> <script src="../../widgets/kissy/build/mini-all.js"></script> <script src="../../widgets/jsbridge/index.js"></script> <script src="../../widgets/mtop/index.js"></script> <script src="../../config.js"></script> <script src="../../map.js"></script> </head> <body> <h1>Demo</h1> <!--TMS--> <tms id="tms_fragment_1"></tms> <script src="http://proxy.php?src=data.php&id=tms_fragment_1"></script> <script> KISSY.use('h5-test/pages/search/index', function(S, Search) { new Search(); }); </script> </body> </html> • pages/search/index.html 即使是读取本地文件 客户端也存在IO性能 阻塞渲染
<!DOCTYPE html> <html lang="zh"> <head> <title>Demo</title> <meta charset="utf-8" /> <!--Global
StyleSheets--> <link rel="stylesheet" href="index_combo.css" /> <!--Global JavaScripts--> <script src="index_combo.js"></script> </head> <body> <h1>Demo</h1> <!--TMS--> <tms id="tms_fragment_1"></tms> <script src="http://proxy.php?src=data.php&id=tms_fragment_1"></script> <script> KISSY.use('h5-test/pages/search/index', function(S, Search) { new Search(); }); </script> </body> </html> 合并请求, 减少IO的消耗 • pages/search/index.html
合并请求... 测试结果: 一秒的白屏... (即使是把TMS去掉)
提示一下下
None
<!DOCTYPE html> <html lang="zh"> <head> <title>Demo</title> <meta charset="utf-8" /> <!--Global
StyleSheets--> <link rel="stylesheet" href="index_combo.css" /> </head> <body> <h1>Demo</h1> <!--TMS--> <tms id="tms_fragment_1"></tms> <script> MT.Get.rendered([ 'index_combo.js', 'http://proxy.php?src=data.php&id=tms_fragment_1' ], function() { KISSY.use('h5-test/pages/search/index', function(S, Search) { new Search(); }); }); </script> </body> </html> 页面渲染之后再发起请求
window.alitrip_render_finished_callback = function() { executeCallbacks(document, 'rendered'); }; • mpi/get/index.js 客户端通知更准确的渲染时间
延迟请求... 测试结果: 秒了!! 秒了!!
WHAT ABOUT THE CODE?!
None
离线包构建/调试 • grunt build_offline - 构建 • grunt offline -
本地调试
Demo
ň廆⑺❉㖆Ⅷʼn 17:00
None
工具, Hybrid, 性能
None
None
None
None
ň冩Ⅿ㖃┑㽺⚲Ⅷ猾㧪↡℩屢棏䥥⛸獑猳ʼn 18:00
THIS IS THE END