2017年WEB开发知识分享会议

作者:纵横
链接:https://www.zhihu.com/question/64300184/answer/231367777
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

什么做分享的大佬回答了我还要出来回答呢:因为大佬们讲的太好了!

听完之后觉得应该写下来,不然以后就忘了。


上午场

0x0000

腾讯副总Rose在conf开始之前发表了开幕词,回顾了他的光荣历史。2003年是Windows客户端的天下(电脑版QQ)。2005年Web开始发力(QQ空间、QQ邮箱),性能优化这些问题开始受到重视。2009年达到巅峰,前端团队规模达到几十人。2012年,随着APP的兴起,Web日渐衰落。但是在今天Web仍有立足之地,敏捷开发、混合开发、H5,形成了一股新热潮。

感觉低头走路的时候也要抬头看看,时代在进步,变亦变,不变亦变。在最后的时候一位导师说的话挺让人有感触:你们首先是工程师,然后才是前端工程师。

0x0001

第一场是W3C交互技术负责人Philippe分享的《Now and the Future》。这位大佬一口纯正的英国口音,表示理解无能,只能看着PPT勉强理解一下了。Philippe回顾了W3C历史上的丰功伟绩。还顺便科普了一下草案的制定过程,听得半懂:

  • Working Draft(打算推进)
  • Candidate Recommendation(收集资料)
  • Proposed Recommendation(定稿)
  • W3C Recommendation(大家认可)

之后Philippe从几个方面,讲了一下现在(已经被支持)及未来的发展方向。我印象比较深的是渲染、安全、媒体、通信还有新应用这些。

  • 性能:
    • requestAnimateFrame(帧级别的定时器)
    • will-change(CSS动画的预加载)
    • Web assembly(前端使用汇编)
    • 生命周期(参见vue等)
  • 安全:
    • refer(预防csrf)
    • httpOnly(预防XSS)
    • authorization(存放身份信息)
    • secure content(不太懂)
  • 通信
    • service worker(后面有PWA讲到了,感觉是个代理)
    • 消息推送(服务端主动推送消息)
  • 应用
    • VR、AR等

Philippe还鼓励在座的大佬们共同参与W3C的制定,并给出了github地址

在提问中有一个很有意思的问题:前端发展越来越快,W3C会不会跟不上前端界的发展。Philippe老爷子很自信的回答:不会的,浏览器厂商一直在抱怨我们的标准制定的太快了,他们来不及实现。年轻人,先有标准,才有浏览器实现。

0x0002

说实话,我觉得Michael Yeung的分享《PWA与AWP》带给我的收获最大,可惜忘记给大佬点赞了。

大佬一上来就指出了前端发展的几个问题:

  • APP的使用量远远大于Web
  • 用户在top3的APP上花了80%的时间(28定律)
  • 世界目前APP的月均每人下载量为0

这样一来Web不是没救了。不甘寂寞的前端程序员提出了AMP。AMP是一种规范,用来提高网页加载速度,想要给用户带来和原生APP一样的体验。

他的原理其实就是通过约束程序员随意的代码,牺牲少部分功能,提高加载速度。AMP必须遵守下面几条规范:

  • 使用图片、视频资源,必须指定长宽,防止回流(重新渲染)造成的卡顿
  • 不允许使用同步JS
  • 不允许在页面直接引用第三方JS(可以封装组件)
  • 只允许内联CSS

然后,大佬介绍了AMP的进阶版PWA。PWA比他的老爸更像原生APP。想要具有原生APP的以下特点:

  • 可靠(断网也能加载出来)
  • 快速(一次下载就能飞起来)
  • 吸引(和原生一样丰富的API,大佬说这个目前有点虚)

要有这些功能该怎么办呢,只能由浏览器放权,提供接口给Web。其实个人理解小程序或许就是一个PWA(提供了大量接口的Web)。当前浏览器(safari不支持)提供的接口有:

  • 独立的任务详情页
  • 本地快捷图标
  • 资源存储可控

前两个是浏览器提供的,和开发者没什么关系。所以详细讲了前端开发者如何控制资源的缓存和请求。这里主要用到的是service worker。service worker其实是一个用JS代码实现的代理层。web要请求html、css、图片资源的时候,都要经过service worker的代理。

  • service worker拦截到请求的时候,也可以选择从本地获取缓存,如果有就返回给web。(又快又可靠,可惜不是最新的)
  • service worker拦截到请求的时候,可以选择先从internet上获取,如果获取不到就读取本地缓存,返回给web。(又新又快又可靠)

大佬为了让台下的小白能快速上手,贴心的讲解了一下service worker的生命周期。register的时候加载所要执行的js,install的时候缓存本地资源,active的时候实现代理逻辑(可以先读本地,也可以先读remote)。

