文章目录

    • 前言
    • Something great
    • 第1章 浏览器和浏览器内核
      • 浏览器
      • 用户代理和浏览器行为
      • 内核特征
      • WebKit与blink
    • 第2章 HTML网页和结构
      • 网页构成与结构
      • WebKit的网页渲染过程
    • 第3章WebKit架构和模块
      • WebKit架构及模块 及 源代码结构
      • 基于Blink的Chromium浏览器结构 及 代码结构
      • WebKit2 架构、模块
    • chromium 的渲染
      • 渲染过程
      • 渲染步骤
      • HTML
      • DOM
      • CSS
      • 浏览器架构
      • 浏览器工作原理概述
  • 参考

前言

Something great

  • render :渲染
  • Blink: chromium渲染引擎的名称
  • parser: 解析器
  • AST :(Abstract Syntax Tree,抽象语法树)
  • openGL :(Open Graphics Library,开放图形库);一个大部分平台都支持的 底层图形库的 API 标准
  • DirectX:(Direct eXtension,简称DX)微软的多媒体API。
  • 沙箱(sandBox):操作系统对 进程的可访问的内存地址所做的限制。
    • 渲染进程被 Sandbox 隔离,网页 web 代码内容必须通过 IPC 通道才能与浏览器内核进程通信,通信过程会进行安全的检查。
    • 沙箱运行:渲染器在单独的进程中运行,通过沙箱限制其对系统资源(文件、网络、显示、击键)的访问,而须通过父浏览器进程访问
  • 插件:浏览器的插件用于显示网页特定内容
  • 扩展:浏览器的扩展用于增加浏览器新功能的软件或压缩包
  • inspector:(web inspector,调试页面))

第1章 浏览器和浏览器内核

浏览器
  • 通常所谓的浏览器内核也就是浏览器所采用的渲染引擎,浏览器内核主要包括以下三个技术分支:排版渲染引擎、 JavaScript引擎,以及其他。

    • 渲染引擎决定了浏览器如何显示网页的内容以及页面的格式信息。
    • Google V8引擎是一个JavaScript引擎实现,使用C++开发。
  • Webkit引擎包含WebCore排版引擎及JavaScriptCore解析引擎。WebCore是苹果公司开发的排版引擎,由排版引擎“KHTML”的基础上而来。

  • Blink是一个由Google和Opera Software开发的浏览器排版引擎,这一渲染引擎是开源引擎WebKit中WebCore组件的一个分支

用户代理和浏览器行为
  • 用户代理和浏览器行为体现了客制化,是浏览器的内卷结果。

    • 用户代理(User Agent)用于表明浏览器的身份,因而互联网的内容供应商能够知道发送请求的浏览器身份,浏览器能够支持什么样的功能

      • 例如:服务器为Chrome的桌面版和Android版,发送不同的网页内容以适应屏幕和操作系统的差别,或者是因为不同的浏览器支持的标准不一样。
      • 这样做的目的当然是为了避免浏览器不支持的功能以及获得更好的用户体验。
  • 实践:
    • 通过设置用户代理chrome -android mobile刷新后,可以看到页面是为安卓系统设计的,更适合手机交互。
内核特征
  • 渲染引擎的功能主要包括:HTML解释器、CSS解释器、布局(lay out)、JS引擎。

    • HTML解释器:将HTML文本解释成DOM.
    • CSS解释器:为DOM各个元素计算出样式信息,为布局提供基础设施。
    • 布局:将DOM元素对象和样式信息结合,计算大小位置等布局信息,形成一个内部表示模型。
    • JS引擎:js可以修改网页内容,JS引擎解析js并通过DOM接口和CSSOM接口修改网页内容和样式信息,从而改变渲染结果。
    • 绘图:使用图形库,将布局计算后的网页节点绘制成图像结果。
  • 渲染引擎依赖了:网络、存储、2D/3D图形、音频和视频、图片解码器。
    • 同样一起依赖了OS的支持(如线程、文件等)。

WebKit与blink
  • 2001年WebKit来自KHTML,05年被苹果开源。
  • 2013年 blink fork 自WebKit。

第2章 HTML网页和结构

