Android SDK 类产品开发总结

原作者:snow,转载已获得作者授权。

原文链接:https://democome.com/article/android-sdk-development-summary

在开发Android应用时,我们需要用到Google提供的SDK。当我们的开发的某一个模块足够通用也可以封装成SDK给其他业务方使用。什么是一个良好的SDK类产品?站在开发者和接入方的角度我认为应该满足以下几点:

# 对于开发者

  • 良好的可维护性
  • 设计合理、可扩展性强
  • 代码逻辑清晰合理
  • 监控及数据打点完备

# 对于接入方

  • 集成简单,最好一行代码搞定
  • 接入文档,接入实例详细
  • 崩溃率低、内存占用小、SDK尽量小
  • 出现问题及时响应解决

以上总结起来就是对开发者友好、对接入方友好。当别人接手代码没有砸键盘的冲动甚至想和你干一杯82年的雪碧。当业务方接入你的SDK时感到神清气爽。下面总结一下本人在开发过程中总结的一些点,抛砖引玉,共同探讨。

# 注意点

# 1、熟悉你的代码

这个放在第一条,是每个人要对自己的代码逻辑负责。

# 2、合理的接口设计

接口设计尽量简单,尤其是对业务方来说,没有那么多时间研究你的方法。接入越简单对业务方成本越低。

# 3、内存分配与回收

申请合适的内存,如果数组只放10个数据,就没必要申请20个空间大小。不用的资源及时回收。对于有多个进程的应用,要考虑是否有必要在每个进程都初始化SDK。

# 4、慎重选择第三方库

本身我们要做的就是一个SDK类的产品,尽量不使用第三方库。因为它会增大我们SDK包的大小。如果必须要使用,要选择稳定的第三方库,同时需要注意第三方库冲突的问题。你的接入方可能也依赖了这个第三方库,甚至和你的版本不一样。这时有两种选择,在你的SDK中以provided的方式依赖。二是修改第三方库的包名以解决冲突(这样会增大最终应用的大小)。关于修改包名可以使用jarjar.jar。可参考这篇文章

# 5、ContentProvider authorities 冲突导致应用无法安装

<provider
    android:name="com.democome.SPContentProvider"
    android:authorities="com.democome.sdk.sp"
    android:exported="false"
    android:process=":push" />

 

像上面这样,如果多个应用接入了我们的SDK,那么第二个安装就会出问题“应用组件的命名与已安装应用有冲突”,导致第二个应用无法安装,正确的做法是authorities和包名相关,如下:

<provider
    android:name="com.democome.SPContentProvider"
    android:authorities="${applicationId}.sdk.sp"
    android:exported="false"
    android:process=":push" />

# 6、异常处理和日志

什么样的异常自己处理,什么样的异常抛给业务方。我认为如果是业务方接入问题导致的异常,可以给业务方抛出异常。某些流程的关键环节打印出日志,当然这个日志是个可以开关的。

# 7、多进程操作SharedPreferences

多进程操作SharedPreferences是有问题的,尽管SharedPreferences有一个MODE_MULTI_PROCESS模式,但这个模式也是不靠谱的,在一个进程中修改SharedPreferences中的值,另一个进程不会同步更新。解决办法是可以通过ContentProvider进行进程的同步操作。

8、安全问题

本地拒绝服务漏洞,getIntent()的intent附带空数据、异常或畸形数据,会导致应用崩溃。解决办法需要加try catch。

9、打包管理

规范的打包管理系统,版本的管理,发布的管理等。

10、aar资源名称

aar中资源的名字加上一个前缀避免引用错误。

11、混淆

这个仁者见仁,有些大名鼎鼎的SDK都没有混淆。

12、内存泄漏

用leakcanary检测,不要有内存泄漏。

13、打点统计

SDK有良好的运行时监控机制,在某些关键地方以及崩溃打点上报,及时获取SDK运行状态,保证运行时稳定。但是打点也不能太频繁,避免对业务方业务造成影响。

14、特定机型适配

这点没什么好说的,其实也是最坑的,各种乱七八糟的坑需要填。

以上就是在SDK开发过程中的一些总结,以后有更新会继续补充,如果你在开发过程中有什么经验或教训欢迎留言交流!

使用 Flutter 开发 macOS App

原作者:WhatsXie,转载已获得作者授权。

原文链接:https://zhuanlan.zhihu.com/p/50218676

Flutter 框架

Flutter 是 Google 开发的一套全新的跨平台、开源 UI 框架,支持 iOS、Android 系统开发,并且是未来新操作系统 Fuchsia 的默认开发套件。

Flutter 通过跨平台的 Skia 图形库来实现图形渲染,只依赖各个系统的图形绘制相关的 Api,可能是目前为止真正意义上的全平台 UI 框架。

借助 Feather 平台,我们可以在 MacOS 和 Windows 上运行我们的 Flutter 应用程序,也就是说您可以编写一个可以在所有主要桌面和移动设备上运行的应用程序。

Feather 平台

Feather 是一个在桌面上运行 Flutter 应用程序的平台。

  • 在 Mac 和 Windows 上运行 Flutter 应用程序的编译器和库
  • 一个应用商店,您可以使用它来发布和更新应用,并为用户提供最小的安装阻力
  • 一组可选的扩展 Flutter UI 小部件,用于高级界面设计
  • 目前处于 alpha 测试阶段
  • 免费使用的商业执照

官网:feather-apps.com

配置环境

进入官网,点击 Build an App Now 下载 Mac 端编译器。

下载完成后打开 Feature Workbench,这里就有了墙的存在,非精品网可能要自行处理一下。

Google 账户登录后,可以看到工程列表,如果你第一次做,当然是空的。

项目改造

我们这里新建一个项目为例,教大家怎么把 Flutter 项目运行到 MacOS 上,非常简单哦。

1. 打开终端,新建一个 Flutter 项目

flutter create mac_app

2. 打开 mac_app 项目中 main.dart 修改两处:

1)在代码顶部引入 foundation 架包

import 'package:flutter/foundation.dart';

2)改造 void main() 函数,增加平台覆盖

void main() {  
   debugDefaultTargetPlatformOverride = TargetPlatform.iOS; 
   runApp(MyApp());
 }

保存代码,就可以了。

新建 Feather 项目

点击 Feature Workbench 界面右下角的加号,进入新建页面,点击 BROWSE 找到 Flutter 项目工程。

设置应用名和图标就创建完成了。

点击 TEST 会打开 Xcode, command + r 运行就会看到 Flutter 的官方示例运行在 MacOS 上了。

Flutter 右上角的 DEBUG 是环境标记,不想看见它,切换生产环境它就不见了

发布和使用

点击 PUBLISH 设置应用描述和截图,发布应用到 Feather 商店。

发布完成后再次进入项目列表,就可以看到 WEB 选项,点击就会进入 Feather 应用商店的网站。

更新

和发布流程一样,只是需要注意修改版本号、应用描述和截图,最后上传应用即可。

效果演示

上面使用的是 Flutter 官方的示例工程,有朋友表示看起来不过瘾,so 我从网上找了一个看起来很适合做跨平台服务的示例工程,经过改造后我将其运行到了 macOS 系统上。

