前端精髓

关注前端开发核心技术


  • Home

  • Archives

什么是阻塞和非阻塞I/O

Posted on 2019-06-10

在听到Node的介绍时,我们时常会听到异步、非阻塞、回调、事件这些词语混合在一起推介出来,其中异步与非阻塞听起来似乎是同一回事。从实际效果而言,异步和非阻塞都达到了我们并行I/O的目的。但是从计算机内核I/O而言,异步/同步和阻塞/非阻塞实际上是两回事。

操作系统内核对于I/O只有两种方式:阻塞与非阻塞。在调用阻塞I/O时,应用程序需要等待I/O完成才返回结果

阻塞I/O的一个特点是调用之后一定要等到系统内核层面完成所有操作后,调用才结束。以读取磁盘上的一段文件为例,系统内核在完成磁盘寻道、读取数据、复制数据到内存中之后,这个调用才结束。

阻塞I/O造成CPU等待I/O,浪费等待时间,CPU的处理能力不能得到充分利用。为了提高性能,内核提供了非阻塞I/O。非阻塞I/O跟阻塞I/O的差别为调用之后会立即返回

操作系统对计算机进行了抽象,将所有输入输出设备抽象为文件。内核在进行文件I/O操作时,通过文件描述符进行管理,而文件描述符类似于应用程序与系统内核之间的凭证。应用程序如果需要进行I/O调用,需要先打开文件描述符,然后再根据文件描述符去实现文件的数据读写。

此处非阻塞I/O与阻塞I/O的区别在于阻塞I/O完成整个获取数据的过程,而非阻塞I/O则不带数据直接返回,要获取数据,还需要通过文件描述符再次读取。

非阻塞I/O返回之后,CPU的时间片可以用来处理其他事务,此时的性能提升是明显的。但非阻塞I/O也存在一些问题。由于完整的I/O并没有完成,立即返回的并不是业务层期望的数据,而仅仅是当前调用的状态。为了获取完整的数据,应用程序需要重复调用I/O操作来确认是否完成。这种重复调用判断操作是否完成的技术叫做轮询,下次我们就来简要介绍这种技术。

任意技术都并非完美的。阻塞I/O造成CPU等待浪费,非阻塞带来的麻烦却是需要轮询去确认是否完全完成数据获取,它会让CPU处理状态判断,是对CPU资源的浪费。

Hello World

Posted on 2019-06-10

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

React中PureComponent原理

Posted on 2019-06-09

PureComponent 会对 props 和 state 进行浅层比较,并减少了跳过必要更新的可能性。

React.PureComponent 与 React.Component 很相似。

两者的区别在于 React.Component 并未实现 shouldComponentUpdate(),而 React.PureComponent中以浅层对比 prop 和 state 的方式来实现了该函数。

如果赋予 React 组件相同的 props 和 state,render() 函数会渲染相同的内容,那么在某些情况下使用 React.PureComponent 可提高性能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import React from 'react';
import ReactDOM from 'react-dom';

class Counter extends React.Component {
state = {
count: 0
}
handleClick = () => {
this.setState({
count: this.state.count + 1
})
}
render() {
return (
<div>
<Title title='计数器'></Title>
<span>
{ this.state.count }
</span>
<button
onClick={this.handleClick}>
+1
</button>
</div>
);
}
}

class Title extends React.Component {
render() {
// 检查是否多次打印
console.log('Title render')
return (
<p>{this.props.title}</p>
);
}
}

ReactDOM.render(<Counter />, document.getElementById('root'))

上面演示的代码中 Counter 组件中使用了 Title 组件,Counter 组件每次修改状态都会导致 Title 组件重新渲染。可以看到 console 语句多次打印出 Title render。如果不想让 Title 组件多次渲染,就需要让 Title 组件继承 PureComponent 组件。

开始使用

  1. 类组件使用 PureComponent
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import React from 'react';
import ReactDOM from 'react-dom';

class Counter extends React.Component {
state = {
count: 0
}
handleClick = () => {
this.setState({ count: this.state.count + 1 })
}
render() {
return (
<div>
<Title title='计数器'></Title>
<span>
{ this.state.count }
</span>
<button
onClick={this.handleClick}>
+1
</button>
</div>
);
}
}