Show me the code!首先要先判断浏览器是否支持service worker。如果支持的话就可以执行某个js文件了。

if (navigator.serviceWorker) {
    navigator.serviceWorker.register('worker.js').then(function(registration) {
        console.log('regist success');
    }).catch(function (err) {
        console.log('regist error')
    });
}

接着在worker文件里定义install,缓存需要存储的文件。

var cacheFiles = [
    'index.html'
];
self.addEventListener('install', function (evt) {
    evt.waitUntil(
        caches.open('my-test-cahce-v1').then(function (cache) {
            return cache.addAll(cacheFiles);
        })
    );
});

这时候断开网络,打开页面,发现还是显示了404,这是因为我们没有拦截fetch请求。

self.addEventListener('fetch', function (evt) {
    evt.respondWith(
        caches.match(evt.request).then(function(response) {
            if (response) {
                return response;
            }
            var request = evt.request.clone();
            return fetch(request).then(function (response) {
                if (!response && response.status !== 200 && !response.headers.get('Content-type').match(/image/)) {
                    return response;
                }
                var responseClone = response.clone();
                caches.open('my-test-cache-v1').then(function (cache) {
                    cache.put(evt.request, responseClone);
                });
                return response;
            });
        })
    )
});

这样就大功告成了。在用户第二次打开页面的时候,service worker就会直接代理请求,加载缓存在本地的文件了。

这里有观众提问:这样实现和long cache有什么区别呢?Michael 的原话我记不太清了。大意是,这种实现方式是浏览器放权的一种思想,将资源加载完全交由开发者处理。

0x0003

Limin zhu大佬带来的是《Typescript》(这位大佬最终成了本期最佳讲师)。Z老师安利的确实很棒,之前也有很多人推荐过ts,如今下定决心用一用了。

Z老师一上来就指出了前端开发的苦逼现状,70%时间在读代码,25%时间在改bug,5%时间在写需求。作为一个大四的百度实习生,表示真的很对啊,真的很想去做新需求啊!Z老师一波安利,使用了ts和vscode可以让我们65%的时间在读代码,20%的时间在改bug,15%的时间在写需求。还是相当的诱人的。

如何快速上手ts,Z老师的给出了一个从未见过、及其方便的方案。首先你要有一个vscode,换编辑器吧,骚年。然后你只需要在头部注释@ts-check 就可以对全文进行检验了,你在编码的时候编辑器就会提示你可能出现的错误。注意,类型的注释格式必须和下面代码一样。

// @ts-check

/**
 *  @type {number}
 */

let test = 'hello world'
//提示:[js] Type '"hello world"' is not assignable to type 'number'.

大佬还演示了如何使用typescript工具编译ts文件为javascript 。直接上代码吧,首先要安装typescript。

npm install -g typescript

我这里就使用官网的示例文件了,你也可以自己编写一个ts文件。

// 注意看person后面的string类型声明
function greeter(person: string) {
    return "Hello, " + person;
}

var user = "Jane User";

document.body.innerHTML = greeter(user);

然后运行编译就可以咯,很简单。

tsc greeter.ts

当然,实际项目中我们不可能这样使用,通常我们会结合webpack打造一个自动化的工作流。使用ts-loader就可以咯。当然还可以辅助sourcemap这些工具进行调试。

module: {
    loaders: [
      { test: /.ts$/, loader: 'ts-loader' }
    ]
  }

大佬还演示了如何在react项目中使用ts,这里我就不再粘贴代码过来了,我对比了一下大佬的代码,发现好像就是这个github的。

0x0004

喵喵喵?这个大佬在说啥。狂记了一波笔记,回来了解一下再写。

上午过得还是挺快的,进门就领了牌子、衣服、本子、笔。会场挺大的,坐在前面看的很清楚。总的来说举办的真不错。不过一天下来真的困的要死啊,程序员为何要为难程序员呢。明天再来接着写吧。

下午场

0x0000

听完上午大牛的分享,就跑去楼下吃午餐。主办安排的时间太紧凑了,吃完就又跑回分会场,准备听下午的分享。下午分成了三个分会场,Node.js、框架性能、综合会场。其实还是挺想听Node.js的,但是感觉框架性能分会场的比较适合我的业务场景,所以还是去了框架性能分会场。

0x0001

百度外卖的林溪大佬为我们带来的是《Tree-Shaking》。

什么是tree shaking呢。直接翻译过来应该是摇树。把树上枯萎的叶子、果子摇下来,树就会变得更美观、更容易把养料用在该用的地方。tree shaking就是摇代码这棵树,在编码完成后,去掉没有用的代码。