功能更新 | 概览面板布局更新与热力图功能

这个月,FrontJS 经历了两次大功能更新。月初新增了报警系统,让你随时随地收到网站的突发异常,及时处理问题。详情 👉http://blog.frontjs.com/archives/123

年末,FrontJS 再次完成了进化

1. 调整了概览面板布局,新增多个可视化图表;

2. 趋势页新增页面访问分布热力图。

现在,只要打开 FrontJS 工作台的概览页面,即可一目了然地获悉网页或小程序的各项指标,将数据完全「可视化」。

另外,FrontJS 新增了页面访问分布功能,可以通过 「热力图」直观的看到每个自定义时间段的访问情况。在“概览”页和“趋势”页都能找到它。有了它,网站或小程序的所有者就能清楚的看出页面的访问情况,进一步了解用户的访问行为和访问习惯,在运营中也可以有效的通过这些指标对产品进行迭代和优化。

 

 

WebAssembly的过去、现在和未来

原作者:Richard

原文链接:https://zhuanlan.zhihu.com/p/50218676
首发于知乎专栏「前端杂货铺」

历史

在每个浏览器里面,无论Chrome,Firefox,Safari,Edge,能够运行的语言就是Javascript。为了能够让其他语言的代码在浏览器中运行,WebAssembly被创造出来。它拥有更好性能,更小的size,能够更快的加载和执行。我们无需编写WebAssembly的代码,只需要将其他高级语言编译成WebAssembly,这样就能在浏览器中复用大量的其他语言现有的代码。

WebAssembly仍在持续的发展,还有大量的特性即将到来。其最早发明出来是为了将C++的转译成JS,然后在浏览器中运行起来,这样就能把大量现有的C++代码在浏览器中复用。被转译后的JS代码比原生的JS代码要慢,Mozilla的工程师发现一种类型系统,可以让被转译后的JS运行得更快,这就是asm.js. 同时,其他浏览器厂商发现asm.js的运行速度非常快,也把这种优化加入到他们的浏览器引擎中。这仅仅是开始,工程师们仍在持续努力,但是,不是将其他语言编译成JS,而是一种新的语言,那就是WebAssembly。

最小可用产品

WebAssembly不仅仅支持C/C++,同时也希望支持更多的高级语言,因此,需要一个语言无关的编译目标,就像汇编语言一样,支持任何语言编译成汇编语言。这个编译目标有如下的特点:

  1. 跟具体的平台无关,因此不同平台的不同浏览器都能运行WebAssembly。
  2. 拥有足够快的运行速度,能够带来足够流畅的交互体验。
  3. 加载速度要足够快,因此,需要编译目标能够被压缩,减小加载内容的大小
  4. 能够手动的管理,分配内存。我们知道C/C++一类的语言支持指针的特性,通过指针可以读写特定地址的内存;为了安全考虑,还要对限制特定地址的内存进行操作。出于以上的亮点,WebAssembly使用了线性内存模型。

通过以上的特点,保证了WebAssembly能够在生产环境中使用起来。

如何应对繁重的桌面应用

我们知道,大量的桌面应用,像PS,AutoCAD,这些应用非常的庞大,对性能要求非常苛刻。要先让他们在浏览器里面运行起来非常的难,因此需要更多的特性来确保更佳的性能:

  1. 首当其冲的,是需要支持多线程。现代的计算机都是多核的,通过多线程能够更好的利用计算机的计算能力。
  2. SIMD(单指令多数据)。通过SIMD,能够将一组内存划分成不同的执行单元,就像多核一样。
  3. 64位寻址。借助64位寻址,能够使用更多的内存,这对一些内存敏感性的应用是非常有利的。
  4. 流式编译。前面提到了,提升加载的速度,其实我们有更好的办法,就是刚下载的时候就开始编译,这将是巨大的提升。
  5. HTTP缓存。如何两个浏览器加载相同的WebAssembly代码,将会编译成相同的机器码,因此可以将编译后的机器码保存在HTTP缓存中,这样就可以跳过编译的过程,复用机器码。

现状

  1. 多线程:一个草案已经接近完成,其中的关键SharedArrayBuffers,已经被否决了。
  2. SIMD:正在开发中…
  3. 64位寻址:wasm-64即将登场
  4. 流式编译:Firefox已经在2017年支持,其他浏览器也即将支持

虽然这些特性仍在开发中,但是我们能够看到已经有大量的桌面应用在浏览器中运行起来,其中最大的幕后功臣就是WebAssembly。

WebAssembly与JavaScript

对于很多的web应用场景,我们可能只需要在一些性能敏感的部分,使用WebAssembly。因此,某些模块需要用WebAssembly来编写,然后替换掉那些JS写的部分。一个例子就是Firefox中的source map library的parser,它用WebAssembly编写,比原来用JS编写的快11倍。为了能让这种场景下,WebAssembly更好的发挥作用,有更多的要求:

  1. JS和WASM能够更快的相互调用。因为要将WASM代码作为模块继承到现存的JS应用中,需要他们能够更快的相互调用,Firefox中已经有了巨大的提升
  2. 快速而容易的数据转换。在JS和WASM相互调用时,需要传递数据,要想实现上面的两个目标,非常的难:WASM只理解数字,那就需要将各种数据格式转换成数字
  3. ES module。集成WASM模块,通常在JS中使用import,export关键词,因此,浏览器需要内置ES module。
  4. 工具链。在JS中,可以使用npm,brower等工具,但是在WASM中,好像没有这个工具…
  5. 兼容性。前端开发,都逃不了兼容性的问题。

现状

  1. Firefox中,JS和WASM能够很快的调用
  2. 引用类型草案登场,其增加了一种新的,WASM函数能够接收和返回的类型,这个类型引用一个外部的object,可以是JS的Object。
  3. 一个ES module的草案被提及,浏览器厂商正在支持。
  4. Rust生态的wasm-pack能够像npm一样支持包管理
  5. 借助wasm2js工具,能够让WASM在旧版的浏览器中得到支持

通过以上的特性以及正在开发中的功能,WASM的能力得到释放,接下来就是如何再现有的Web生态中使用WASM。

应用

在前端开发中,大量涉及的框架及编译成JS的语言都将是WASM发挥作用的场景。所以就有两种选择了:1,使用WASM来重写现有的Web框架;2,将Reasonml,Elm等语言编译成WASM。为了实现这些功能,需要WASM提供更多高级语言的特性,包括:

  1. GC。首先,提供GC功能对重写web框架是非常有优势的。例如:使用WASM重写React中的diff功能,借助多线程,手动的内存分配,能够提供以前无法现象的高性能,但是当你跟JS 对象交互时,例如组件,仍然需要GC来减轻开发的负担。
  2. 异常处理。很多的高级语言,如C/C++提供异常处理,在某些特定场景下非常有用,同时JS也有异常处理,当WASM和JS互操作时,也需要有异常处理的支持。
  3. debug。这个就不多说

