Coder Social home page Coder Social logo

blogs's Introduction

blogs's People

Contributors

jiaoguanwen avatar

Stargazers

 avatar

Watchers

 avatar  avatar

blogs's Issues

git fetch之后?

一直以来,一直用的都是pull,现在用一用fetch,fetch的话是拉取特定分支,比如git fetch origin branch_name,这时是拉取了这个远程分支,但是没有操作,后续可以进行diff,checkout操作,git diff origin/branch_name,或者git checkout branch_name,这样会创建该分支。

如何更新fork的项目?

如果需要更新fork的项目,可以在自己fork的项目下create a New pull request,这时左边会是原作者的项目,右边是你fork的项目,但是这是github对于fork项目的默认pr配置,即向原库提交pr,但此时我们是更新自己fork的库,左右替换一下左右两边的来源即可完成pr,然后自己merge即可。

【译】现代浏览器内部窥探(部分二)

导航里发生了什么

这是我们探究Chrome工作原理四篇文章中的第二篇。在上一篇文章中,我们看到了不同的进程和线程是如何处理浏览器的不同部分。在这篇文章中,我们会深入探究每一个进程和线程为了展示一个网站是如何交流的。

让我们看一个网络浏览中的简单例子:你输入一个URL给浏览器,然后浏览器从互联网获取数据并展示页面。在这篇文章中,我们将会聚焦于用户请求一个站点,和浏览器准备渲染页面这部分,也就是常说的导航。

它开始于一个浏览器进程

如我们在部分一:CPU,GPU,内存和多进程结构中了解的,一个tab之外的所有东西都是由浏览器进程处理的。浏览器进程有线程,比如UI线程,它绘制了浏览器的按钮和输入框,网络线程,它处理网络以从互联网获取数据,存储线程,控制文件权限等。当你在地址栏输入一个URL,你的输入就是由浏览器进程的UI线程处理的。
Browser Process
图1:浏览器的顶部UI,和底部的浏览器进程和UI,网络,存储线程。

一个简单的导航

步骤一:处理输入

当一个用户在地址栏开始输入,对于UI线程的第一件事就是“这个是搜索查询还是URL?”。在Chrome中,地址栏也是搜索框,所以UI线程需要解析输入以决定是带你去搜索引擎还是你请求的网站。
UI Thread
图2:UI线程正在询问输入是搜索内容还是URL?

步骤二:开始导航

当一个用户按下Enter键,UI线程初始化一个网络请求去获取站点内容。tab的拐角就会出现加载框,网络线程就会通过适当的协议,如DNS查找,为请求建立TLS连接。
Network Thread
图3:UI线程告诉网络线程导航到mysite.com

在这时,网络线程可能会接到来自服务器的重定向响应头比如HTTP301。这种情况下,网络线程就会告知UI线程,服务器要求重定向。然后,另一个URL请求就会初始化。

步骤三:读取响应

一旦响应体(有效载荷)开始进来,有必要的话,网络线程会看一下数据流的前几个字节。响应的内容类型(Content-Type)一般会指明数据的类型,但是一旦它丢失或者错误,媒体类型嗅探到这就结束了。就像在源码中注释提到的那样这是一个棘手的业务。你可以看一下源码去了解不同的浏览器是处理内容类型/有效载荷的。
Content-Type
图4:响应头包含了内容类型,有效载荷则包含了实际数据。

如果响应是一个HTML文件,那么下一步就是将数据交给渲染进程,但是如果是一个zip文件,或者其他文件,那就意味着这是一个下载请求,所以它们需要把数据交给下载管理器。
Network Thread
图5:网络进程正在询问响应数据是不是来自安全站点的HTML。

这就是安全浏览检测。如果域名和响应数据看起来符合一个已知的恶意网站,那么网络线程就会弹出一个警告页面。额外的,跨源读取拦截(CORB)检测也会启动以确保敏感跨站数据不会被渲染进程拿到。

步骤三:找一个渲染进程

一旦所有的检测通过,网络线程就可以确保浏览器可以导航到请求的网站,网络线程告诉UI线程数据准备好了。UI线程就会找一个渲染进程去继续渲染网页。
Network Thread tell UI Thread
图6:网络线程告诉UI线程找一个渲染进程