网页构成与结构
  • html 是一种半结构化数据表现方式,结构特征有:树状、层次、框结构。

    • js代码用于控制网页内部逻辑。即控制用户端逻辑。
    • CSS用于描述网页显示信息。
  • HTML5 :
    • 2D、3D图形以及多媒体方面的支持。使得2D、3D图形以及多媒体 被浏览器原生支持。不需要第三方插件。
  • 网页结构:
    • 框结构:

      • 每个框结构包含一个HTML文档,使用元素嵌套框。桌面端应用较为广泛。
    • 层次结构:
      • 层次结构指:网页中元素可能分布在不同层次中,webkit 为他们构建新层,是为了渲染引擎在处理上方便和高效。

        • 如:创建新层可以更有效的处理视频解码器和浏览器之间的交互和渲染问题。

          • 如:层1为video创建的层;;层2为需要3D变换的div创建的层;层3、4对应canvas,有着HTML5中的2D、3D绘图操作。
          • 可以使用浏览器的show composited layer borders 打开网页的层次结构显示详细观看。
WebKit的网页渲染过程
  • 网页比我们屏幕可视面积要大,当前可见区域成为视图
  • 渲染分为三个阶段:URL到DOM、DOM到构建绘图上下文、绘图上下文到最终图像
    • URL到DOM:

      • js可能修改DOM树结构,如步骤7 。
      • 节点可能需要依赖其他资源,如图片、CSS、视频等,要异步加载他们,如步骤8 。
        • 如果是加载URL,没有标记异步方式,则需要停止DOM构建直到资源加载完。
      • 当DOM构建完成时,发出DOMconent事件
      • 当DOM构建完成、网页所依赖资源都加载完之后,发出onload 事件。
        • 因为资源加载不一定影响DOM树创建,所以这两个事件不一定同时发生。
    • DOM到绘图上下文:
      • webkit 利用CSS和DOM树,构建renderObject树,直到绘图上下文。

        1. CSS文件被CSS解释器解释成内部表示结构
        2. CSS解释器结束后,在DOM上附加解释后的样式信息,就是renderObject树
        3. renderObject 节点创建同时,webkit 根据网页层次结构创建 renderLayer树,同时构建一个虚拟的绘图上下文。
      • renderObject树的创建并不会让DOM树销毁,这四个结构一直存在,直到网页被销毁,因为都对网页渲染有很大作用。
    • 绘图上下文到最终图像:
      • 这个过程主要依赖2D、3D图形库。

        1. 绘图上下文是个与平台无关的抽象类,将每个绘图操作桥接至不同具体绘图实现类。
        2. 绘图实现类,在chromium 中需要其合成器完成复杂的多进程与GPU加速机制。
        3. 绘图实现类,将2D、3D图形库绘制的结果保存下来,交给浏览器和UI一起显示。
  • 如今网页多是动态网页,渲染完成后,由于动画与交互,浏览器一直重复执行渲染过程。

第3章WebKit架构和模块

WebKit架构及模块 及 源代码结构
  • WebKit支持不同浏览器,为了不同需求,有些代码是共享的,有些是不同的,不同的部分成为WebKit的移植(ports)

      • 虚线框部分:该模块在不同浏览器使用 webkit的实现不一样。
      • 第三方库是WebKit的运行基础,WebKit是这些库的使用者。
      • Webcore 部分是共享的,是网页加载和渲染的基础部分。(web inspector,调试页面))
      • jscore 是WebKit的js引擎,chromium中替换为了V8引擎。
      • WebKit ports 是非共享部分。由于平台差异、依赖第三方库、和需求不同,所以实现方式不同。
      • 嵌入式编程接口: 提供给浏览器调用。因为接口与移植有关,所以有个浏览器相关的绑定层。(???)
      • WebKit中其实还包括了测试用例,一般包括布局测试用例(layout tests)、性能测试用例(performance tests)。
  • WebKit源代码结构:

  • 主要目录有四个。

    • WTF是基础类库,像是C++的 STL库。
    • webcore:
      • 按照目录组织了webcore 的模块代码。
    • webkit2:
      • 主要包含两种类型目录

        • 各个进程代码:

          • web进程、UI进程、网络进程、插件进程以及它们的共享代码。
        • 各移植的简单主函数入口:
          • 一个构建webkit2接口的简单的可执行程序。