现状

  1. JS拥有Typed Objects 草案,WASM拥有GC草案。通过这两个草案,JS和WASM都能够清晰的知道一个对象的结构以及如何去存储,使用,回收。
  2. 异常处理。目前还在开发阶段。
  3. debug。目前,大多数浏览器已经支持。

功能更新 | 新增报警系统 ,前端异常尽在掌握

从地域图表到桑基图功能,FrontJS 一直将功能更新的重头戏放在数据的可视化上,归根结底只有一个目的——节省开发者获得数据的时间,提升开发效率。这是我们设计产品时追求的核心目标,也是我们一直在做的事。本次上线的「报警系统」,更是能让你随时随地收到网站的突发异常,及时处理问题。

  • 项目概览页趋势图优化

在项目概览页的趋势图中,我们对横纵坐标点进行了细化,增加了描点的密度,使趋势图展现更精准明确。 

  • 新增报警系统

下面说说本次更新的重头戏——报警功能。有了这个功能,可以大大提升工作效率,能帮助开发者更好的关注网页的异常动态。

打开 FrontJS 工作界面,在左边栏中点击“通知策略”后,通过右上角的“新增策略”即可设置需要报警的详情,其中各项指标均可自定义。

需要注意的是,报警功能分为「静态报警」和「动态报警」两种方式,可以按需选择。「静态策略」主要依赖于先前设置的固定指标,一旦超过该数值即会收到报警信息;而「动态策略」指的是趋势,一旦有异常趋势就会启动报警。

在监控类型中,报警功能支持多种错误类型及类型细分设置,涵盖网站的所有性能,同时可自主控制报警策略内容。

另外说一个小技巧,如果监测的指标繁杂,可以在设置策略名称时适当优化,帮助你快速识别问题所在。

*注意:报警信息会通过邮件或短信的形式发送,报警延迟时间为3分钟。

所有设置里报警的指标都可以通知策略中的列表里找到,在这个界面里可以看到策略的所有信息,包括目前的观测值与报警状态,并可以随时在该界面对策略进行调整。

一文带你快速了解现代的CSS

作者|Peter Jang
译者|覃云
相信大家已经熟悉一般的 CSS,现在我们将从 CSS 预处理器开始介绍改善 CSS 语言本身工作体验的构建工具。
使用 CSS 预处理器获取新语法

CSS 预处理器允许你使用不同的语言编写样式,将其转换为浏览器可以理解的 CSS,这在浏览器实现新功能速度非常缓慢的时候是极其重要的。第一个主要的 CSS 预处理器是 2006 年发布的 Sass,它具有新型的简洁语法(缩进代替括号、没有分号等),并增加了 CSS 中缺少的高级功能,例如变量、辅助函数和计算。以下是使用带变量的 Sass 的示例:

$dark-color: #4a4a4a
$light-color: #f9f9f9
$side-color: #eee
body
  color: $dark-color

header, footer
  background-color: $dark-color
  color: $light-color

main
  background: $light-color
nav, aside
  background: $side-color

请注意,如何使用 $ 符号定义可重用变量,并消除括号和分号,使语法更清晰简洁。虽然 Sass 的语法简洁是一件好事,但当时变量是革命性的功能特性,因为它们为编写简洁且可维护的 CSS 开辟了新的可能性。

如果使用 Sass,你需要安装 Ruby,这是用于将 Sass 代码编译为常规 CSS 的编程语言。然后,你需要安装 Sass gem,然后在命令行中运行将.sass 文件转换为.css 文件的命令,以下是一个示例:

sass --watch index.sass index.css

这个命令会将一个名为 index.sass 常规 CSS 的文件中的 Sass 代码转换成一个名为 index.css(在任何时候,--watch会提示它保存更改的内容,这很方便)。

这个过程称为构建步骤,这在 2006 年可是一个重大的难题。如果你能熟练使用 Ruby 这样的编程语言,那么这个过程将会非常简单。但当时许多前端开发者只使用不需任何此类工具的 HTML 和 CSS,因此,对开发者来说,学习整个生态系统以获得由 CSS 预处理器提供的功能是一个很高的要求。

2009 年,CSS 的 Less 预处理器发布,它也是用 Ruby 编写的,并且提供了与 Sass 类似的功能。主要的区别在于语法,其语法的设计尽可能接近 CSS,这意味着任何 CSS 代码都是有效的 Less 代码,下面是使用 Less 语法编写的示例:

@dark-color: #4a4a4a;
@light-color: #f9f9f9;
@side-color: #eee;
body {
  color: @dark-color;
}

header, footer {
  background-color: @dark-color;
  color: @light-color;
}

main {
  background: @light-color;
}
nav, aside {
  background: @side-color;
}

它们几乎是相同的(@前缀代替 $ 变量),只是不像 Sass 示例那样漂亮,但它与 CSS 具有相同的大括号和分号,这种与 CSS 相似的特点使得开发人员更容易接受它。2012 年,JavaScript(特别是 Node.js)代替 Ruby 用于重写和编译 Less。这让 Less 比那些使用 Ruby 的同类速度要快,并且这让 Less 在那些已在工作流程中使用 Node.js 的开发人员中更受欢迎。

要将此代码转换为常规 CSS,首先你需要安装 Node.js,然后安装 Less,最后运行如下命令:

lessc index.less index.css

这个命令会将名为 index.less 文件中的 Less 代码转换为 index.css 中的常规 CSS。请注意,Lessc命令并没有提供查看文件以及进行文件更改的方式(这与 Sass 命令不同),这意味着你需要安装不同的工具来自动监视和编译 .less 文件,这为进程增加了复杂性。不过,这对于习惯使用命令行工具的程序员来说,并不是一件难事儿,但对于其他只想使用 CSS 预处理器的人而言,这是一个难以跨越的障碍。

伴随着 Less 在意识层面上获得很大的认可,Sass 开发人员在 2010 年增加了一种名为 SCSS 的新语法(可以认定为 CSS 的高配版,与 Less 类似)。他们还发布了 LibSass,这是 Ruby Sass 引擎的 C / C ++ 端口,它的作用是使其加速,并且能够支持多种语言。

另一种替代 CSS 预处理器的是 Stylus,它于 2010 年推出,采用 Node.js 编写,与 Sass 或 Less 相比,它更注重语法的清洁度。一般说来,谈论最多的三种 CSS 预处理器是 Sass、Less 和 Stylus。它们在提供的功能方面都非常相似,所以无论你选择哪个,都不算选错。

然而,有些人认为 CSS 预处理器变得不那么重要了,因为浏览器最终会实现它们的一些特性(例如变量和计算)。此外,还有一种称为 CSS 后处理的方法,可能会使 CSS 预处理器过时(显然有争议),我们将在后面介绍这些方法。

使用 CSS 后处理器实现转换功能

CSS 后处理器使用 JavaScript 来分析并将 CSS 转换为有效的 CSS。从这个意义上讲,它与 CSS 预处理器非常相似,你可以将其视为解决相同问题的不同方法。关键的区别在于,虽然 CSS 预处理器使用特殊语法来标识需要转换的内容,但在无特殊语法下,CSS 后处理器可以解析常规 CSS 并对其进行转换。下面这个例子来最好地说明了这一点。让我们来看看用上面最初定义 CSS 的一部分去设计标题标签的样式:

h1, h2, h3, h4, h5, h6 {
  -ms-hyphens: auto;
  -moz-hyphens: auto;
  -webkit-hyphens: auto;
  hyphens: auto;
}

粗体的部分称为浏览器前缀,在浏览器试验性地添加或测试新的 CSS 功能时会被用到,它为开发人员使用 CSS 的新特性提供了一种方法。-ms前缀是指 Microsoft Internet Explorer,-moz 前缀是指 Mozilla Firefox,-webkit 前缀是指使用 Webkit 渲染引擎的浏览器(如 Google Chrome、Safari 和 Opera 的新版本)。

请注意,添加所有这些不同的浏览器前缀以便使用 CSS 的新特性是非常麻烦的。如果有自动添加浏览器前缀的工具的话,将会很省心,我们可以用 CSS 预处理器来解决这个问题。例如,你可以用 SCSS 做这样的事情:

@mixin hyphens($value) {
  -ms-hyphens: $value;
  -moz-hyphens: $value;
  -webkit-hyphens: $value;
  hyphens: $value;
}
h1, h2, h3, h4, h5, h6 {
  @include hyphens(auto);
}

在这里,我们使用了 Sass 的 mixin 功能,这个功能允许你在定义了一个 CSS 块后,能在其他地方重用。当这个文件被编译成常规的 CSS 时,任何 @include 语句都将被替换成与之匹配的 CSS @mixin 语句。总的来说,这并非是一个糟糕的解决方案,但是你需要为任何需要浏览器前缀的 CSS 属性在首次定义 mixin 时负责。这些 mixin 定义需要维护,因为在浏览器更新其 CSS 兼容性之后,你可能希望删除一些你不再需要的特定浏览器前缀。

不是使用 mixin,而是只写常规的 CSS,并使用一个工具自动识别需要前缀的 CSS,并相应地添加前缀,在这方面,一个 CSS 后处理器就能够做到。例如,如果你将 PostCSS 与 autoprefixer 插件一起使用,则可以在没有任何浏览器前缀的情况下编写常规的 CSS,并让后处理器完成剩下的工作:

h1, h2, h3, h4, h5, h6 {
  hyphens: auto;
}

当你在此代码上运行 CSS 后处理器时,结果会是hyphens: auto,行将被替换为相应的浏览器前缀(正如 autoprefixer 插件中定义地那样,并不需要你直接管理)。也就是说你可以只写常规 CSS 而不必担心任何兼容性或特殊语法,这是一件非常好的事。

除了用于 PostCSS 的 autoprefixer 外,还有一些插件可以让你做很酷的事情。cssnext 插件允许你使用 CSS 的试验性功能,该 CSS 模块插件可以自动改变类来避免名称冲突,stylelint 插件识别 CSS 中的错误和不合常规的行为。这些工具在过去的一两年内才开始起步,为开发人员展示了从未有过的工作流程!

然而,这一过程需要付出代价。与使用 CSS 预处理器相比,安装和使用 PostCSS 之类的 CSS 后处理器更为重要。你不仅需要使用命令行来安装和运行工具,还需要安装和配置各个插件并定义一组更复杂的规则(例如,面向哪些浏览器等),而不是直接从命令行中运行 PostCSS,许多开发人员将其整合到可配置的构建系统中,如 Grunt、Gulp 或 webpack,这些可帮助你管理在前端工作流程中可能使用到的所有不同的构建工具。

注意:如果你以前从未使用过现代的前端构建系统,那么学习所有的必要组件可能会让你觉得是一件颠覆的事情。如果你想从头开始,请查阅我的文章 Modern JavaScript Explained For Dinosaurs,它涵盖了前端开发人员所需的所有 JavaScript 工具。

值得注意的是,CSS 后处理器的身上存在一些争议,有人说它们应该统称为 CSS 预处理器,还有别的说法认为它们应该简单地称为 CSS 处理器等,也有一些人认为 CSS 后处理器完全不需要 CSS 预处理器,而有些人认为它们应该一起使用。无论怎样,很显然,如果你有兴趣更深一步挖掘出 CSS 的潜能,那么学会使用 CSS 后处理器将值得你去尝试。

使用 CSS 的方法论进行维护

CSS 预处理器和 CSS 后处理器等工具为改进 CSS 开发体验迈出了重要的一步,但单靠这些工具还不足以解决大型 CSS 代码库的维护问题。为了解决这个问题,人们开始记录关于如何编写 CSS 的不同的指导方针,通常称为 CSS 方法论。

在我们深入研究任何特定的 CSS 方法论之前,我们要清楚这么多年是什么使得 CSS 的维护变得如此困难?关键的问题在于 CSS 的全局性 – 你定义的每种风格都会应用于页面的每个部分。想出一个详细的命名规则来维护唯一的类名或者用特殊规则来决定哪个样式应用于给定的元素,这将变成你的工作。CSS 方法提供了一种有组织性的方式来编写 CSS,以解决大型代码库的痛点,让我们以时间顺序粗略地看一下那些流行的方法。

 OOCSS

OOCSS(Object Oriented CSS)是在 2009 年首次提出的,它遵循两种原则。第一个原则是将结构和表现隔开,这意味着定义结构(如布局)的 CSS 不应该与定义表现(如颜色、字体等)的 CSS 一起混用,这使得应用程序更容易重构其表现。第二个原则是将容器和内容隔开,这意味着将元素视为可重用的对象,而且不管对象在页面的哪个位置,看起来都应该是相同的。

OOCSS 提供了成熟的指导方针,但没有具体的方案。后来的方法如 SMACSS 采用了 OOCSS 的核心概念并增加了更多细节,使其更容易入门。

 SMACSS

SMACSS(Scalable and Modular Architecture for CSS)是在 2011 年推出的,它主要围绕 CSS 中 5 个属性展开,包括基本规则、布局规则、模块、状态规则和主题规则。SMACSS 也提供了一些命名规则,对于布局规则,你可以用l-layout-作为类名称的前缀。对于状态规则,你需要在描述状态的类名加上前缀,比如is-hiddenis-collapsed

与 OOCSS 相比,SMACSS 有更多的细节,但在决定哪些 CSS 规则应该进入哪个类别时仍需要慎重考虑。后来像 BEM 这样的方法避免了做决策的步骤,使其更容易被采用。

 BEM

BEM(Block、 Element、 Modifier)于 2010 年推出,它是将用户界面划分为独立 Block 的一种方法论。一个 Block 是一个可重复使用的部件(例如搜索表单,定义

)。Element 为 Block 的一小部分,它不能独立重复使用(如搜索表单内的 button,Search)。Modifier 是一个实体,定义为外观、状态、Block 或 Element 中的行为(例如禁用搜索表单里的按钮,定义为Search)。

BEM 很容易理解,它具有特定的命名规则,新手在应用它时无需做出复杂的决策。它的缺点是类名非常冗长,并且不遵循传统的规则来编写语义类名。后来的方法如 Atomic CSS 会把这个非传统的方法带到了另一个层面上!

 Atomic CSS