【译】现代浏览器内部窥探(部分一)

点此看原文
CPU,GPU,内存,和多进程结构
在这个4部分的系列博客中,我们将会从高级体系结构(High-Level Architecture)到渲染管线(Rendering Pipeline)的细节来一探Chrome浏览器。如果你想知道浏览器是怎么把你的代码变成一个功能网站,或者你不确定一个为什么一个特定的技术可以用来做性能提高,那么这个系列的博客就很适合你。
在该系列的部分1中,我们将会看到一些核心术语和Chrome的多进程结构。
注意: 如果你对CPU/GPU以及进程/线程相当熟悉那么你可以跳过这里到浏览器结构
计算机的核心是CPU和GPU
为了理解浏览器的运行环境,我们首先需要理解一些计算机的东西和它们能做什么。
CPU
首先是**处理单元(Central Processing Unit),即CPU。CPU可以看做是你计算机的大脑。一个CPU核心,就像如图所示的一个办公人员,当任务进来时,可以一个接一个处理很多不同的任务。当它知道怎么去回复一个消费者的响应,它能处理从数学到艺术的所有事情。以前,大部分的CPU是一个单独的芯片。一个核心就像另一个CPU住在同一个芯片上。现代硬件设备中,一般会有不止一个核心,它们给你的手机和笔记本提供更多的算力。
CPU
图1:4个CPU核心就像办公人员坐在自己的工位,当任务进来时,处理他。

GPU
图形处理单元(Graphics Processing Unit),即GPU,是计算机的另一部分。不像CPU,GPU擅长处理简单但是能多核同时运行的任务。就像名字表明的那样,它最先开发用于处理图形。这也就是为什么在图形环境中“使用GPU”或”GPU加速“与快速渲染和柔顺交互有关。近些年来,随着GPU加速计算的发展,越来越多的计算单独跑在GPU上成为可能。
GPU
图2:很多带扳手的GPU核心表明它们处理有限的任务

当你在计算机或者手机打开一个应用,CPU和GPU就为该应用提供力量。通常,应用运行在由CPU和GPU支持的操作系统的机制上。
Application
图3:计算机的三层结构。硬件机器在下,操作系统在中间,应用在上面。

在进程和线程上执行程序
在深入浏览器的结构之前,另一个要讨论的概念就是进程和线程。一个进程可以描述为一个应用的执行程序。一个线程就是在进程中,执行进程程序部分的东西。
当你打开一个应用,一个进程就创建了。程序可能会创建线程帮助它工作。操作系统给予进程一块内存以便让他工作,而且所有应用相关的状态就存储在那块私有内存空间里面。当你关闭应用,进程就会消失,同时操作系统也会释放那块内存。
Process andThread
图4:进程就像一个有边界的盒子,线程就像抽象的鱼,在进程中畅游。
Memory
图5:进程使用内存空间并存储应用数据

一个进程可以向操作系统申请另一个进程去做一些不同的工作。在这种情况下,不同部分的内存就会分配给新的进程。如果两个进程需要交流,他们可以使用IPC(Inter Process Communication)。许多应用被设计为这样:当一个工作进程无响应时,他可以无需停止应用中不同部分的其他进程而重启。
IPC
图6:进程间通信

浏览器结构
那么网络浏览器是怎么使用进程和线程的呢?它可能是一个进程包含多个线程或者多个进程和少量线程,以及进程间通过IPC交流。
Browser Process
图7:不同浏览器的进程/线程结构

重要的一点是这些不同的结构实现的细节。这里如何构建一个网络浏览器没有标准的规范。一个浏览器的实现可能和另一个完全不同。

在这一系列的博客文章中,我们将会使用Chrome近期的结构,如下图所示。

在顶层是浏览器进程,和负责应用其他部分的进程相互配合。对于渲染进程来说,会创建多个,并且分配到每一个tab。直到最近,Chrome会尽量给每一个tab一个进程;但现在,它正在尝试给每一个站点一个进程,包括iframes(见站点独立).
Browser Process Architecture
图8:Chrome的多进程结构。可以看到图中渲染进程有多层,代表Chrome在每个tab运行了多个渲染进程。