基于Blink的Chromium浏览器结构 及 代码结构
    • content模块和content API,是chromium 对渲染网页功能的抽象。

      • 沙箱模型、跨进程GPU硬件加速、众多HTML5功能在content层实现
    • content模块和content API 将渲染机制、安全机制、插件机制封装一个接口层。
      • 接口层被上层模块使用,内部调用包括了chromium浏览器、content shell,外部包括CEF(chromium enbedded framework)、opera浏览器等。

        • chromium浏览器拥有完整功能,但是外壳没开源?
        • content shell 是使用content shell包装的简单的,用于验证功能有效性和作为开发的demo。
          • android 中,开发者大多依赖 content shell 进行移植开发。
    • android webview 为了满足android 系统的webview设计,即利用chromium 替换原来的android 默认webview。(这都是历史了吧)
  • 多进程模型:

    • chromium常用多进程模型:

      • 连接线代表IPC,可以看到NPAPI插件没有定义使用FPU进行加速的接口。
    • 多进程模型的好处:

      • 避免单个页面的不响应或崩溃影响整个浏览器的稳定性。
      • 第三方插件崩溃不影响浏览器稳定性。
      • 方便了安全模式的实施,沙箱模型基于多线程。
    • 主要进程类型:

      • browser 进程:浏览器主进程,负责浏览器界面显示、页面管理,是其他类型进程的祖先,负责他们的创建与销毁。仅有一个。
      • renderer 进程: 网页渲染进程,renderer进程数量和网页数量的关系不一定,根据配置改变。沙箱模型启动情况下,该进程会发生变化。
      • 插件进程: 每个类型插件创建一次,多个网页使用一种类型插件时,为每个使用者创造一个实例,即插件进程是被共享的。
      • GPU进程:最多一个,用于对3D图形加速调用的实现。
    • 进程模型特征:

      • browser 进程和页面渲染分开,保证页面渲染导致崩溃不影响浏览器主界面崩溃。
      • 每个网页独立进程,保证页面互不影响
      • 插件进程独立,保证插件问题不影响浏览器主界面和网页。
      • GPU硬件加速进程也独立。
    • render 进程创建的类型有:

      • Process-per-site-instance
      • Process-per-site
      • Process-per-tab
      • Single process
    • renderer和 browser进程:

      • renderer和 browser进程代码层次如图:

        • 首先是webkit接口层, 一般基于webkit接口层的浏览器直接在上面构建,不引入复杂的多进程架构。
        • 然后是黏附层,是个桥阶层,用于处理chromium和webkit内部的不一致。
        • renderer 主要处理进程间的通信,接受来自browser 进程的请求,并调用相应webkit 接口层。
        • browser进程 中的 rendererHost 与renderer 对应, 用于处理和renderer 之间的IPC。
        • web contents 表示网页内容。
  • 多线程模型:

    • browser进程:多线程为了保持用户界面的高响应度,保证UI线程对用户操作的响应

      • 主要有主线程、IO线程、还有很多其他线程,用于处理视频、存储、网络、文件、音频、浏览历史等,因为可能这些操作可能阻塞,所以需要置于单独的线程
    • renderer进程: 将渲染过程管线化,利用多核优势。
      • 将blink的渲染过程解耦,创建新线程,利用CPU多核能力,加速渲染,像流水线处理一样,提高并发性。
    • 网页加载和渲染过程的基本工作方式:
      1. browser进程收到用户请求,UI线程处理,将任务转给IO线程,然后任务传递到 renderer 进程。
      2. renderer进程 的IO线程经过简单解释后交给渲染线程。 渲染线程加载网页并渲染网页,其中可能需要browser进程获取资、需要GPU进程来帮助渲染。 最后renderer 进程将结果通过IO线程传递给browser进程。
      3. browser进程 将结果绘制出来。
    • 线程同步与通信:
      • 多线程容易造成死锁、资源竞争与冲突。chromium 使用事件、任务传递机制,仅在不得已时才使用锁或者线程安全对象

        • 线程内部的消息和任务,在第九章 js引擎部分讲解。
  • content 接口:

    • 提供了一层对多进程进行渲染的抽象接口。为了支持HTML5功能、GPU硬件加速功能、沙箱机制。
    • 相关部分分为:embedder调用的接口、embedder应该实现的回调接口(用于参与具体实现逻辑或事件监听)。
      • APP:包括了应用程序或进程的创建与初始化,被所有进程使用,处理一些进程公共操作。
      • Browser:HTML5功能等的实现参与,content模块需要调用他们实现HTML5功能;
      • Common:一些renderer、browser 共享的公共接口。
      • Plugin:通知embedder plugin进程何时被创建的接口类。
      • Renderer
      • Utility:
  • chromium 代码结构:

    • chromiumOS 是一个基于web的OS,仅支持web网页和web 应用程序。
    • 还有个很重要的目录:third_party
      • 里面包含了Blink和一些依赖的第三方开源项目。
    • content 目录基本对应了多进程模型中的各种进程类型。