Atomic CSS(也称功能型 CSS)是在 2014 年引入的一种方法,它的主要思想是基于视觉功能创建小而单一用途的类名。这种方法与 OOCSS、SMACSS 和 BEM 完全相反,它 不是将页面上的元素视为可重用的对象,而是完全忽略了这些对象,并使用可重用的单一实用工具类来对每个元素的样式进行设置。所以,你看到不是这样的:<button class="search-form__button">Search</button>,而是这样的:<button class="f6 br3 ph3 pv2 white bg-purple hover-bg-light-purple">Search</button>

如果你对这个例子的第一反应是害怕而退缩,那么你不是一个人,因为许多人认为这种方法与现有的 CSS 最佳实践方案完全背离。然而,不同场景下最佳实践方案的有效性引起了人们的质疑,在这个过程中也引起了不错的讨论。这篇文章 做了很好的分析,重点阐述了传统的关注点分离是如何创建依赖于 HTML 的 CSS(甚至是应当在什么时候使用 BEM 等方法),而 Atomic CSS 或功能型方法则是基于 CSS 创建的 HTML。两者都没错,但经过仔细观察,你会发现 CSS 和 HTML 之间完全的分离从未真正地实现过!

其他的 CSS 方法,如 CSS in JS,实际上包含了 CSS 和 HTML 总是相互依赖的概念,是最具争议性的方法之一。

 CSS in JS

CSS in JS 是 2014 年推出的一种方法,它的观点是:不在单独的样式表中定义 CSS 样式,而是直接在每个组件中定义。它是作为 React JavaScript 框架的一种方法而引入的(它采用了有争议的方法,直接在 JavaScript 中为组件定义 HTML 而不是在单独的 HTML 文件中)。最开始的时候,它采用内联样式,但后来使用 JavaScript 来生成 CSS(使用基于组件的独一无二的类名),并使用样式标记将其插入到文档中。

CSS in JS 再次完全违背了现有 CSS 最佳实践中的分离问题,这是因为我们使用网络的方式随着时间的推移发生了巨大变化。最初网站主要由静态网站组成,那时将 HTML 内容与 CSS 分离很有意义。如今,Web 用于创建动态的 Web 应用程序,这时,通过可重用组件分离更有意义。

CSS in JS 的目标是能够用 HTML / CSS / JS 封装的“硬边界”定义组件,使得每个组件中的 CSS 不会影响任何其他组件。React 是最早被广泛采用的框架之一,它们为这些组件提供了“硬边界”的支持,随后影响了其他主流框架,如 Angular,Ember 和 Vue.js 等。需要注意的是, CSS in JS 是新型的一种方法,在这期间开发人员试图在 Web 应用程序的组件时代为 CSS 建立新的最佳实践,并进行了大量的实验。

我们很容易被许多不同的 CSS 方法淹没,但重要的是要记住,没有一种完全正确的方法—— 当你面对足够复杂的 CSS 代码库时,你应该将它们视为几种不同工具作为备用。经过深思熟虑,为你的作品选择一个最佳的工具,并且在这个过程中进行的每一次试验都将为每位开发人员带来长远利益!

  结 论  

综上所述,这就是现代的 CSS。我们介绍了使用 CSS 进行基础设计的排版属性,将 CSS 用于使用浮点、flexbox 和基于网格的布局,使用 CSS 预处理器以获取新语法(如变量和 mixins),使用 CSS 后处理器实现转换功能,例如添加浏览器前缀,并使用 CSS 的几种方法论进行维护,克服 CSS 样式的全局性。我们没有机会深入了解 CSS 提供的许多其他功能,例如高级选择器、转换器、动画、形状、动态变量等。

由于现代的 CSS 总是在不断地变化和快速发展,将其用在工作上难免让人头疼。但别忘了,随着时间的推移,网络也在不断发展,很高兴有很多聪明的人愿意加入这个行列,构建具体的工具和提出有效的方法来提升 CSS 的实践能力。我希望这些信息可以作为路线图,帮助你踏上旅程!

 原文链接

https://medium.com/actualize-network/modern-css-explained-for-dinosaurs-5226febe3525

文章来源:微信公众号「前端之巅」,微信号:frontshow

展现数据流动的利器——桑基图,现在FrontJS中也能看到

数据的流入和流出渠道一直是网站所有者以及运营人员十分关注的指标。你的用户“从哪来”,又从你的页面流向了哪里,对于这种流动的数据,桑基图就能帮你捋清它们的来龙去脉!

  • 什么是桑基图:一目了然展示数据流动

桑基图(Sankey Diagram)主要由边、流量和节点组成,其中边代表了流动的数据,数值代表了流动数据的具体数值,节点代表了不同分类。边的宽度与流量成比例地显示,边越宽,数值越大。

桑基图有一个很大的特点,即能量守恒。也就是说,桑基图在描述一组数据到另一组数据的流向的同时,还能展示到底「流」了多少。数据从开始到结束,总量都能保持不变。

在近几次的更新中,FrontJS 技术团队一直着眼于数据的可视化表达,旨在提升网页开发者的工作效率,同时提供数据支撑。桑基图通常用于可视化能源或成本转移,也帮助我们确定各部分流量在总体中的大概占比情况。

值得一提的是,除了Web端以外,FrontJS的桑基图功能同样支持微信小程序!作为小程序开发者的你一定不要错过这个黑科技,在小程序用户越来越多的今天,是时候通过关注页面流向好好地把小程序运营起来了!

小程序开发者可以通过FrontJS中「性能与访问」栏里的「页面访问」中找到某一页面的流量来源与流向。页面中的桑基图会以选定的页面为中心节点,展示出向上向下两级页面的流向构成

从上图可以看出,即使流动的数据很多,但是桑基图能利用不同颜色很好地把不同的分类数据区分开来。不同的支点就像发带一样,把多如发丝的边按照流向 “束”起来。大量数据经过不同的支点再分类后重新出发,流向下一个分类。一张图即可表达所有信息,易读性强。

想不想体验一下桑基图的魅力呢?点击这里查看Demo吧!如果你想要看看自己的小程序和网站的桑基图,那就快来FrontJS注册吧,注册即享受10天专业版的免费使用。

 

干货 | CSS 中重要的层叠概念

*本文作者为 SHERlocked93,转载已获得作者授权。

原文链接:

https://segmentfault.com/a/1190000016489078

最近在项目的过程中遇到了一个问题,menu-bar希望始终显示在最上面,而在之后的元素都显示在它之下,当时设置了 z-index 也没有效果,不知道什么原因,因此找了一下css有关层叠方面的资料,解决了这个问题,这里记录一下~

屏幕是一个二维平面,然而HTML元素却是排列在三维坐标系中,x为水平位置,y为垂直位置,z为屏幕由内向外方向的位置,我们在看屏幕的时候是沿着z轴方向从外向内的;由此,元素在用户视角就形成了层叠的关系,某个元素可能覆盖了其他元素也可能被其他元素覆盖;