每个进程控制什么?

下面的这个表格描述了每一个Chrome进程,以及它控制什么:

每个进程控制什么
浏览器控制应用的“chrome”部分,包括地址栏,书签,前进后退按钮。也处理网络浏览器看不见、权限的部分,比如网络请求和文件权限
渲染控制tab里网页显示的一切
插件控制网页使用的一切插件,比如flash
GPU独立处理来自其他进程的GPU任务。它被分成了不同的进程,因为GPU们处理来自不同app的请求并将它们绘制在同一层上

Different Process
图9:不同的进程负责浏览器界面的不同部分。

这里还有一些其他进程,比如拓展进程和工具进程。如果你想看你的Chrome有多少进程在运行,点击右上角的选项按钮图标image,选择更多工具,然后选择任务管理器。这将会打开一个窗口,其中展示了当前正在运行的进程列表和CPU/GPU的使用情况。

Chrome多进程结构的优点

前面,我提到Chrome使用了多渲染进程。在大多数简单的情况下,你可以想象每一个tab都有自己的渲染进程。假如你打开了三个tab,并且每一个tab都是运行独立的渲染进程之下。如果其中的一个tab无响应,那么你可以关闭这个无响应的tab,然后换到其他tab,并且其他tab都是正常的。如果所有的tab都运行在同一个进程下,当其中一个tab无响应时,所有的tab都会无响应,这很不好。
Multiple Process
图10:如图所示,多进程tab

另外一个把浏览器的工作分配到多个进程上的好处就是安全和沙箱化。因为操作系统提供了一种方法限制进程的权限,浏览器对于特定的功能,可以沙箱化特定的进程。比如,Chrome 浏览器限制处理任意用户输入的进程(如渲染器进程)对任意文件的访问。

因为进程有它们自己的私有内存空间,他们经常包含了通用基础设施的备份(如Chrome的JavaScript引擎,V8)。这意味着更多的内存占用,因为他们无法像同一进程中的线程那样共享上下文资源。为了节省内存,Chrome对于它能创建的进程数添加了限制。限制的数字取决于你的设备有多少内存和CPU资源,但是当Chrome到达这个限制数时,它开始把同一个网站的多个tab运行在同一个进程下。

节省更多的内存-Chrome中的服务化

同样的实现也被用在了浏览器进程上。Chrome经过结构变化,把浏览器程序的每一个部分作为一个服务以便于可以简单的把他们分到不同的进程中或者整合成一个。

一般来讲,当Chrome运行在强大的硬件上,它可能会把每一个服务拆分到不同的进程中以获得更高的稳定性,但是当它在资源吃紧的设备上,Chrome会将服务聚合到一个进程中以节省内存占用。在内存紧张的情况下,服务聚合这种实现在此之前在一些平台上已经使用,比如Android。
Servicification
图11:Chrome的服务化(将服务移动到多个进程和一个浏览器进程)

逐帧渲染进程-站点独立

站点独立是一个在Chrome中近期将会出现的功能,它会在每一个跨站的iframe上运行独立的渲染进程。我们已经讨论过每个tab模型会分配一个渲染进程,这允许跨站的iframe运行在一个单独的渲染进程,并在不同的站点之间共享内存空间。在同一个渲染进程下运行a.com和b.com可能看起来okay。同源策略是web的核心安全策略;它保证了一个站点未经准许不能获取到其他站点的数据。绕过这个策略是安全攻击的主要目标。进程独立是最有效的方式去隔离站点。随着Meltdown and Spectre病毒的出现,我们需要利用进程来隔离站点这一点也变得越来越清晰。桌面版Chrome从67版本开始默认开启站点独立,tab中的每一个跨站的iframe都会有一个分离的渲染进程。
Site Isolation
图12:站点独立。一个站点中多个渲染进程指向了iframe。

开启站点独立已经是一个多年来的工程尝试。站点独立不像分配不同的渲染进程那样简单;它本质上改变了iframe之间的交流方式。在一个包含iframe的不同进程的页面下,打开开发者工具,意味着开发者工具必须实现后台工作来让它们看起来无缝。甚至在页面中一个简单的Ctrl+F搜索一个关键字,就意味着要搜索不同的渲染进程。你可以看到为什么浏览器工程师会认为站点独立是一个重大的里程碑了。