tree shaking有什么意义呢:

  • 减少网络传输的体积
  • 提高加载速度
  • 减小代码包

目前有三种tree shaking的工具:

  • roll up(开山)
  • webpack(uglify支持)
  • closure compiler(配置比较复杂)

tree shaking的原理是这样的:

  • 消除Dead code(不会执行或者结果不会用到)
  • 消除无用模块

消除无用模块是基于ES6来说的,由于ES6模块具有以下特征,所以可以在静态检验的时候就可以确定依赖,消除不需要引用的部分。

  • 只能在顶层作用域出现(一般写在最前面)
  • 名称只能是常量不可更改

这里大佬特别指出,对于那些函数式编程的库,消除模块的作用比较明显。因为函数式编程可以规避动态访问,tree shaking可以放心的去掉静态检验中没有引用的函数。

这里我按照大佬的讲解配置了一下webpack.config.js

new webpack.optimize.UglifyJsPlugin({
      beautify: false,
      comments: false,
      compress: {
        warnings: false,
        drop_console: true,
        collapse_vars: true,
        reduce_vars: true
      }
})

如果你使用了antd大佬还给你提供了babel-plugin-import-fix

import {Button} from 'antd';

主要实现的功能就是把上面的内容变成下面的。

import {Button} from 'antd/lib/button';
import 'antd/lib/button/style'

不仅js可以tree shaking,css也可以。大佬好像是基于postcss的解析做的。根据大佬所说,他只对class和id做了tree shaking,而没有动伪类等等。其实个人感觉,有的时候我也会拼接class,这样来看应该是会有副作用报错的吧。下载插件后这样使用。

var ExtractTextPlugin = require('extract-text-webpack-plugin')
const CssTreeShakingPlugin = require("webpack-css-treeshaking-plugin")

module.exports = {
  plugins: [
    new CssTreeShakingPlugin({
      remove: false,
      ignore: ['state-d']
    }),
    new ExtractTextPlugin({
      filename: 'build/style.css'
    })
  ]
};

大佬最后总结了一波他的探索过程,大佬在对比结果的时候使用的工具很有意思,大家可以从这里下载,在每次打包之后可以分析各个文件大小,绘制出交互图像。

最后,要保证tree shaking的效果,请遵循以下两点建议:

  • 使用eslint做检查
  • 函数式编程
最后有一个大佬提问:我们也在做tree-shaking,发现对于有些库效果不明显,只能减少10+kb,应该怎样处理。回答是这样的:tree-shaking现在还处于实践阶段,但是总有一天我们可以消除无用的代码。(膜)

0x0002

徐杰大佬讲解的是《RN在QQ空间中的应用》。其实这几天React真的很不太平,先是Wordpress改版成React,然后React又不给用了。接着百度内部全面剔除React。想着听听算了,不过徐杰大佬应该是架构师这一层面的吧,给出了很多自己的考虑和思路,大团队使用RN的考虑还是很让人耳目一新的。

徐杰大佬主要讲的是一个在手Q中(ios)的页面。一上来大佬就先分析了在用RN改版前的加载耗时情况:

  • Webview启动耗时(最多,然而H5不可控)
  • 请求资源耗时
  • 页面渲染耗时

为了突破webview耗时过多的瓶颈,才把H5重构成RN的。据说每多等一秒,就有很多转化率流失。(说服产品的好理由啊,彰显前端价值)。

然而使用RN也有以下的顾虑:

  • 性能
  • 可靠性(红屏)
  • 组件化(可复用)

最后大佬提出了两种解决思路:

  • 业务拆包
    • base bundle一并下发
    • task bundle按需下发
  • 降级方案
    • 默认使用RN方案(成功率有96%,其余好像都是网络环境的原因失败)
    • 如果失败使用H5降级方案(这里需要原生同学帮忙)
效率问题是所有前端开发者注重的大问题。为了提高加载速度,不断折腾,或许是前端最有趣的事情之一吧。

0x0003

王跃大佬带来的是《小程序核心架构剖析》。同行的小伙伴本来是不想听的,结果听了之后的评价是:这是本次conf干货最多的一个分享(他好像也没来的及投票)。

根据大佬的解说,初步了解了小程序的盛况,腾讯内部有100+小程序,外部有?(这里保密了)个小程序,小程序的入口就有50多个(应该是算上了各种卡片、推送等等的吧)。接着大佬分享了对小程序的分析。

小程序编译后的静态文件分为以下几部分:

  • WAService(逻辑)
  • WAWebview(视图)
  • WAConsole(调试)
  • app-config(所有配置项,包括一些默认的)
  • app-service(全局逻辑,包括global这些)
  • page_frame.html(模板)
  • pages(css样式)