那么这里有几个重要的概念:层叠上下文 (堆叠上下文, Stacking Context)、层叠等级 (层叠水平, Stacking Level)、层叠顺序(层叠次序, 堆叠顺序, Stacking Order)、z-index

声明:

  1. 以下定位元素指的是position: absolute|fixed|relative|sticky
  2. 以下非定位元素指的是position: initial|static
  3. 关于层叠上下文还有一个类似的概念:块级格式化上下文(BFC, Block Formatting Context),可以参考一下 CSS 中重要的BFC,其中还介绍了一些文档流的内容;
  4. 本文蛮长的,但是如果你有勇气看完,那应该对层叠有关概念就基本掌握了 (~o ̄▽ ̄)~
  1. 层叠上下文 (Stacking Context)

层叠上下文 (堆叠上下文, Stacking Context),是HTML中一个三维的概念。在CSS2.1规范中,每个元素的位置是三维的,当元素发生层叠,这时它可能覆盖了其他元素或者被其他元素覆盖;排在z轴越靠上的位置,距离屏幕观察者越近

文章<关于z-index 那些你不知道的事>有一个很好的比喻,这里引用一下;

可以想象一张桌子,上面有一堆物品,这张桌子就代表着一个层叠上下文。 如果在第一张桌子旁还有第二张桌子,那第二张桌子就代表着另一个层叠上下文。

现在想象在第一张桌子上有四个小方块,他们都直接放在桌子上。 在这四个小方块之上有一片玻璃,而在玻璃片上有一盘水果。 这些方块、玻璃片、水果盘,各自都代表着层叠上下文中一个不同的层叠层,而这个层叠上下文就是桌子。

每一个网页都有一个默认的层叠上下文。 这个层叠上下文(桌子)的根源就是<html></html>。 html标签中的一切都被置于这个默认的层叠上下文的一个层叠层上(物品放在桌子上)。

当你给一个定位元素赋予了除 auto 外的 z-index 值时,你就创建了一个新的层叠上下文,其中有着独立于页面上其他层叠上下文和层叠层的层叠层, 这就相当于你把另一张桌子带到了房间里。

层叠上下文1 (Stacking Context 1)是由文档根元素形成的, 层叠上下文2和3 (Stacking Context 2, 3) 都是层叠上下文1 (Stacking Context 1) 上的层叠层。 他们各自也都形成了新的层叠上下文,其中包含着新的层叠层。

在层叠上下文中,其子元素按照上面解释的规则进行层叠。形成层叠上下文的方法有:

  • 根元素<html></html>
  • position值为absolute | relative,且z-index值不为 auto
  • position 值为 fixed | sticky
  • z-index 值不为 auto 的flex元素,即:父元素display: flex | inline-flex
  • opacity 属性值小于 1 的元素
  • transform 属性值不为 none的元素
  • mix-blend-mode 属性值不为 normal 的元素
  • filterperspectiveclip-pathmaskmask-imagemask-bordermotion-path 值不为 none 的元素
  • perspective 值不为 none 的元素
  • isolation 属性被设置为 isolate 的元素
  • will-change 中指定了任意 CSS 属性,即便你没有直接指定这些属性的值
  • -webkit-overflow-scrolling 属性被设置 touch的元素

总结:

  1. 层叠上下文可以包含在其他层叠上下文中,并且一起组建了一个有层级的层叠上下文
  2. 每个层叠上下文完全独立于它的兄弟元素,当处理层叠时只考虑子元素,这里类似于BFC
  3. 每个层叠上下文是自包含的:当元素的内容发生层叠后,整个该元素将会在父级叠上下文中按顺序进行层叠

2. 层叠等级 (Stacking Level)

层叠等级 (层叠水平, Stacking Level) 决定了同一个层叠上下文中元素在z轴上的显示顺序的概念

  • 普通元素的层叠等级优先由其所在的层叠上下文决定
  • 层叠等级的比较只有在同一个层叠上下文元素中才有意义
  • 在同一个层叠上下文中,层叠等级描述定义的是该层叠上下文中的元素在Z轴上的上下顺序

注意,层叠等级并不一定由 z-index 决定,只有定位元素的层叠等级才由 z-index 决定,其他类型元素的层叠等级由层叠顺序、他们在HTML中出现的顺序、他们的父级以上元素的层叠等级一同决定,详细的规则见下面层叠顺序的介绍。

3. z-index

在 CSS 2.1 中, 所有的盒模型元素都处于三维坐标系中。 除了我们常用的横坐标和纵坐标, 盒模型元素还可以沿着”z 轴”层叠摆放, 当他们相互覆盖时, z 轴顺序就变得十分重要。

— CSS 2.1 Section 9.9.1 – Layered presentation

z-index 只适用于定位的元素,对非定位元素无效,它可以被设置为正整数、负整数、0、auto,如果一个定位元素没有设置 z-index,那么默认为auto;

元素的 z-index 值只在同一个层叠上下文中有意义。如果父级层叠上下文的层叠等级低于另一个层叠上下文的,那么它 z-index 设的再高也没用。所以如果你遇到 z-index 值设了很大,但是不起作用的话,就去看看它的父级层叠上下文是否被其他层叠上下文盖住了。

4. 层叠顺序 (Stacking Order)

层叠顺序 (层叠次序, 堆叠顺序, Stacking Order) 描述的是元素在同一个层叠上下文中的顺序规则,从层叠的底部开始,共有七种层叠顺序:

  1. 背景和边框:形成层叠上下文的元素的背景和边框。
  2. 负z-index值:层叠上下文内有着负z-index值的定位子元素,负的越大层叠等级越低;
  3. 块级盒:文档流中块级、非定位子元素;
  4. 浮动盒:非定位浮动元素;
  5. 行内盒:文档流中行内、非定位子元素;
  6. z-index: 0:z-index为0或auto的定位元素, 这些元素形成了新的层叠上下文;
  7. 正z-index值:z-index 为正的定位元素,正的越大层叠等级越高;

同一个层叠顺序的元素按照在HTML里出现的顺序层叠;第7级顺序的元素会显示在之前顺序元素的上方,也就是看起来覆盖了更低级的元素:

5. 实战

5.1 普通情况

三个relative定位的div块中各有absolute的不同颜色的span.redspan.greenspan.blue,它们都设置了position: absolute

参见Codepen – 普通情况

那么当没有元素包含z-index属性时,这个例子中的元素按照如下顺序层叠(从底到顶顺序):

  1. 根元素的背景和边界
  2. 块级非定位元素按HTML中的出现顺序层叠
  3. 行内非定位元素按HTML中的出现顺序层叠
  4. 定位元素按HTML中的出现顺序层叠

红绿蓝都属于 z-index 为auto的定位元素,因此按照7层层叠顺序规则来说同属于层叠顺序第6级,所以按HTML中的出现顺序层叠:红->绿->蓝

5.2 在相同层叠上下文的父元素内的情况

红绿位于一个div.first-box下,蓝位于div.second-box下,红绿蓝都设置了position: absolutefirst-boxsecond-box都设置了position: relative

参见Codepen – 父元素不同但都位于根元素下