class Title extends React.PureComponent {
render() {
console.log('Title render')
return (
<p>
{ this.props.title }
</p>
);
}
}

ReactDOM.render(<Counter />, document.getElementById('root'))
  1. 函数组件使用 memo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Counter extends React.Component {
state = {
count: 0
}
handleClick = () => {
this.setState({
count: this.state.count + 1
})
}
render() {
return (
<div>
<Title title='计数器'></Title>
<span>
{ this.state.count }
</span>
<button
onClick={this.handleClick}>
+1
</button>
</div>
);
}
}
const Title = React.memo(props => {
console.log('Title render')
return <p>{props.title}</p>
})
  1. memo 的原理
1
2
3
4
5
6
7
8
9
10
function memo (Func) {
class Proxy extends React.PureComponent {
render() {
return (
<Func {...this.props} />
);
}
}
return Proxy
}
  1. PureComponent 的原理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import React, { Component } from 'react';

function shallowEqual(obj1, obj2) {
if (obj1 === obj2) {
return true
}
let noObj1 = typeof obj1 !== 'object' || obj1 === null
let noObj2 = typeof obj2 !== 'object' || obj2 === null
if (noObj1 || noObj2) {
return false
}
let keys1 = Object.keys(obj1)
let keys2 = Object.keys(obj2)
if (keys1.length !== keys2.length) {
return false
}
for (const key of keys1) {
let equalKey = obj1[key] === obj2[key]
if (!obj2.hasOwnProperty(key) || !equalKey) {
return false
}
}
return true
}

class PureComponent extends Component {
shouldComponentUpdate(nextProps, nextState) {
let equalProps = shallowEqual(this.props, nextProps)
let equalState = shallowEqual(this.state, nextState)
return !equalProps || !equalState
}
render() {
return this.props.children;
}
}

export default PureComponent;

自动部署你的博客

Posted on 2019-06-01

通过 Hexo 快速生成静态博客,通过 GitHub 代码托管,然后通过 CI 网站持续部署。

生成博客

Hexo 是一个快速、简洁且高效的博客框架。接下来只需要使用 npm 即可完成 Hexo 的安装。

1
npm install -g hexo-cli

执行命令之前请确保你已经安装了 node 和 git 软件。

安装 Hexo 完成后,请执行下列命令,Hexo 将会在指定文件夹中新建所需要的文件。

1
2
3
hexo init <folder>
cd <folder>
npm install

<folder> 表示项目名称,可以自定义,然后 cd 表示进入到生成的项目,npm install 表示安装依赖。

上传代码

你需要有一个 GitHub 账号登录,然后新建一个空仓库,把刚才生成的项目提交的这个仓库中。

生成 GitHub 的 token,详细步骤如下图。

选中所有的选项

复制生成的token

自动部署

https://travis-ci.com/ 通过 GitHub 登录到这个自动部署的网站中,这个网站会自动获取你 GitHub 中的所有仓库,选择你刚才创建的项目,修改设置选项。

增加环境变量,名字是 TOKEN,值是通过 GitHub 生成的 token,是登录 GitHub 的令牌。

添加配置

修改博客的配置文件,将部署的GitHub地址和部署的跟目录加上。保证静态资源可以正常访问。

增加 .travis.yml 文件,里面的内容如下,需要改成你的用户名邮箱和 git 项目地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
language: node_js
node_js:
- "11"
install:
- npm install
script:
- hexo g
after_script:
- cd ./public
- git init
- git config user.name "用户名"
- git config user.email "邮箱"
- git add -A
- git commit -m "init"
- git push --force "https://${TOKEN}@项目地址" "master:gh-pages"
branches:
only:
- master

完成以上操作,然后再推送一次到 GitHub 中,项目就会自动开始部署到 GitHub 的 gh-pages 中,每次推送都会自动部署的,关于项目的地址就是的静态页地址。格式是:用户名.gitbub.io/项目名称。

Qiang

看前端技术文章

4 posts
2 tags
© 2019 Qiang
Powered by Hexo
|
Theme — NexT.Muse v5.1.4