总结

在这篇文章中,我们了解了浏览器的高层结构以及多进程结构的优点。我们也谈到了Chrome中的服务化和站点独立,这些深深依赖于多进程结构。在下一篇文章中,我们将会深入了解,这些进程和线程为了显示一个网页,会发生什么。

React Components, Elements, and Instances

React Components, Elements, and Instances

组件,他们的实例和元素之间的区别,困扰着很多React新手。为什么有3个不同的术语来指代绘制在屏幕上的东西?

管理实例

如果你刚接触React,你之前可能工作中只用到组件类和实例。比如,你可能通过创建一个类声明了一个按钮Button组件。当app运行时,你可能会有多个这个组件的实例在屏幕上,每一个都有它自己的属性和本地状态。这是传统的面向对象UI编程。那为什么要介绍元素呢?

在传统的UI模型中,关注创建和销毁子组件实例取决于你自己。如果一个表单组件想要渲染一个按钮组件,他需要创建一个他的实例,然后手动的保持它和新信息的更新。

class Form extends TraditionalObjectOrientedView {
  render() {
    // Read some data passed to the view
    const { isSubmitted, buttonText } = this.attrs;

    if (!isSubmitted && !this.button) {
      // Form is not yet submitted. Create the button!
      this.button = new Button({
        children: buttonText,
        color: 'blue'
      });
      this.el.appendChild(this.button.el);
    }

    if (this.button) {
      // The button is visible. Update its text!
      this.button.attrs.children = buttonText;
      this.button.render();
    }

    if (isSubmitted && this.button) {
      // Form was submitted. Destroy the button!
      this.el.removeChild(this.button.el);
      this.button.destroy();
    }

    if (isSubmitted && !this.message) {
      // Form was submitted. Show the success message!
      this.message = new Message({ text: 'Success!' });
      this.el.appendChild(this.message.el);
    }
  }
}

这些是伪代码,但是它或多或少结束了当你写组合UI时一贯的面向对象的方式比如使用Backbone类库。

每一个组件实例都必须保持着他对DOM节点和子组件实例的引用,然后在合适的时机创建、更新和销毁它们。代码行数的增长是组件可能状态数量的平方,父组件对它们的子组件实例有着直接的控制,这就使得想要在未来分开他们很难。

那么React是怎么不同于此的呢?

元素描述着树

在React中,这里是元素来解决这个问题。元素是一个描述组件实例或者DOM节点和它期望的属性的对象字面量。他只包含组件类型(例如,一个Button),他的属性(例如,他的color),以及他里面的每一个子元素等信息。

一个元素不是一个实际的实例。有点像一种你告诉React你希望屏幕上展示什么的方式。你不能调用元素伤的任何方法。他只是一个拥有两个字段type(string | ReactClass)和props(Object)的不变的描述对象。

DOM元素

总结

如何打乱一个数组?

打乱一个数组,有时候会有这种需求,比如歌曲列表的随机播放等,那么该如何打乱这个数组呢?

获取一个合理范围的随机数

获取一个随机数的话,首先会想到Math对象的random方法,但是这个方法返回一个大于等于0小于1的浮点数,即值区间为[0, 1),但是作为数组下标的话,这个值应该是一个大于等于0的整数,所以我们需要处理一下,如下代码

function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min)
}

这段代码能让我们拿到一个介于minmax之间的整数,这样的话,这个整数我们就能拿来获取一个随机的数组索引值。

打乱数组

打乱数组的话,如下代码

function shuffle(arr) {
  let _arr = arr.slice()
  for (let i = 0; i < _arr.length; i++) {
    let j = getRandomInt(0, i)
    let t = _arr[i]
    _arr[i] = _arr[j]
    _arr[j] = t
  }
  return _arr
}

这段代码利用获取到的随机数,打乱数组。同时注意,打乱数组不应该修改原数组。

code

GAWAE-FCWQ3-P8NYB-C7GF7-NEDRT-Q5DTB-MFZG6-6NEQC-CRMUD-8MZ2K-66SRB-SU8EW-EDLZ9-TGH3S-8SGA
[email protected]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.