这个例子中,红蓝绿元素的父元素first-boxsecond-box都没有生成新的层叠上下文,都属于根层叠上下文中的元素,且都是层叠顺序第6级,所以按HTML中的出现顺序层叠:红->绿->蓝

5.3 给子元素增加 z-index

红绿位于一个div.first-box下,蓝黄位于div.second-box下,红绿蓝都设置了position: absolute,如果这时给绿加一个属性z-index: 1,那么此时.green位于最上面;

如果再在.second-box下.green后加一个绝对定位的 span.gold,设置z-index: -1,那么它将位于红绿蓝的下面;

参见Codepen – 设置了z-index

这个例子中,红蓝绿黄元素的父元素中都没有生成新的层叠上下文,都属于根层叠上下文中的元素

  1. 红蓝都没有设置 z-index,同属于层叠顺序中的第6级,按HTML中的出现顺序层叠;
  2. 绿设置了正的 z-index,属于第7级;
  3. 黄设置了负的 z-index,属于第2级;

所以这个例子中的从底到高显示的顺序就是:黄->红->蓝->绿

5.4 在不同层叠上下文的父元素内的情况

红绿位于一个div.first-box下,蓝位于div.second-box下,红绿蓝都设置了position: absolute,如果first-box的z-index设置的比second-box的大,那么此时无论蓝的 z-index 设置的多大z-index: 999,蓝都位于红绿的下面;如果我们只更改红绿的z-index值,由于这两个元素都在父元素first-box产生的层叠上下文中,此时谁的z-index值大,谁在上面;

参见Codepen – 不同层叠上下文的父元素

这个例子中,红绿蓝都属于设置了z-index的定位元素,不过他们的父元素创建了新的层叠上下文;

  1. 红绿的父元素first-box是设置了正z-index的定位元素,因此创建了一个层叠上下文,属于层叠顺序中的第7级;
  2. 蓝的父元素second-box也同样创建了一个层叠上下文,属于层叠顺序中的第6级;
  3. 按照层叠顺序,first-box中所有元素都排在second-box上;
  4. 红绿都属于层叠上下文first-box中且设置了不同的正 z-index,都属于层叠顺序中第7级;
  5. 蓝属于层叠上下文second-box,且设置了一个很大的正 z-index,属于层叠元素中第7级;
  6. 虽然蓝的 z-index 很大,但是因为second-box的层叠等级比first-box小,因此位于红绿之下;

所以这个例子中从低到到显示的顺序:蓝->红->绿

(我遇到的的情况就属于这个例子类似情形)

5.5 给子元素设置 opacity

红绿位于div.first-box下,蓝位于div.second-box下,红绿蓝都设置了position: absolute,绿设置了z-index: 1,那么此时绿位于红蓝的最上面;

如果此时给first-box设置opacity: .99,这时无论红绿的 z-index 设置的多大z-index: 999,蓝都位于红绿的上面;

如果再在.second-box.green后加一个span.gold,设置z-index: -1,那么它将位于红绿蓝的下面;

参见Codepen – opacity的影响

之前已经介绍了,设置opacity也可以形成层叠上下文,因此:

  1. first-box设置了opacityfirst-box成为了一个新的层叠上下文;
  2. second-box没有形成新的层叠上下文,因此其中的元素都属于根层叠上下文;
  3. 黄属于层叠顺序中第2级,红绿属于第7级,first-box属于第6级,蓝属于层叠顺序中第6级且按HTML出现顺序位于first-box之上;

所以这个例子中从低到到显示的顺序:黄->红->绿->蓝

网上的帖子大多深浅不一,甚至有些前后矛盾,在下的文章都是学习过程中的总结,如果发现错误,欢迎留言指出~

参考:

  1. 你不知道的Z-Index
  2. MDN – z-index
  3. What No One Told You About Z-Index
  4. 彻底搞懂CSS层叠上下文、层叠等级、层叠顺序、z-index
  5. 前端性能优化之更平滑的动画
  6. 关于z-index 那些你不知道的事
  7. 聊聊CSS中的层叠相关概念

推介阅读:

  1. CSS 中重要的BFC

Web性能优化 | 如何提高首屏加载速度?

在 FrontJS 的使用反馈中,页面和资源的加载速度是很多用户密切关注的数据,想要提高加载速度,就需要不断的对网站进行优化。相信大家都有在浏览网页时遇到过页面加载不完全的问题。作为网站的“建造人”,我们不仅是开发者,同时也是用户。当我们在网页上看到各种红叉和长时处于 loading 状态的信息时,会瞬间失去浏览页面的兴致,变得不耐烦起来——尤其是首屏,加载的快与慢直接影响着用户的使用体验及滞留时间。

相对于移动端的首屏,Web端想让用户看到的信息更多更丰富,页面难免会大而“重”,首屏作为用户与网站的第一眼互动,“秒开”变得至关重要。今天就来谈谈如何对首屏时间进行性能优化。

  • 什么是首屏?

以800×600像素尺寸为标准,当浏览器加载页面后看到第一眼的显示内容为首屏;从开始加载到浏览器页面显示高度达到600像素且此区域有内容显示的时间为首屏显示时间(当然这个标准随着技术进步在不断变化)下图京东首页为例,对于电商网站而言,营销活动的banner、轮播图、账户信息、分类检索等供用户自主选择的主要内容全部集中在首屏,所以对首屏的加载速度要求极高。

  • 大公司是如何进行首屏优化的?

仍然以京东为例:

当我们打开京东的网站(不要滚动鼠标和键盘),右键查看源代码会发现京东首页的DOM树出奇的简单,页面DOM中多含有mod_lazyload的类。

<div class="J_f J_lazyload J_f_lift mod_lazyload need_ani chn" id="portal_8" data-backup="basic_8" data-source="cms:basic_8" data-tpl="portal_tpl">

再看下 localstorage

尤其在查看键名类似于 URL 的键值对时,会发现它们的值中多存在一串完整的类似于html的内容。

{"dom":"{%var liftTxtArr = pageConfig.liftTxtArr,clstagPrefix = 'h|keycount|2016|41a', i;%}<ul class=\"lift_list\">{% for (i = 0; i < liftTxtArr.length; i++) { %}<li class=\"J_lift_item lift_item{%= (i===0) ? ' lift_item_first' : '' %}\" clstag=\"{%= clstagPrefix + (i < 9 ? '0' : '') + (1+i) %}\"><a href=\"javascript:;\" class=\"lift_btn\"><span class=\"lift_btn_txt\">{%= liftTxtArr[i] %}</span></a></li>{% } %}<li class=\"J_lift_item J_lift_item_top lift_item lift_item_top\" clstag=\"{%= clstagPrefix + (i < 9 ? '0' : '') + (1+i) %}\"><a href=\"javascript:;\" class=\"lift_btn\"><span class=\"lift_btn_txt\">顶部<i class=\"lift_btn_arrow\"><!--&#xe606;--></i></span></a></li></ul>","style":".lift{display:none;position:fixed;z-index:100;-moz-box-shadow:0 0 4px rgba(0,0,0,.2);box-shadow:0 0 4px rgba(0,0,0,.2);background-color:#918888}.lift_item{border-top:1px solid #b1aaaa;-webkit-transition:background-color .1s;-moz-transition:background-color .1s;transition:background-color .1s}.lift_item_first{border-top:none}.lift_btn{*cursor:pointer;overflow:hidden;display:block;width:24px;padding:10px 5px;line-height:14px;text-align:center;color:#fefefe;-webkit-transition:color .1s;-moz-transition:color .1s;transition:color .1s}.lift_item:hover,.lift_item_on{position:relative;border-bottom:1px solid #d70b1c;margin-bottom:-1px;border-color:#d70b1c;background-color:#d70b1c}.lift_item:hover .lift_btn,.lift_item_on .lift_btn{color:#fff}.lift_item_top,.lift_item_top:hover{border-top:1px solid #f6f6f6;background-color:#5e4a4a;border-bottom:0;margin-bottom:0}.lift_item_top .lift_btn{color:#fff}.lift_btn_arrow{display:block;width:0;height:0;margin:auto;border-style:solid;border-width:4px;border-color:#5e4a4a #5e4a4a #fff}.o2_mini .lift{display:none}","version":"062a40dffff4da26"}