WebKit2 架构、模块
  • webkit2 是一套全新结构与接口,同chromium一致,讲渲染过程放在单独进程中,独立于用户界面。

    • 这里的web进程对应chromium 的rederer进程。UI进程对应chromium 的browser 进程。
  • webkit2 和chromium 多进程模型和接口。
    • webkit 和chromium 多进程的关系:

      • renderer进程直接调用webkit 接口。
      • content接口允许应用程序注入,并参与content之下各个进程的内部逻辑。
    • webkit2 接口希望将多进程结构隐藏,不让应用程序纠缠内部细节。
    • webkit 是给 chromium提供content 接口以便构建浏览器,其本身目标不是提供嵌入式接口。

chromium 的渲染

  • 渲染:将web content,转换为正确的 openGL 调用,让其显示在屏幕上。

渲染过程

  1. 样式计算 :渲染进程的主线程解析CSS,确定每个DOM节点的计算样式
  2. 布局 - layout : 渲染进程知道每个节点的文档结构和样式。布局是查找元素几何的过程。
    • 布局过程主线程 遍历DOM并计算样式,并创建布局树(layout tree, 包含坐标和边界框大小等信息)。
      确定页面布局的挑战:
    • 从上到下的块流须考虑字体的大小以及在哪里划分它们,最终影响段落的大小和形状,影响下一段的位置
      CSS可以使元素浮动到一侧,屏蔽溢出项,并更改写入方向
  3. 绘制 - Paint : 主线程遍历布局树以创建绘制记录(知道元素的大小,形状和位置,但是不知道绘制的顺序。)
  4. 合成 :
    • 合成是一种将页面的各个部分分层,分别栅格化,并在合成器线程的单独线程中合成为页面的技术。
    • 如果发生滚动,图层已经被栅格化需要合成一个新帧。通过移动图层和合成新帧,可以以相同的方式实现动画。
    • 浏览器知道文档的结构、每个元素的样式、页面的几何形状和绘制顺序,需将信息转换为屏幕上的像素,称为光栅化
  • 渲染难点:

    1. 布局树变化:在每个步骤中,前一个操作的结果用于创建新数据。例如,如果布局树中的某些内容发生更改,则需要为文档的受影响部分重新生成“绘制”顺序。
    2. 动画:动画对人眼来说会很平滑(视觉停留效应),但是如果动画错过了两者之间的帧或程序运行JS时,则页面将出现卡顿。需要将JS操作划分成小块,并安排在每个帧上运行

渲染步骤

  1. 渲染的第一步需要解析HTML的标签,生成能反映该HTML结构的对象模型,即DOM(文档对象模型,document object model )。 V8 引擎 通过blindings system 将DOM简单包装后 暴露为:DOM web APIs。
  • web content 有 HTML、CSS、JS、video、etc。
  • DOM:用于作为页面的内部表示、将查询或修改渲染的API暴露给JS。
    • V8 引擎 通过blindings system 将DOM简单包装后 暴露为:DOM web APIs
  • CSS 的样式属性(style propertys) 是web 开发者用来自定义DOM元素渲染的控制选项(control knob)
    • 样式属性很多,怎么确定样式作用于哪些元素也越来越复杂,(样式可能被多重规定,可能有冲突)。
    • 样式引擎用于整理这些样式属性。

HTML

  • HTML的标签给了文档赋予了语义上的层级结构。

    • 如 div 可以分为多个文本段落
  • HTML标签可以嵌套

DOM

  • DOM:

    • 作为页面的内部表示;
    • 作为暴漏给JS 以查询、修改的API;
  • V8 引擎 通过blindings system 将DOM简单包装后 暴露为:DOM web APIs。

CSS

  • CSS 的selector 选择的就是DOM树的节点,然后将对应的 property 应用于对应节点。
  • web 开发者用 properties 定义DOM元素 的渲染。(形变、格式、颜色、边距、位置等)
    • 解析CSS 难点在于解析 property具体作用于哪些元素。

