ZooTeam-前端周刊|第-54-期

政采云前端小报第54期浏览更多往期小报,请访问: https://weekly.zoo.team ES6、ES7、ES8、ES9、ES10新特性一览 掌握不断更新的ES新特性从程序媛角度去看项目管理 | Aotu.io「凹凸实验室」 项目管理一般是从技术负责人、项目产品负责人的角度去看的,程序员虽然码代码很重要,但对项目的领悟能力也同样重要。我们经常会遇到各种困惑:手上的项目需求越来越多,BUG列表只增不减,该采取怎样的措施,保证自己的生产力?希望以下的讲述带给你莫名的认同感,或多或少让你磨刀霍霍一试。 需求管理下图描述的是程序员从接到需求到开发环节的过程: 一般我们首先会收到产品的PRD或交互稿,被询问今天什么时间点是...我不想成为不懂 GUI 的 UI 开发者 - 掘金 作为一个程序员,我是从切图开始职业生涯的。行业内一般把我这种编写用户界面 (UI) 的岗位,叫做前端开发。工作几年后我发现了个奇怪的现象,那就是整个前端圈子里,虽然大家常常谈 UI,但很少有人谈 GUI。 这话要从何说起呢?前端圈子里从上游到下游,强调的都是...技术栈:为什么 Node 是前端团队的核心技术栈 小菜前端的基建在一步步走过来的过程中,NodeJS 是如何使用的及扮演了哪些角色,它对于工程师个人,团队能力,公司研发效率,业务支撑,技术的探索与突破等等到底有什么实际的意义...从“愚昧之巅”到“绝望之谷”,讲讲我价值几千万的认知 不要缝合自己的脑洞,打开,打开,重新打开自己的逻辑闭环。当前端遇到机器学习?听 TensorFlow.js 负责人怎么说 第十四届 D2 前端技术论坛将于12月14日拉开帷幕,其中, Google TensorFlow.js 团队的负责人 Ping Yu 将作为「智能化」专场的嘉宾,为我们讲解 TensorFlow.js 生态系统,以及如何将现有的机器学习模型植入到前端。网站性能优化实战——从12.67s到1.06s的故事 - 腾讯Web前端 IMWeb 团队社区 | blog | 团队博客 Web前端 腾讯IMWeb 团队社区再谈javascriptjs原型与原型链及继承相关问题 - 腾讯Web前端 IMWeb 团队社区 | blog | 团队博客 Web前端 腾讯IMWeb 团队社区React Concurrent 模式抢先预览上篇: Suspense the world - 掘金 ...

November 2, 2019 · 1 min · jiezi

译Web内容如何影响电池的使用

原文地址:https://webkit.org/blog/8970/...原文作者:Benjamin Poulain & Simon Fraser译者:刘辉 校验:李刚松现在用户上网大多使用移动设备或者笔记本电脑。对这两者来说,电池寿命都很重要。在这篇文章里,我们将讨论影响电池寿命的因素,以及作为一个web开发者,我们如何让网页耗电更少,以便用户有更多时间来关注我们的内容。 是什么在耗电?移动设备的电力消耗有以下几个因素: CPU (核心处理器)GPU (图形处理)网络 (wifi或者蜂窝移动网络)屏幕屏幕功耗相对稳定,并且主要由用户控制(通过屏幕使用时间和亮度),但是对于其他组件,例如CPU,GPU,网络模块,功耗是动态变化的,而且变化范围很大。<!--more-->系统根据当前正在处理的任务调整CPU和GPU性能,包括在Web浏览器中用户正在交互的网页以及使用Web内容的其他应用程序。这是通过打开或关闭某些组件以及通过更改其时钟频率来完成的。总的来说,芯片所需的性能越高,其功率效率就越低。硬件可以非常快速地提升到高性能(但是需要很大的功率),然后迅速恢复到更高效的低功耗状态。 良好用电的一般原则为了最大限度地延长电池寿命,你必须尽量减少硬件处于高功率状态的时间,让硬件尽可能的处于空闲状态。 对于web开发者来说,有三种交互场景需要注意: 用户主动与内容交互页面处于前台,但是用户没有交互页面处于后台高效的用户交互用户交互的时候肯定会耗电。页面需要快速的加载,并且能够快速的响应触摸。在大多数场景中,减少首次渲染时间也会降低功耗。不过,在初始页面加载后继续加载资源和运行脚本时要小心。我们要尽快让系统返回空闲状态。总的来说,浏览器已经完成了布局和渲染,js执行的越少,耗电越少。 一旦页面加载完,用户可能会滚屏或者点击页面,这同样会产生耗电(主要是CPU和GPU),这是必要的消耗。要确保尽快返回空闲状态。并且,最好使用浏览器本身提供的功能。- 举例:普通的页面滚动肯定比用js自定义的滚动更高效。 让空闲状态耗电趋向于零当用户没有和页面交互时,尽可能的使页面不耗电,例如: 尽量少用定时器以避免唤醒CPU,可以把基于定时器的任务合并,使用尽可能少的定时器。大量滥用定时器会导致CPU被频繁唤醒,这比把这些任务合并处理要糟糕的多。最大限度地减少动画内容,如动画图像和自动播放视频。要特别注意"loading"用的gif图片或css动画,这些动画会不断触发渲染,即使看不到也会触发。IntersectionObserver可以用来在可见时才运行动画。尽量用css做动画和过渡,这些动画不可见时,浏览器会进行优化,并且css动画比js动画要高效的多。避免通过轮询来获取服务器更新,可以用websocket或者持久连接来代替轮询。看起来处于空闲状态的页面,如果正在后台进行工作,其用户交互的响应效率也会降低,因此最小化后台活动也可以提高响应能力以及电池寿命。 页面在后台时CPU零使用这几种场景时,页面变为非活动状态(不是用户的首要焦点),例如: 用户切换到其他tab用户切换到其他app浏览器窗口最小化浏览器窗口失去焦点浏览器窗口在其他窗口后面窗口所在的空间不是当前空间(MacOS才有空间的概念)当页面不活动时,webkit会自动做以下处理来减少耗电: 停止调用requestAnimationFrameCSS和SVG动画会暂停定时器会节流此外,WebKit利用操作系统提供的能力来最大限度地提高效率: 在iOS上,不用的选项卡(tab页)会完全暂停。在macOS上,选项卡会响应App Nap功能,这意味着不可视更新的选项卡的Web进程优先级较低,并且其计时器会做节流处理。但是,页面可以通过计时器(setTimeout和setInterval),消息,网络事件等触发CPU唤醒。页面在后台时应避免这些唤醒,有两个API对此有用: 页面可见性API提供了一种响应页面转换为后台或前台的方法。这是一种避免页面在后台时更新UI的好方法。用visibilitychange事件,在页面可见时更新页面内容。页面失去焦点时会发出blur事件。这时,页面依然可见,但是不是聚焦窗口。可以考虑暂停动画。查找问题最简单的方式就是用浏览器控制台的时间线功能。页面在后台时,时间线记录中不应该有任何事件发生。 找到问题所在现在我们知道了web页面主要的耗电因素,并且给出了一些创建高效页面的一般规则。 接下来讨论一下怎样找出并解决导致功耗过大的问题。 脚本如上所述,现代CPU能够把功率从空闲态的非常低提升到非常高来满足用户交互和其他任务的要求。 也正因为如此,CPU是导致电池寿命减少的主要原因。页面加载期间CPU要做一连串工作包括加载、解析、渲染资源,并且执行js。在大多数现代web页面上,执行js花费的时间远远高出浏览器用在其余加载过程中花费的时间。因为尽量减少js执行时间对省电有最大的效益。 测量CPU使用的最佳方法是使用Web Inspector,就像之前文章里所说的,时间线面板可以显示任意选定时间范围内的CPU活动。 为了高效地使用CPU,WebKit尽可能在多核上分配工作(使用Workers的页面也可以使用多核)。Web Inspector提供与页面主线程同时运行的线程的细分图表。例如,以下屏幕截图显示了滚动具有复杂渲染和视频播放的页面时的线程: 在寻找优化点时,应关注主线程,因为js运行在主线程上(除非您正在使用Workers)。我们可以使用时间线面板的 “JavaScript and Events” 项来了解触发脚本的内容。也许你在响应用户或滚动事件或从requestAnimationFrame触发隐藏元素的更新时做了太多工作。你需要了解你在页面上使用的JavaScript库和第三方脚本所做的工作。如果要深入挖掘,你可以使用Web Inspector的JavaScript profiler来查看时间都用在哪些地方。 “WebKit线程”中的活动主要由与JavaScript相关的工作触发:JIT编译和垃圾收集。因此减少运行的脚本数量并减少短生命周期的JavaScript对象可以降低webkit线程的活动。 WebKit调用的各种其他系统框架都使用线程,“Other thread” 包括了这些工作; “Other thread” 最主要的工作是渲染,我们将在下面讨论。 渲染主线程CPU使用也可以通过大量布局和绘制来触发;这些通常由脚本触发,但是除了transform,opacity和filter之外的属性的CSS动画也可以触发它们。查看时间线面板的 “Layout and Rendering” 项将帮助你了解导致活动的原因。 如果 “Layout and Rendering” 显示的渲染过程不能清楚展示页面正在发生什么变化,可以启用 Paint Flashing: 这部分渲染将用红色背景的高亮显示,你可以滚动页面查看。注意,WebKit会保留一些“透视”图块以允许平滑滚动,因此视口中不可见的图形仍然可以正常工作以使屏幕外图块保持最新。如果渲染展示在时间轴中,说明它正在工作。 除了导致CPU耗电外,渲染通常还会触发GPU工作。macOS和iOS上的WebKit使用GPU进行渲染,因此触发渲染可以显着增加耗电。额外的CPU使用通常显示在时间线面板 “CPU” 项中的 “Other threads” 下。 ...