由上面的结构可知,京东已经将它们的页面结构放到了localstorage。由此可见,只是它页面其中一个模块的内容。分析到这里已经很明显了,京东通过前端缓存和异步加载已经完美的实现了首屏快速加载,在Web端达到了秒开的级别。

京东首先只加载框架然后将框架内容与模版绑定,用户滚动时,一旦该框架内容部分进入了视窗,则请求对应的 data-tpl 地址,拿到渲染这个模块所需要的脚本和数据,不过这中间还有一层本地缓存 localstorage,如果在本地缓存中匹配到了对应的 hash string 内容,则直接渲染,否则请求到数据之后更新本地缓存。localstorage 中的 version 会在页面加载时候,与后端文件 hash相对比,hash不变直接取localstorage中的内容(当然也可以使用cookie判断版本)。

如果数据和初始化脚本包装在一起,虽然节约了一个请求,但一旦数据变化,整个脚本都得重新加载。将数据和脚本分离,脚本可以长期缓存在本地,单独请求数据,这个量会小很多。直接改变上面的 version 版本号便可以让浏览器重新请求最新脚本。

从上面可以看出,任何一个模块的改动,在前端只会引起一个较小的加载变化,加上 http 的缓存策略,服务器的压力也是很小的。

看了上面的内容,相信大家已经对京东关于首屏优化的方案有了一个大致的了解,下面我们再整理一下关于首屏显示速度优化细节上的内容:

  • CSS静态文件在哪里?

为了追求速度,京东的首页是没有 CSS 外链的,相信对于我们来说,也是老生常谈的前端优化了。

有人可能会问,如果没有 CSS 外链,那一整个页面的 CSS 是否会增加页面的体积?其实上面已经提到,将页面切分为模块化加载,对应模块下的 CSS 交给 js 或 jsonp 请求返回。

  • js文件怎么加载?

如果外部 CSS 资源较小,可以直接将这些内容插入到HTML文档中,这称为“内嵌”。通过这种方式内嵌较小 CSS 资源,浏览器可以继续呈现网页。请注意,如果CSS文件较大,完全内嵌CSS可能会对浏览器构建和渲染DOM树增加不少压力。如果 CSS 文件较大,您需要识别和内嵌呈现首屏内容所需的 CSS,并暂缓加载其余样式,直到首屏内容显示之后为止。

京东采用请求的方式减少了与服务器交互的时间。

<script src="//misc.360buyimg.com/??/jdf/lib/jquery-1.6.4.js,/jdf/2.0.0/ui/ui/1.0.0/ui.js,/mtd/pc/index/gb/lib.min.js,/mtd/pc/base/1.0.0/base.js,/mtd/pc/common/js/o2_ua.js,/mtd/pc/index/home/index.min.js,/mtd/pc/index/home/init.min.js"></script>
  • js文件怎么执行?

懒加载也就是延迟加载,有交互才执行。js文件有需要时才加载,并不是再打开页面时一次性全部加载完成。

  • 图片如何处理?

图片在其他屏(非首屏)都采用懒加载的模式,这样既能节省流量,也能减少请求数或延迟请求数。

当访问一个页面的时候,先把 img 元素或是其他元素的背景图片路径替换成一张大小为1*1px图片的路径(这样就只需请求一次,俗称占位图),只有当图片出现在浏览器的可视区域内时,才设置图片正真的路径,让图片显示出来。用这样的方式,可以使页面加载速度变快,从而减轻服务器的压力,同时优化用户体验。当访问一个页面的时候,先把 img 元素或是其他元素的背景图片路径替换成一张大小为1*1px图片的路径(这样就只需请求一次,俗称占位图),只有当图片出现在浏览器的可视区域内时,才设置图片正真的路径,让图片显示出来。用这样的方式,可以使页面加载速度变快,从而减轻服务器的压力,同时优化用户体验。

  • 服务器需要做什么?
  1. 少量静态文件的域名,图片与iconfont均是放在同一个域下,减少DNS的解析事件,最好做到域名收敛。
  2. 模块化接口的支持。
  3. 首屏内容最好做到静态缓存。

版权声明:

*本文在转载时有删改

原作者:一半水一半冰

出处:https://www.cnblogs.com/jingh/p/6531105.html#3962455

 

功能更新 | 地域分布图表功能上线!

这次的新功能可以说是真“新鲜出炉”了!首页的「概览」中新增了「独立访客」与「国家和地区」两个板块。

独立访客数量(UV)是网站流量分析中十分重要的指标,不仅对运营人员来说是每天都要关注的数据,对网站开发者或是PM而言同样重要。我们在听取了用户建议后,决定将「独立访客」数据单独展示在“概览”中,当日的访客数量一目了然。

同时,想关注当日或历史日活数据,只需在日报中点击对应日期查看即可。👇

另外,在「趋势」栏中,可以看到近两周的页面访问与日活的趋势,是不是很贴心?

接下来聊聊“版图”这件事儿。

FrontJS新增了超酷的地域分布图表功能,在「概览」「性能」以及「日报」中可以找到。增添了这个功能之后,一切都变得简单直观了起来。

值得一提的是,除了当日的独立访问量,同样可以看到当日访客的分布地图,颜色越深代表当日访客量越多。

对于网站开发者来说,看着自己的产品“版图”日益扩张,在这个世界的每个角落留下痕迹,内心想必是澎湃且激动的吧!

在性能栏的「网络请求」页中,可以观测到下载时长的地区分布图,通过颜色的深浅表示网络请求的时长,颜色越深,请求时间越长。

「资源加载」页新增资源加载时长地区分布图,同样的,颜色越深的地区表示资源加载用时越长。

「页面加载」页新增页面加载时长地区分布图,颜色越深的地区表示页面加载用时越长。

地域分布图标功能上线了之后,数据监控变得更加简明清晰,大大节省了用户小伙伴获得数据的时间。「为用户设计」一直是我们设计产品时追求的核心目标,提升产品的可用性也是我们一直在做的事。快来试试新功能吧 👉 https://www.frontjs.com/