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
ningzbruc
February 01, 2016
Programming
210
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
63
阿里旅行去啊H5首页总结&Promise
ningzbruc
0
280
KISSY.Base - all about that Base
ningzbruc
0
140
Hammer.js
ningzbruc
1
360
淘宝旅行门票iPad版开发
ningzbruc
0
160
Travel on KISSY mini
ningzbruc
0
210
Events
ningzbruc
2
130
Why YUI3
ningzbruc
0
190
Other Decks in Programming
See All in Programming
Next.js: The final boss of Web Performance
guaca
0
370
AIが生成したコードは読むべきか?抽象化設計とコードの品質保証 / abstraction-design-and-quality
minodriven
12
7.8k
[Dev Group Paris Octobre 26] Agentforce, SIforce, Claudeforce, Slackbot… on s'y retrouve ?
nabondance
0
120
flutter_test のその先へ — Flutter アプリの LLM 機能に「評価」という品質保証を
kosukesaigusa
0
150
そのデザイントークン、Flutterでも同じ見た目になりますか?
nakamizu
0
140
パスワード再設定メールのURLについて知っておこう
uyuki234
0
200
AI時代のシニアエンジニアとは
yosuke_furukawa
PRO
13
11k
Vue.jsで作る空間解析アプリとCapacitorプラグインのData Bridge
hal_spidernight
1
140
Spec-driven Development with AI
simas
PRO
0
2.2k
社内AIエージェント「Askワンバン」における コストチューニングの取り組み
t0yohei
0
120
Materialが消えた日 〜真っ白なFlutterキャンバスにRenderObjectで絵を描く〜
umigishiaoi
0
120
React Native에 현대적인 빌드 도구 더하기: Rollipop 구현기
leegeunhyeok
0
170
Featured
See All Featured
Kristin Tynski - Automating Marketing Tasks With AI
techseoconnect
PRO
0
570
New Earth Scene 8
popppiees
4
2.7k
What does AI have to do with Human Rights?
axbom
PRO
1
2.5k
Designing for Timeless Needs
cassininazir
1
540
What the history of the web can teach us about the future of AI
inesmontani
PRO
2
770
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
390
HDC tutorial
michielstock
2
990
ラッコキーワード サービス紹介資料
rakko
5
5.6M
Agile that works and the tools we love
rasmusluckow
331
22k
Ruling the World: When Life Gets Gamed
codingconduct
0
430
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.9k
Information Architects: The Missing Link in Design Systems
soysaucechin
1
1.2k
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