October 8, 2019 · 1 min · jiezi

Vue项目构建持续集成阿里云CDN

CDN加速是Web应用性能优化和用户体验提升的至关重要的一环,当一个项目构建部署时,就需要考虑到如何高效的去完成相关资源的CDN部署。本文以一个基于 vue-cli3 构建的项目实例,来简单讲解如何配合Teamcity,自动进行阿里云CDN资源部署和持续集成。项目构建vue-cli3 默认支持将项目以 test、development、production 三种模式构建,其中 production 模式将在 build 后生成 dist目录。我们在项目路径下插入 .env.[mode] 格式的文件就可以实现自定义模式。通常,默认的构建模式无法满足项目研发需求。一个项目至少需要包含本地调试 - 即开发过程中的 development 模式,不生成 dist 静态目录,使用 vue-dev-server运行项目;测试环境 - 即基本的集成测试,需要文件静态化,部署到测试环境;线上环境 - 即用户环境,也需要文件静态化,并做CDN加速等性能优化措施;按照这个模型,我们需要自定义一个 deploy 模式,来实现和普通 production打包后,资源引入路径的区别。首先,环境创建在项目根目录下创建 .env.deploy 文件,添加内容如下:NODE_ENV=productionDEPLOY=onlineNODE_ENV的设置代表webpack构建时使用production模式,即会生成 dist静态目录。DEPLOY的设置,是一个我们定义的变量,用于在配置中区分deploy和production模式。其次,配置文件在 vue.config.js 中,配置 BASE_URL// 根据自定义的变量来进行内容设置let BASE_URL = ‘/‘switch(process.env.DEPLOY) { case ‘online’: BASE_URL = ‘http://web-cdn.xxx.com/' break default: BASE_URL = ‘/’}module.exports = { publicPath: BASE_URL, ….}该配置会使得当程序使用 deploy 模式运行时,打包的资源根路径为我们的CDN地址。最后,构建命令在 package.json 中,配置使用 deploy 模式的打包命令"scripts": { “build”: “vue-cli-service build”, “deploy”: “vue-cli-service build –mode deploy”, …}当用户执行 npm run build 时,会生成以 / 为资源路径的文件;当用户执行 npm run deploy 时,生成 index.html 中的资源路径就变成了我们配置的CDN路径。<!DOCTYPE html><html> <head> <meta charset=utf-8> <meta http-equiv=X-UA-Compatible content=“IE=edge”> <meta name=viewport content=“width=device-width,initial-scale=1”> <link rel=icon href=http://web-cdn.xxx.com/favicon.ico> <title>Demo</title> <link href=http://web-cdn.xxx.com/css/chunk-0fabbc4c.08fa0fd2.css rel=prefetch> <link href=http://web-cdn.xxx.com/css/chunk-1025f268.0dc416de.css rel=prefetch> <link href=http://web-cdn.xxx.com/js/app.84dcc9e6.js rel=preload as=script> </head> <body> <div id=app></div> <script src=http://web-cdn.xxx.com/js/chunk-vendors.614ecc0c.js></script> <script src=http://web-cdn.xxx.com/js/app.84dcc9e6.js></script> </body></html>阿里云CDN配置和上传接下来,我们要做的就是配置一个CDN,并能够把这些资源传上去。首先,在阿里云上配置CDN,做好域名CNAME解析,并获取到阿里云的 accessKeyId、accessKeySecret、Region、BucketName等信息,然后选择一种语言,写好上传脚本。这里我们以Node脚本为例:// oss-deploy.jslet OSS = require(‘ali-oss’)let fs = require(‘fs’)let client = new OSS({ region: ‘oss-cn-hangzhou’, accessKeyId: ‘xxx’, accessKeySecret: ‘xxx’, bucket: ‘xxx’})// 使用async+await方法,实现同步化,方便在失败后重试处理async function put(fileName) { try { let result = await client.put(fileName, ‘../dist/’ + fileName) console.log(‘File Upload Success: ‘, fileName) } catch (e) { console.log(‘File Upload Failed: ‘, fileName) // 这里省略异常/失败的重试 }}// 读取打包后的 dist 路径,按照原文件夹结构,进行上传let readFileList = (path, filesList) => { let files = fs.readdirSync(path) files.forEach(itm => { if (itm) { let stat = fs.statSync(path + itm) if (stat.isDirectory()) { readFileList(path + itm + ‘/’, filesList) } else { filesList.push(path + itm) } } }) return filesList}let dist = readFileList(’../dist/’, [])// 递归执行文件上传操作let i = 0, l = dist.lengthlet uploadAsset = () => { if (i < l) { let name = dist[i].split(’../dist/’)[1] put(name) i++ uploadAsset() }}uploadAsset()执行npm install –save-dev ali-ossnode oss-deploy.js即可看到文件已经被上传到了CDN路径下。持续集成上面的两个模块,已经实现了基本的CDN部署。但我们在项目开发的时候,肯定不希望每次 build完,都去自己执行上传CDN,再去服务器上部署。这里我们再把 TeamCity上实现自动build、一键上线的流程简单阐述。TeamCity上的执行脚本如下:cd /apps/kaleido-cms/git pull -f origin masternpm installnpm run deploygit add dist/*git commit -m “Deploy"git push origin mastercd /apps/kaleido-cms/deploynode oss-deploy.jsssh root@10.0.0.1 “./deploy_cms.sh"ssh root@10.0.0.2 “./deploy_cms.sh"因为线上服务通常是集群模式,而 webpack在不同服务器执行build,会产生不同的哈希值版本号,会导致远程资源无法获取到。所以我们需要在持续集成部署的服务器上做build操作,生成dist路径,上传到git和cdn。最后再到集群的每个服务器上拉取静态文件即可。补充:在同一台服务器上,只要文件完全不变,我们使用vue-cli3构建生成的最终文件的哈希值版本号就不会产生改变。因此,对于用户来说当我们更新版本时,并不会对用户造成所有缓存文件失效的性能和体验影响。在阿里云的CDN上,是使用协商缓存的ETag来进行文件资源缓存,因此重名新文件覆盖旧文件时,如文件内容完全一致,Etag也会保持一致,对用户来讲也不必担心缓存问题;如文件发生变更,用户协商缓存也将无法命中,就会取新的资源文件。有些方法是把静态资源的请求发到Nginx,然后再转发到CDN地址。笔者认为,这样会造成所有资源需要重定向、并且在Nginx上无法设置缓存信息,性能上不如本文介绍的直接构建生成CDN地址的HTML文件的方法。通过这套操作,最终我们实现了在TeamCity上,一键执行打包、上传CDN、部署的整个流程。 ...