浏览器架构

  • 整体架构:

    • 操作系统:WebKit可以运行在不同的操作系统上,如Chromium浏览器支持Windows、Linux、Android等系统;
    • 第三方库:这些库是WebKit运行的基础,包括2D图形库、3D图形库、网络库、存储库、音视频库等;
    • WebCore:WebKit加载和渲染网页的基础,是不同浏览器所使用的WebKit中共享的部分,包括HTML解析器、CSS解析器、SVG、布局、渲染树等等;
    • JavaScript引擎:JavaScript解析器,WebKit默认的引擎是JavaScriptCore,Google的Blink为V8引擎;
    • WebKit Ports:WebKit中的移植部分,包括网络栈、音视频解码、硬件加速等模块,这部分对WebKit的功能和性能影响比较大。
    • WebKit嵌入式接口:WebKit对外暴露的接口层,这个接口是提供给浏览器调用的,如给chromium调用,因为接口与具体的移植也有关系,所以中间会有一个WebKit绑定层
  • JavaScriptCore(用于Safari)

    • JavaSript Parser,JSON Parser
    • 字节编译器:使用内部字节码格式
    • 汇编程序:在运行时使用代码修补 - >它需要可写代码内存
    • 数据流图:基于编译时推测优化生成代码的新举措
    • 解释器:运行生成的字节码
    • Regexp引擎:支持JIT
    • 垃圾收集器:标记和扫描
    • 运行时:所有JS全局对象(日期,字符串,数字等)
    • 调试器,Profiler
  • WebCore

    • 资源加载器:HTML和XML解析器,DOM
    • SVG和SMIL
    • CSS:分析器,选择器,动画
    • 渲染和布局
    • 绑定生成器:IDL文件:JSC,V8,ObjC
    • HTML5:音频,视频,画布,WebGL,通知功能
    • WebInspector
    • 平台集成:图形,字体,声音,视频

浏览器工作原理概述

先后经过页面导航、渲染、资源加载、样式计算、布局、绘制、合成到栅格化,最后完成GPU展示

  • 浏览器内核经过了 Loader、Parser、Layout和Paint模块

    • Loader 负责处理HTTP请求、网络资源缓存。

      • 通常有两个IO管道,一个负责页面下载,另一个负责外链资源下载(js、CSS、image)。
      • 因为JS可能改变页面,因此需要保持执行顺序和下载管道后续处理的阻塞
    • Parser 负责解析HTML页面,从HTML文本HTML语法树文档对象树(DOM) 的映射过程。

      • HTML 语法树生成主要包括词法解析和语法解析
      • 词法解析:依靠词法规则将HTML 文本分割成大量标记(token)。(词法规则如正则表达式);
      • 语法解析:按照语法规则匹配token序列生成语法树。(通产有自上而下、自下而上两种匹配方式);
      • CSSParse解析CSS后,将CSS解析为对应树结构。 // problem
      • js由单独的脚本引擎解析执行。用于动态改变DOM树,如为DOM接天添加事件响应处理函数,即根据时间或事件映射一颗DOM树到另一个DOM树。

      简单的说,Parser将页面文本转换为带CSS style、会相应自定义事件的styled DOM树。

      • layout 负责排版。包括创建布局树(渲染树、render tree)、计算布局。

        • 布局树与DOM树同时存在于内核,render树是DOM树的排版表示,用以计算可视DOM节点的布局信息(坐标、高、宽)和后续阶段的绘制显示。

          • // 并非所偶的DOM节点都可视,这些节点没有在render树中对应,如标签。// DOM树可视节点的CSS style 就是对应render树节点的style。
        • 计算布局就是安排和计算页面中每个元素大小位置等几何信息的过程。

          • HTML采用流式布局模型,基本原则为页面元素在顺序遍历过程中依次从左到右、上到下的排列方式确定各自位置 区域。

参考

  • WebKit技术内幕

  • 朱永盛 csdn

  • www.webkit.org

  • 深入理解Android:WebKit卷