他们是这样编译来的:

  • WXML ==> page_frame
  • WXSS ==> page
  • js ==> WXService
  • json ==> app-config

在运行时,小程序开了2两个webview(感觉像是两个线程),他们之间的通信通过jsBridge传递到native,再由native传递回jsBridge。主要的传递方法我就记住了webkit上的postmessage和addEventlist。

WAwebview主要以webkit为内核,主要跑了以下文件:

  • WAWebview.js
  • page-frame.html
  • page

WAwebview主要提供了以下服务:(感觉就是react的作用)

  • component
  • API(主要是给component调用的)
  • render
  • event
  • jsBridge
  • reporter

WAservice在PC上是webkit内核,在ios上是JScore内核,在android上是V8内核,这样做的目的是精简内核,毕竟webkit里有很多用不到的东西。而PC主要用于调试,选之前的技术栈就可以了。主要跑了以下文件:

  • WAservice.js
  • app-config.js
  • app-service.js

WAservice主要提供了以下服务:(感觉就是redux的作用)

  • API(全局)
  • module
  • global
  • reporter

接着大佬根据原理,讲解了一些小技巧:

  • page:一般不超过5个,超过后小程序就会自动复用
  • size: 一般不超过2M
  • Dom: 一般不超过16000
  • Data: 会占用内存,数据传输jsBridge会耗时,只要setData自己有用的资源就可以了
  • 动画:可以用css3解决
  • 请求:小程序使用的是service worker
  • 渲染:diff算法
  • 预加载优化
    • 小程序会在打开一个页面的时候,先加载下一个页面的page_frame,加载时会自动拷贝page对象,因此,我们可以提前在page对象里注入数据。
    • 开发者可以自己预测用户可能会点击的下一个页面,并将数值缓存到localstorage
    • 对媒体资源如图片等设定长宽,防止reflow的时候画面闪动(AMP)

 

良心之作,会后给大佬微信,没想到大佬居然回我了,终于找到了小程序源码。原来大佬是android翻的文件,双击666。难怪我在PC上硬是没找到编译后的文件,不知道拦截上传行不行。

0x0004

林子杰大佬分享的是《页面性能体系的评估》,这位大佬很像我的一个师兄,好年轻啊。

大佬首先推荐了scrat框架,包含了脚手架、测试等很多功能。接着,大佬演示了如何使用scrat和UC浏览器进行性能优化。在例子中主要用的技巧是:

  • require.sync
  • settimeout(balabala,0)

那么性能测试应该包含哪些维度呢:

  • 谷歌浏览器
    • FP 首次绘制时间
    • FMP 关键内容绘制时间(这个比较难以测量)
    • TTI 可交互时间(所有都加载完,用户可以点击)
  • UC浏览器
    • responsetime T0 (服务器返回)
    • 首次绘制内容 T1 (有东西显示)
    • 绘制满屏内容 T2 (html和css完成)
    • 加载完所有资源 T3 (图片和媒体资源)

根据页面种类不同,所需要重视的维度也有所不同:

  • 营销游戏:T3、FPS(流畅度)
  • Feed流: T1、T2
  • 长列表: T1、T2、FPS

根据网络环境不同,对指标的要求也有所不同:

  • WIFI环境
    • 普通页面在1000ms之内
    • 视频等富媒体页面在2000ms之内
  • 2G/3G/4G(由于网络环境不稳定,一般看比例)
    • 1s占比
    • 2s占比
    • 3s占比

性能优化后如何进行调试:

  • 线下
    • 真机调试
    • 内核工具
    • 测试平台
  • 线上
    • API
window.chrome.loadTimes() //谷歌

几种常见的优化方法:

  • 优化图片占比
  • 优化总体size
  • T1/T2分析
    • 可以将部分T1资源后置到T2
    • 可以考虑localstorage是否合适
  • JS耗时分析(断点调试长耗时算法)
  • 排版渲染(防止回流等)
  • 提高缓存命中概率
以前没注意到还有这么多接口可以查看统计数据,UC浏览器的接口好像比chrome多封装了一些,有空用用看。有个嘉宾提问:UC封装了这么多统计接口,会不会影响页面加载?回答:不会的,可以切换实验环境和实际环境。

0x0006

好了,到这里就基本结束了。中间的茶点和充电宝很棒。很感谢IMWeb提供了这个机会,让我们向大佬们学习。建议你明年一起去咯~说不定还能见面呢,一起学习。能力有限,记得不多(也不一定准),不好意思了。

原文地址:https://www.cnblogs.com/msb-/p/10876488.html