April 18, 2019 · 2 min · jiezi

Web应用性能优化随笔

优化思路是什么?BIG QUESTION: 当我们谈到一个web应用的性能优化,应该从哪些方面去考虑?思路就是,当我们去访问一个web应用的时候,都做了哪些操作?对应这些操作的,就是我们所能进行的优化的模块!浏览器请求DNS服务器,获取IP地址;建立TCP连接;浏览器发出详细请求,通常为HTTP(s)、WebSocket之类;服务器响应请求,并返回数据;浏览器渲染返回的数据到页面;释放TCP连接;那么,我们接下来就按照这个流程,一步一步来看如何进行优化。不好控制和不重要的优化内容1. DNS首先,DNS查询的流程如下图所示当有浏览器缓存时,就不会去查询之后的步骤,有无缓存的对比如下图可以看到,DNS Lookup这一步,在有缓存之后就不会出现。2. TCP连接建立同样如上图所示,Initial Connection 所占用的时间即为TCP建立连接的耗时。由于TCP建立需要3次握手的操作,使其成为HTTP(s)协议通信耗时最长的过程。针对这个过程,我们可以使用HTTP Keep-Alive机制,来保持TCP连接状态,这样可以使客户端不需要在每次http请求的时候都去与服务器建立TCP连接,可以节省掉很大的时间开支、提高服务器吞吐率。之所以说这个也是不好控制和不重要的优化点,是因为现代浏览器已经默认支持 Keep-Alive,而常用的Web服务器也都可以对应进行支持。如需手动设置,要注意 timeout 和 max 参数,保持时间太长的TCP连接,也会对服务器造成无用资源消耗。重要的优化内容3. 浏览器请求和服务器响应针对请求和响应的优化,简而言之,就是:减少请求次数降低请求耗时在这里,可做的优化点包括:CDN压缩传输,即GZIP/Deflate前端模块化使用缓存使用本地存储负载均衡:Nginx/SLB3.1 CDNCDN是Web应用优化的基础,也是最重要最影响用户体验的一个环节!在项目中,需要注意将打包后的资源文件上传到CDN地址,并且在构建工具中配置相关CDN信息。3.2 数据压缩服务端与客户端的数据交互可通过压缩来进行优化,常用的压缩方式是 GZip和Deflate,本文以 GZip为例。GZip支持 HTML/CSS/JS/XML/PlainText等多种格式的压缩。下图可看出是否使用压缩,对于传输文件大小的影响。3.3 前端模块化前端模块化便于文件管理、也更利于资源归类压缩,模块化大致经历了如下历程。script -> 闭包函数 -> AMD -> CMD -> CommonJS -> ES6而对应的构建工具,也有以下发展历程。Grunt/Gulp -> Browserify -> Webpack前端模块化详情可参见 《Web前端模块化方法》3.4 使用缓存当客户端使用服务端返回的内容时,可以通过缓存机制,减少请求传输次数。缓存分为 强制缓存和协商缓存 两种。强制缓存使用 Expires 和 Cache-Control:max-age 控制缓存有效时间。协商缓存使用 Last-Modified 配合 ETag 控制缓存有效时间。通常来讲,系统优先匹配强制缓存。对于静态资源,系统需要做好相关缓存,避免重复请求。3.5 使用本地存储使用本地存储,可以在一定程度上减少服务器请求,也可以加快内容展示速度。本地存储的使用有以下历程:Cookie+变量 -> WebStorage -> 单页面内存式存储 -> IndexDB变量 + Cookie
Cookie 被设计来管理状态,但在简单应用中可存储数据
4KB限制 + 域名绑定单页面内存式存储针对单页面应用设计的变量存储如VueXWeb StorageLocalStorage & SessionStorage区别:生命周期、作用域IndexDB
终极方案、NoSQL3.6 负载均衡通常负载均衡包含4中模式:4. 浏览器渲染4.1 Async和Defer对于资源文件的引入,使用 async和defer。async 没有固定顺序,即加载到文件就会引入;defer会按照dom顺序进行插入。4.2 懒加载内容的懒加载,如配合 vue-router的按需加载;图片的懒加载,即需要展示时才去加载。4.3 图片优化图片优化是渲染层面能够最大程度提升性能的优化模块,也是操作起来最麻烦、需要投入精力最多的模块。笔者认为大致分为三个方向:源:确保所有的图片都从CDN源获取裁剪:使用正确大小的图片格式:按需使用格式源和裁剪都比较明确,格式方面我们细说一下。常用格式包括:JPG: 体积小、有损压缩、不支持透明PNG: 体积大、无损压缩、支持透明SVG: 文本文件、体积小、不失真、兼容性好BASE64: 文本文件、依赖编码、小图标解决方案; 需要少量小图标时可以使用此方案,需要大量小图标时建议使用CssSprites;WebP 新格式,支持动图、体积小;浏览器支持的兼容性差。# 阿里在1688网站上的使用方法可以借鉴:https://alicdn.com/xxx.jpg_xxx.webp4.4 Throttle & Debounce节流(Throttle)
在某段时间内,不论触发了多少次回调,都只做第一次,并在结束时给出响应。防抖(Debounce)在某段时间内,不论触发了多少次回调,都只做最后一次,并在完成后给出响应。节流和防抖的目标,都是减少执行,降低损耗,减少卡顿。示例如下:Throttle示例let flag = falsewindow.onscroll = () => { if (flag) { return } flag = true setTimeout(()=>{ doSomething() flag = false })}Debounce示例<input onKeyUp=“kp()">var timervar kp = ()=> { clearTimeout(timer) timer = setTimeout(()=> { search() }, 500)} ...