【读书笔记】【WebKit 技术内 幕(一)】浏览器架构与浏览器内核;chromium、webkit和blink的渲染过程;chromium、webkit的架构与代码结构;webkit2架构相关推荐

  1. 【读书笔记】【WebKit技术内 幕(三)】GPU硬件加速渲染、canvas与WebGL、 JavaScript与JavaScript 引擎、JavaScriptCore与V8

    文章目录 前言 Something great 第8章 硬件加速机制 硬件加速基础 -- *** Chromium的硬件加速机制 -- *** 其他硬件加速模块 第9章 JavaScript引擎 Ja ...

  2. 【读书笔记】【WebKit技术内 幕(二)】Chromium Webkit资源加载与网络栈、DOM树、HTML解释器、影子DOM、CSS解释器和样式布局、网页层次与渲染、绘图上下文、

    文章目录 前言 Something great 第4章 资源加载和网络栈 Webkit 资源加载 Chromium多进程资源加载 Chromium 网络栈 第5章 HTML解释器和DOM模型 DOM模 ...

  3. 《MySQL技术内 幕 InnoDB存储引擎》读书笔记

    MySQL技术内幕 LnnoDB存储引擎 读书笔记 1 MySQL 体系结构和存储引擎 1.1 数据库和数据库实例 数据库:物理操作系统文件活其他形式文件类型的集合 ​ 实例:MySQL数据库是由后台 ...

  4. 读书笔记:技术的本质-技术是什么,它是怎样进化的 (布莱恩•阿瑟)

    读书笔记算不算原创? - page 30 然而.作为人类,我们实际上不应该和技术如此紧密地结合,而是应该和其它什么东西融合得更为紧密,那就是自然. 在最深的层次上.人的存在应该和自然,和我们最初的环境 ...

  5. 读书笔记:技术的本质-技术是什么,它是如何进化的 (布莱恩•阿瑟)

    读书笔记算不算原创? - page 30 然而,作为人类,我们实际上不应该和技术如此紧密地结合,而是应该和其他什么东西融合得更为紧密,那就是自然.在最深的层次上,人的存在应该和自然,和我们最初的环境, ...

  6. 【JavaScript忍者秘籍】读书笔记之第一章:无所不在的JavaScript、第二章:运行时的页面构建过程

    1.1 "理解"JavaScript语言 为什么要深入理解原型? Babel和Traceur是什么? 为什么它们对现在的JavaScript开发者至关重要? 1.2 理解浏览器 2 ...

  7. MySql技术内 幕:InnoDB存储引擎 读书笔记

    书名 <MySql技术内幕:InnoDB存储引擎> 作者 姜承尧 书摘 第一章:MySQL体系结构和存储引擎 定义数据库和实例: 定义数据库和实例 数据库:文件的集合,frm.MYD.MY ...

  8. 推荐一本Vue源码阅读书籍《Vue.js技术内.幕》

    1. 概述 这幅图大家应该都很清楚: 但这个过程在Vue框架中是如何实现的呢? 是否考虑过如果是自己,该如何设计呢?而这本<Vue.js技术内幕>就是一本非常好的关于Vue框架源码学习的书 ...

  9. 专栏《乔新亮的CTO成长复盘》读书笔记(技术架构篇)

    架构决策能力不但非常关键,而且是技术管理者最重要的能力和职责之一,而且职级越高就越重要. 很多所谓的"技术债",也就是由一次次的决策失误不断累加而成的. 管理者要能充分利用自己的技 ...

最新文章

  1. 如何用CSS制作横向菜单?
  2. 一种缘于积木游戏的思维
  3. 锋利的JQuery —— DOM操作
  4. 安装OpenLDAP
  5. Apache Flink 零基础入门(十九)Flink windows和Time操作
  6. Spring框架学习3:bean元素属性
  7. Asp.net基础概念之 委托
  8. HTML5文件上传插件 Huploadify V2.1发布
  9. sprint() 和 snprint()
  10. [软件开发] 基于Qt开发的一款免费取色器软件 - TakeColor
  11. 2021年个人年终总结
  12. tcl电视显示服务器异常1500,TCL 智能液晶电视常见故障分析检修实例
  13. Linux之压缩解压缩
  14. mysql 木马_通过mysql写入一句话木马
  15. Matlab中FrechetDistance方法实现---比较两条曲线的相似性,并绘制曲线
  16. seo与sem的关系和区别
  17. win10修改user文件夹名称
  18. 2020 年高中数学联赛试题及解析
  19. 微机原理-第五章 微型计算机接口和外设的数据传输
  20. Java初学者轻便易于上手的小项目(2020最新)

热门文章

  1. Android Webview完美支持播放各种视频。
  2. Wireshark抓取RTP流中的语音文件到本地
  3. 编程时的编码、编码解码、编码乱码问题(ASCII、GBK、Unicode、UTF-32、UTF-8)
  4. 根据UTC和经纬度计算当地年份、季节、时区等的时间类工具
  5. 2020-2021学年——图像图形编程实践实验2_图像的基本运算
  6. 腾讯WeTest开通微信视频号啦
  7. 高压流变仪用TESCOM ER5000压力控制系统的国产化替代方案
  8. DISRUPT 快的原因
  9. Python selenium Browsermob-Proxy获取网页加密请求参数的方法及过程
  10. 【线激光扫描三维成像】原理介绍