April 17, 2019 · 1 min · jiezi

Web 性能优化:21种优化CSS和加快网站速度的方法

这是 Web 性能优化的第 4 篇,上一篇在下面看点击查看:Web 性能优化:使用 Webpack 分离数据的正确方法Web 性能优化:图片优化让网站大小减少 62%Web 性能优化:缓存 React 事件来提高性能CSS 必须通过一个相对复杂的管道,就像 HTML 和 JavaScript一样,浏览器必须从服务器下载文件,然后进行解析并将其应用于DOM。由于优化程度极高,这个过程通常非常快——对于不基于框架的小型 web 项目,CSS通常只占总资源消耗的一小部分。框架打破了这种平衡。包括一个 JavaScript GUI 堆栈,如 jQuery UI,可以观察 CSS, JS 和 HTML大小逐渐的变大。通常,开发人员最后才会感到压力,当他们用一个强大的 8 核工作站后面,使用 T3 internet 时,没有人关心速度,这随着延迟或 cpu 受限设备的出现而改变。优化CSS需要一个多维的方法。虽然手工编写的代码可以使用各种技术进行简化,但是手工检查框架代码是低效的。在这些情况下,使用自动化的简化会产生更好的结果。下面的步骤将带我们进入 CSS 优化的世界。并不是每一个都可以直接应用到你的项目中,但是一定要记住它们。01. 使用简写使用缩写语句,如下面所示的 margin 声明,可以从根本上减小 CSS 文件的大小。在 google 上搜索 CSS Shorthand 可以找到许多其他的速记形式。p { margin-top: 1px; margin-right: 2px; margin-bottom: 3px; margin-left: 4px; }p { margin: 1px 2px 3px 4px; }02. 查找并删除未使用的 CSS删除不必要的部分 CSS,j显然会加快网页的加载速度。谷歌的Chrome浏览器有这种开箱即用的功能。只需转到查看>开发人员>开发人员工具,并在最近的版本中打开Sources选项卡,然后打开命令菜单。然后,选择Show Coverage,在Coverage analysis窗口中高亮显示当前页面上未使用的代码,让您大开眼界。打开谷歌浏览器开发都工具,在 Conlse 旁边更多选择 Coverage,就可以看到未使用的 CSS, 点击对应的项,高亮显示当前页面上未使用的代码,让你大开眼界:03. 以更便捷的方式做到这一点在逐行分析中导航并不一定便捷,使用谷歌浏览器的 Audits 就可以快速帮我们分析,使用方式,打开开发者工具,点击 Audits 栏位,点击 Run audits 后就开始分析结果。04. 注意这些问题请记住,对 CSS 的自动分析总是会导致错误。用压缩后的 CSS 文件替换 未压缩CSS文件之后,对整个网站进行彻底的测试——没有人知道优化器会导致什么错误。05.内联关键 CSS加载外部样式表需要花费时间,这是由于延迟造成的——因此,可以把最关键的代码位放在 head 中。但是,请确保不要做得过火,记住,执行维护任务的人员也必须读取代码。<html> <head> <style> .blue{color:blue;} </style> </head> <body> <div class=“blue”> Hello, world! </div>06.允许反并行解析@import 将 CSS 样式方便添加代码中。遗憾的是,这些好处并不是没有代价的:由于 @import 可以嵌套,因此无法并行解析它们。更并行的方法是使用一系列 <link> 标记,浏览器可以立即获取这些标记。@import url(“a.css”);@import url(“b.css”);@import url(“c.css”);<link rel=“stylesheet” href=“a.css”><link rel=“stylesheet” href=“b.css”><link rel=“stylesheet” href=“c.css”>07. 用 CSS 替换图片几年前,一套半透明的 png 在网站上创建半透明效果是司空见惯的。现在,CSS过 滤器提供了一种节省资源的替代方法。例如,以下这个代码片段可以确保所讨论的图片显示为其自身的灰度版本。img { -webkit-filter: grayscale(100%); /* old safari */ filter: grayscale(100%);}08.使用颜色快捷方式常识告诉我们,六位数的颜色描述符是表达颜色最有效的方式。事实并非如此——在某些情况下,速记描述或颜色名称可以更短。target { background-color: #ffffff; }target { background: #fff; }09. 删除不必要的零和单位CSS 支持多种单位和数字格式。它们是一个值得感谢的优化目标——可以删除尾随和跟随的零,如下面的代码片段所示。此外,请记住,零始终是零,添加维度不会为包含的信息附带价值。padding: 0.2em;margin: 20.0em;avalue: 0px;padding: .2em;margin: 20em;avalue: 0;10. 消除过多分号这种优化需要谨慎,因为它会影响代码的更改。CSS的规范允许省略属性组中的最后一个分号。由于这种优化方法所节省的成本很小,所以我们主要针对那些正在开发自动优化的程序员说明这一点。p {. . . font-size: 1.33em}11.使用纹理图集由于协议开销的原因,加载多个小图片的效率很低。CSS 精灵将一系列小图片组合成一个大的PNG 文件,然后通过 CSS 规则将其分解。TexturePacker 等程序大大简化了创建过程。.download { width:80px; height:31px; background-position: -160px -160px}.download:hover { width:80px; height:32px; background-position: -80px -160px}12. 省略 px提高性能的一个简单方法是使用CSS标准的一个特性。为 0 的数值默认单位是 px—— 删除 px 可以为每个数字节省两个字节。h2 {padding:0px; margin:0px;}h2 {padding:0; margin:0}13. 避免需要性能要求的属性分析表明,一些标签比其他标签更昂贵。以下这些解析会影响性能—如果在没有必要的情况,尽量不要使用它们。border-radiusbox-shadowtransformfilter:nth-childposition: fixed;14. 删除空格空格——考虑制表符、回车符和空格——使代码更容易阅读,但从解析器的角度看,它没有什么用处。在发布前删除它们,更好的方法是将此任务委托给 shell 脚本或类似的工具。15. 删除注释注释对编译器也没有任何作用。创建一个自定义解析器,以便在发布之前删除它们。这不仅节省了带宽,而且还确保攻击者和克隆者更难理解手头代码背后的思想。16. 使用自动压缩Yahoo 的用户体验团队创建了一个处理许多压缩任务的应用程序。它以 JAR 文件的形式发布,在这里可用,并且可以使用所选的JVM运行。java -jar yuicompressor-x.y.z.jarUsage: java -jar yuicompressor-x.y.z.jar [options] [input file]Global Options -h, –help Displays this information –type <js|css> Specifies the type of the input file17. 在 NPM 运行它如果你希望将产品集成到 Node.JS 中,请访问 npmjs.com/package/yuicompressor。维护不良的存储库包含一组包装器文件和JavaScript API。var compressor = require(‘yuicompressor’); compressor.compress(’/path/to/file or String of JS’, { //Compressor Options: charset: ‘utf8’, type: ‘js’,18. 保持 Sass 的检查虽然 CSS 选择器的性能不像几年前那么重要(请参阅参考资料),但是像 Sass 这样的框架有时会产生非常复杂的代,不时查看输出文件,并考虑优化结果的方法。19. 设置缓存有句老话说,最快的文件永远不会通过网络发送。让浏览器缓存请求有效地实现这一点。遗憾的是,缓存头的设置必须在服务器上进行。充分上面讲的的两个 Chrome 工具,它们提供了一种快速分析更改结果的方法。20. 打破缓存设计人员通常不喜欢缓存,因为他们担心浏览器会缓存上次的样式表。解决这个问题的一个简单方法是包含带有文件名的标记。遗憾的是,由于一些代理拒绝缓存具有“动态”路径的文件,此步骤所附带的代码中概述的方案并不适用于所有地方。<Link rel=“stylesheet” href=“style.css?v=1.2.3”>21. 不要忘记基础知识优化CSS只是游戏的一部分。如果你的服务器不使用 HTTP/2 和 gzip 压缩,那么在数据传输期间会损失很多时间。幸运的是,解决这两个问题通常很简单。我们的示例显示了对常用Apache 服务器的一些调整。如果您发现自己在一个不同的系统上,只需参考服务器文档即可。pico /etc/httpd/conf/httpd.confAddOutputFilterByType DEFLATE text/htmlAddOutputFilterByType DEFLATE text/css你的点赞是我持续分享好东西的动力,欢迎点赞!一个笨笨的码农,我的世界只能终身学习!更多内容请关注公众号《大迁世界》! ...

March 17, 2019 · 2 min · jiezi

Web 性能优化: 使用 React.memo() 提高 React 组件性能

这是 Web 性能优化的第四篇,之前的可以在下面点击查看:Web 性能优化: 使用 Webpack 分离数据的正确方法Web 性能优化: 图片优化让网站大小减少 62%Web 性能优化: 缓存 React 事件来提高性能React.js 核心团队一直在努力使 React 变得更快,就像燃烧的速度一样。为了让开发者能够加速他们的 React 应用程序,为此增加了很多工具:Suspense 和 Lazy Load (React.lazy(…), <Suspense/>)纯组件shouldComponentUpdate(…){…} 生命周期钩子在这篇文章中,我们将介绍 React v16.6 中新增的另一个优化技巧,以帮助加速我们的函数组件:React.memo。提示:使用 Bit 共享和安装 React 组件。使用你的组件来构建新的应用程序,并与你的团队共享它们以更快地构建。浪费的渲染组件构成 React 中的一个视图单元。这些组件具有状态,此状态是组件的本地状态,当状态值因用户操作而更改时,组件知道何时重新渲染。现在,React 组件可以重新渲染 5、10 到 90次。有时这些重新渲染可能是必要的,但大多数情况下不是必需的,所以这些不必要的这将导致我们的应用程序严重减速,降低了性能。来看看以下这个组件:import React from ‘react’class TestC extends React.Component { constructor(props) { super(props); this.state = { count: 0 } } componentWillUpdate(nextProps, nextState) { console.log(‘componentWillUpdate’) } componentDidUpdate(prevProps, prevState) { console.log(‘componentDidUpdate’) } render () { return ( <div> {this.state.count} <button onClick={ () => this.setState({count: 1})}>Click Me</button> </div> ) }}export default TestC;该组件的初始状态为 {count: 0} 。当我们单击 click Me 按钮时,它将 count 状态设置为 1。屏幕的 0 就变成了 1。.当我们再次单击该按钮时出现了问题,组件不应该重新呈现,因为状态没有更改。count 的上个值为1,新值也 1,因此不需要更新 DOM。这里添加了两个生命周期方法来检测当我们两次设置相同的状态时组件 TestC 是否会更新。我添加了componentWillUpdate,当一个组件由于状态变化而确定要更新/重新渲染时,React 会调用这个方法;还添加了componentdidUpdate,当一个组件成功重新渲染时,React 会调用这个方法。在浏览器中运行我们的程序,并多次单击 Click Me 按钮,会看到在控制打印很多次信息:在我们的控制台中有 “componentWillUpdate” 和 “componentWillUpdate” 日志,这表明即使状态相同,我们的组件也在重新呈现,这称为浪费渲染。纯组件/shouldComponentUpdate为了避免 React 组件中的渲染浪费,我们将挂钩到 shouldComponentUpdate 生命周期方法。shouldComponentUpdate 方法是一个生命周期方法,当 React 渲染 一个组件时,这个方法不会被调用 ,并根据返回值来判断是否要继续渲染组件。假如有以下的 shouldComponentUpdadte:shouldComponentUpdate (nextProps, nextState) { return true}nextProps: 组件接收的下一个 props 值。nextState: 组件接收的下一个 state 值。在上面,告诉 React 要渲染我们的组件,这是因为它返回 true。如果我们这样写:shouldComponentUpdate(nextProps, nextState) { return false}我们告诉 React 永远不要渲染组件,这是因为它返回 false。因此,无论何时想要渲染组件,都必须返回 true。现在,可以重写 TestC 组件:import React from ‘react’;class TestC extends React.Component { constructor(props) { super(props); this.state = { count: 0 } } componentWillUpdate(nextProps, nextState) { console.log(‘componentWillUpdate’) } componentDidUpdate(prevProps, prevState) { console.log(‘componentDidUpdate’) } shouldComponentUpdate(nextProps, nextState) { if (this.state.count === nextState.count) { return false } return true } render() { return ( <div> { this.state.count } <button onClick = { () => this.setState({ count: 1 }) }> Click Me </button> </div> ); }}export default TestC;我们在 TestC 组件中添加了 shouldComponentUpdate,我们检查了当前状态对象this.state.count 中的计数值是否等于 === 到下一个状态 nextState.count 对象的计数值。 如果它们相等,则不应该重新渲染,因此我们返回 false,如果它们不相等则返回 true,因此应该重新渲染以显示新值。在我们的浏览器中测试,我们看到我们的初始渲染:如果我们多次点击 click Me 按钮,我们只会得到:componentWillUpdatecomponentDidUpdate 我们可以从 React DevTools 选项卡中操作 TestC 组件的状态,单击 React 选项,选择右侧的 TestC,我们将看到带有值的计数状态:在这里,我们可以改变数值,点击count文本,输入 2,然后回车:你会看到状态计数增加到 2,在控制台会看到:componentWillUpdatecomponentDidUpdatecomponentWillUpdatecomponentDidUpdate这是因为上个值为 1 且新值为 2,因此需要重新渲染。现在,使用 纯组件。React在v15.5中引入了Pure Components。 这启用了默认的相等性检查(更改检测)。 我们不必将 shouldComponentUpdate 生命周期方法添加到我们的组件以进行更改检测,我们只需要继承 React.PureComponent,React 将会自己判断是否需要重新渲染。注意:1)继承 React.PureComponent 时,不能再重写 shouldComponentUpdate,否则会引发警告Warning: ListOfWords has a method called shouldComponentUpdate(). shouldComponentUpdate should not be used when extending React.PureComponent. Please extend React.Component if shouldComponentUpdate is used.2)继承PureComponent时,进行的是浅比较,也就是说,如果是引用类型的数据,只会比较是不是同一个地址,而不会比较具体这个地址存的数据是否完全一致。class ListOfWords extends React.PureComponent { render() { return <div>{this.props.words.join(’,’)}</div>; }}class WordAdder extends React.Component { constructor(props) { super(props); this.state = { words: [‘marklar’] }; this.handleClick = this.handleClick.bind(this); } handleClick() { // This section is bad style and causes a bug const words = this.state.words; words.push(‘marklar’); this.setState({words: words}); } render() { return ( <div> <button onClick={this.handleClick}>click</button> <ListOfWords words={this.state.words} /> </div> ); }}上面代码中,无论你怎么点击按钮,ListOfWords 渲染的结果始终没变化,原因就是WordAdder的 word 的引用地址始终是同一个。当然如果想让你变化,只要在 WordAdder 的 handleClick 内部,将 const words = this.state.words; 改为 const words = this.state.words.slice(0),就行了,因为改变了引用地址。3)浅比较会忽略属性或状态突变的情况,其实也就是,数据引用指针没变而数据被改变的时候,也不新渲染组件。但其实很大程度上,我们是希望重新渲染的。所以,这就需要开发者自己保证避免数据突变。接着让我们修改我们的 TestC 组件来使用 PureComponent:import React from ‘react’;class TestC extends React.PureComponent { constructor(props) { super(props); this.state = { count: 0 } } componentWillUpdate(nextProps, nextState) { console.log(‘componentWillUpdate’) } componentDidUpdate(prevProps, prevState) { console.log(‘componentDidUpdate’) } /shouldComponentUpdate(nextProps, nextState) { if (this.state.count === nextState.count) { return false } return true }/ render() { return ( <div> { this.state.count } <button onClick = { () => this.setState({ count: 1 }) }> Click Me </button> </div > ); }}export default TestC;这里注释掉了 shouldComponentUpdate 实现,我们不需要它,因为 React.PureComponent 将为我们做检查。试它,重新加载你的浏览器,并点击多次点击 Click Me 按钮:现在,我们已经看到如何在 React 中优化类组件中的重新渲染,让我们看看我们如何在函数组件中实现同样的效果。函数组件现在,我们看到了如何使用 Pure Components 和 shouldComponentUpdate 生命周期方法优化上面的类组件,是的,类组件是 React 的主要组成部分。 但是函数也可以在 React 中用作为组件。function TestC(props) { return ( <div> I am a functional component </div> )}这里的问题是,函数组件没有像类组件有状态(尽管它们现在利用Hooks useState的出现使用状态),而且我们不能控制函数组件的是否重新渲染,因为我们不能像在类组件中使用生命周期方法。如果可以将生命周期钩子添加到函数组件,那么就以添加 shouldComponentUpdate 方法来告诉React 什么时候重新渲染组件。 当然,在函数组件中,我们不能使用 extend React.PureComponent 来优化我们的代码让我们将 TestC 类组件转换为函数组件。import Readct from ‘react’;const TestC = (props) => { console.log(Rendering TestC : props) return ( <div> {props.count} </div> )}export default TestC;// App.js<TextC count={5}/>在第一次渲染时,它将打印 Rendering TestC :5。打开 DevTools 并单击 React 选项。在这里,更改 TestC 组件的 count 为 5.如果我们更改数字并按回车,组件的 props 将更改为我们在文本框中输入的值,接着继续更为 45:移动到 Console 选项我们看到 TestC 组件重新渲染,因为上个值为 5,当前值为 45.现在,返回 React 选项并将值更改为 45,然后移至 Console:看到组件重新渲染,且上个值与当前值是一样的。我们如何控制重新渲染?解决方案:使用 React.memo()React.memo(…) 是 React v16.6 中引入的新功能。 它与 React.PureComponent 类似,它有助于控制 函数组件 的重新渲染。 React.memo(…) 对应的是函数组件,React.PureComponent 对应的是类组件。如何使用 React.memo(…)这很简单,假设有一个函数组件,如下:const Funcomponent = ()=> { return ( <div> Hiya!! I am a Funtional component </div> )}我们只需将 FuncComponent 作为参数传递给 React.memo 函数:const Funcomponent = ()=> { return ( <div> Hiya!! I am a Funtional component </div> )}const MemodFuncComponent = React.memo(Funcomponent)React.memo 会返回了一个纯组件 MemodFuncComponent。 我们将在 JSX 标记中渲染此组件。 每当组件中的 props 和 state 发生变化时,React 将检查 上一个 state 和 props 以及下一个 props 和 state 是否相等,如果不相等则函数组件将重新渲染,如果它们相等则函数组件将不会重新渲染。现在来试试 TestC 函数组件:let TestC = (props) => { console.log(‘Rendering TestC :’, props) return ( <div> { props.count } </> )}TestC = React.memo(TestC);打开浏览器并加载应用程序,打开 DevTools 并单击 React 选项,选择 <Memo(TestC)>。现在,如果我们在右边编辑 count 值为到 89,会看到我们的应用程序重新渲染:如果我们在将值改为与上个一样的值: 89:不会有重新渲染!!总结总结几个要点:React.PureComponent 是银React.memo(…) 是金。React.PureComponent 是 ES6 类的组件React.memo(…) 是函数组件React.PureComponent 优化 ES6 类组件中的重新渲染React.memo(…) 优化函数组件中的重新渲染原文:https://blog.bitsrc.io/improv…你的点赞是我持续分享好东西的动力,欢迎点赞!一个笨笨的码农,我的世界只能终身学习!更多内容请关注公众号《大迁世界》! ...

March 13, 2019 · 3 min · jiezi

Web 性能优化: 图片优化让网站大小减少 62%

这是 Web 性能优化的第二篇,上一篇在下面看点击查看:Web 性能优化: 使用 Webpack 分离数据的正确方法图像是web上提供的最基本的内容类型之一。他们说一张图片胜过千言万语。但是如果你不小心的话,图片大小有时高达几十兆。因此,虽然网络图像需要清晰明快,但它们尺寸可以缩小压缩的,使用加载时间保持在可接受的水平。在我的网站上,我注意到我的主页的页面大小 超过了 1.1MB,图片占了约88%,我还注意到我提供的图像比它们需要的大(在分辨率方面),显然,还有很多改进的空间。我开始阅读 Addy Osmani 的优秀 Essential Image Optimization电子书,并开始在我的网站上按照他们的建议做了一些图片的优化。,然后再对响应式图像进行了一些研究并应用了它。这使得页面大小减少到 445kb,约 62% !什么是图像压缩?压缩图像就是在图片保持在可接受的清晰度范围内同时减少文件大小,我使用 imagemin 来压缩站点上的图像。要使用 imagemin,确保你已经安装了 Node.js,然后打开一个终端窗口,cd 进入项目,并运行以下命令:npm install imagemin然后创建一个名为 imagemin.js 的新文件,写入下面的内容:const imagemin = require(‘imagemin’);const PNGImages = ‘assets/images/.png’;const JPEGImages = ‘assets/images/.jpg’;const output = ‘build/images’;你可以根据自己的需要更改 PNGImages、JPEGImages 和 output 的值,以符合你的项目结构。此外要执行图片压缩,还需要根据要压缩的图像类型安装对应的插件。JPEG/JPGJPG 的优点JPG 最大的特点是 有损压缩。这种高效的压缩算法使它成为了一种非常轻巧的图片格式。另一方面,即使被称为“有损”压缩,JPG的压缩方式仍然是一种高质量的压缩方式:当我们把图片体积压缩至原有体积的 50% 以下时,JPG 仍然可以保持住 60% 的品质。此外,JPG 格式以 24 位存储单个图,可以呈现多达 1600 万种颜色,足以应对大多数场景下对色彩的要求,这一点决定了它压缩前后的质量损耗并不容易被我们人类的肉眼所察觉——前提是你用对了业务场景。JPG 使用场景JPG 适用于呈现色彩丰富的图片,在我们日常开发中,JPG 图片经常作为大的背景图、轮播图或 Banner 图出现。JPG 的缺陷有损压缩在上文所展示的轮播图上确实很难露出马脚,但当它处理矢量图形和 Logo 等线条感较强、颜色对比强烈的图像时,人为压缩导致的图片模糊会相当明显。此外,JPEG 图像不支持透明度处理,透明图片需要召唤 PNG 来呈现。使用 MozJPEG 压缩 jpeg这里使用 Mozilla 的 MozJPEG 工具,该工具可以通过 imagemin-mozjpeg 作为 Imagemin 插件使用。你可以通过运行以下命令来安装它:npm install imagemin-mozjpeg然后将以下内容添加到的 imagemin.js 中:const imageminMozjpeg = require(‘imagemin-mozjpeg’);const optimiseJPEGImages = () => imagemin([JPEGImages], output, { plugins: [ imageminMozjpeg({ quality: 70, }), ] });optimiseJPEGImages() .catch(error => console.log(error));可以通过在终端中运行 node imagemin.js 来运行脚本。这将处理所有JPEG图像,并将优化后的版本放 build/images 文件夹中。我发现将 quality 设置为 70 在大多数情况下可以产生足够清晰的图像,但你的项目需求可能不同,可以自行设置合适的值。默认情况下,MozJPEG 生成渐进式 jpeg,这会导致图像从低分辨率逐渐加载到高分辨率,直到图片完全加载为止。由于它们的编码方式,它们也比原始的 jpeg 略小。你可以使用 Sindre Sorhus 提供的这个命令行工具来检查JPEG图像是否是渐进式的。Addy Osmani 已经很好地总结了使用渐进式 jpeg 的优缺点。对我来说,我觉得利大于弊,所以我坚持使用默认设置。如果你更喜欢使用原始的jpeg,可以在 options 对象中将 progressive 设置为 false。另外,请确保 imagemin-mozjpeg 版本的变化,请重新查看对应文档。PNG (PNG-8 与 PNG-24)PNG 的优缺点PNG(可移植网络图形格式)是一种无损压缩的高保真的图片格式。8 和 24,这里都是二进制数的位数。按照我们前置知识里提到的对应关系,8 位的 PNG 最多支持 256 种颜色,而 24 位的可以呈现约 1600 万种颜色。PNG 图片具有比 JPG 更强的色彩表现力,对线条的处理更加细腻,对透明度有良好的支持。它弥补了上文我们提到的 JPG 的局限性,唯一的缺点就是 体积太大。PNG 应用场景前面我们提到,复杂的、色彩层次丰富的图片,用 PNG 来处理的话,成本会比较高,我们一般会交给 JPG 去存储。考虑到 PNG 在处理线条和颜色对比度方面的优势,我们主要用它来呈现小的 Logo、颜色简单且对比强烈的图片或背景等。使用 pngquant 优化 PNG 图像pngquant 是我优化PNG图像的首选工具,你可以通过 imagemin-pngquant 使用它:npm install imagemin-pngquant然后将以下内容添加到 imagemin.js 文件中:const imageminPngquant = require(‘imagemin-pngquant’);const optimisePNGImages = () => imagemin([PNGImages], output, { plugins: [ imageminPngquant({ quality: ‘65-80’ }) ], });optimiseJPEGImages() .then(() => optimisePNGImages()) .catch(error => console.log(error));我发现将 quality 设置为 65-80 可以在文件大小和图像质量之间较好的折衷方案。有了这些设置,我可以得到一个屏幕截图,我的网站从 913kb 到 187kb,没有任何明显的视觉损失,惊人的79% 的降幅!这是两个文件。看一看,自己判断一下:原图(913kb)优化后的图像(187kb)WebPWebP 的优点WebP 像 JPEG 一样对细节丰富的图片信手拈来,像 PNG 一样支持透明,像 GIF 一样可以显示动态图片——它集多种图片文件格式的优点于一身。WebP 的官方介绍对这一点有着更权威的阐述:与 PNG 相比,WebP 无损图像的尺寸缩小了 26%。在等效的 SSIM 质量指数下,WebP 有损图像比同类 JPEG 图像小25-34%。 无损 WebP 支持透明度(也称为 alpha 通道),仅需 22% 的额外字节。对于有损 RGB 压缩可接受的情况,有损 WebP 也支持透明度,与 PNG 相比,通常提供 3 倍的文件大小。将 WebP 图像提供给支持它们的浏览器WebP 是谷歌引入的一种相对较新的格式,它的目标是通过以无损和有损格式编码图像来提供更小的文件大小,使其成为 JPEG 和 PNG 的一个很好的替代方案。WebP 图像的清晰度通常可以与 JPEG 和 PNG相提并论,而且文件大小要小得多。例如,当我将屏幕截图从上面转换到 WebP 时,我得到了一个 88kb 的文件,其质量与 913kb 的原始图像相当,减少了90% !看看这三张图片,你能说出区别吗?原图PNG (913kb)优化PNG图像(187kb)WebP图像(88kb,可在Chrome或Opera浏览器中浏览)就我个人而言,我认为视觉效果是可以比较的,而且节省下来的大小是不容忽视的。既然我们已经认识到在可能的情况下使用WebP格式是有价值的,那么很重要的一点是—它不能完全替代 JPEG 和 PNG,因为浏览器对 WebP 支持并不普遍。在撰写本文时,Firefox、Safari 和 Edge 都是不支持WebP的浏览器。然而,根据 caniuse.com 的数据,全球超过70%的用户使用支持WebP的浏览器。这意味着,通过使用 WebP 图像,可以为大约 70% 的客户提供更快的 web 页面及更好的体验。安装它,运行以下命令:npm install imagemin-webp然后将以下内容添加到你的 imagemin.js 文件中:const imageminWebp = require(‘imagemin-webp’);const convertPNGToWebp = () => imagemin([PNGImages], output, { use: [ imageminWebp({ quality: 85, }), ] });const convertJPGToWebp = () => imagemin([JPGImages], output, { use: [ imageminWebp({ quality: 75, }), ] });optimiseJPEGImages() .then(() => optimisePNGImages()) .then(() => convertPNGToWebp()) .then(() => convertJPGToWebp()) .catch(error => console.log(error));我发现,将 quality 设置为 85 会生成质量与 PNG 相当但小得多的 WebP 图像。对于 jpeg,我发现将 quality 设置为 75 可以在视觉和文件大小之间取得很好的平衡。提供 HTML格式的WebP图像一旦有了 WebP 图像,可以使用以下标记将它们提供给可以使用它们的浏览器,同时向不兼容 WebP 的浏览器使用 png 或者 jpeg。<picture> <source srcset=“sample_image.webp” type=“image/webp”> <source srcset=“sample_image.jpg” type=“image/jpg”> <img src=“sample_image.jpg” alt=""></picture>使用此标记,理解 image/webp 媒体类型的浏览器将下载 Webp 图片并显示它,而其他浏览器将下载 JPEG 图片。任何不支持 <picture> 的浏览器都将跳过所有 source 标签,并加载底部 img 标签。因此,我们通过提供对所有浏览器类的支持,逐步增强了我们的页面。请注意,在所有情况下,img 标记都是实际呈现给页面的内容,因此它确实是语法的必需部分。 如果省略 img 标记,则不会渲染任何图像。<picture> 标签和其中定义的所有 source 都在那里,以便浏览器可以选择要使用的图片的路径。 选择源图像后,其 URL 将传给 img 标记,这就是显示的内容。这意味着你无需设置 <picture> 或 source 标记的样式,因为浏览器不会渲染这些标记。 因此,你可以像以前一样继续使用 img 标签进行样式设置。总结正如你所看到的,优化 web 上使用的图像的过程并不复杂,通过减少页面加载时间,可以为客户带来更好的用户体验,希望本文对你有所帮助,共进步!代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。原文:https://medium.freecodecamp.o…你的点赞是我持续分享好东西的动力,欢迎点赞!一个笨笨的码农,我的世界只能终身学习!更多内容请关注公众号《大迁世界》! ...

March 5, 2019 · 2 min · jiezi