├── .gitignore
├── examples
├── react-redux-test
│ ├── mock
│ │ └── .gitkeep
│ ├── .webpackrc
│ ├── .eslintrc
│ ├── .roadhogrc.mock.js
│ ├── src
│ │ ├── index.css
│ │ ├── assets
│ │ │ └── yay.jpg
│ │ ├── services
│ │ │ └── example.js
│ │ ├── components
│ │ │ └── Example.js
│ │ ├── index.js
│ │ ├── router.js
│ │ ├── models
│ │ │ └── example.js
│ │ ├── routes
│ │ │ ├── Count.js
│ │ │ ├── IndexPage.css
│ │ │ └── IndexPage.js
│ │ └── utils
│ │ │ └── request.js
│ ├── .gitignore
│ ├── .editorconfig
│ ├── public
│ │ └── index.html
│ └── package.json
├── chrome-extension
│ ├── icon.png
│ ├── manifest.json
│ ├── js
│ │ ├── content.js
│ │ └── popup.js
│ └── popup.html
├── chrome-plugin-demo-master
│ ├── demo
│ │ ├── img
│ │ │ ├── icon.png
│ │ │ └── sds.png
│ │ ├── _locales
│ │ │ ├── zh_CN
│ │ │ │ └── messages.json
│ │ │ └── en
│ │ │ │ └── messages.json
│ │ ├── devtools.html
│ │ ├── js
│ │ │ ├── show-image-content-size.js
│ │ │ ├── devtools.js
│ │ │ ├── inject.js
│ │ │ ├── options.js
│ │ │ ├── mypanel.js
│ │ │ ├── background.js
│ │ │ ├── content-script.js
│ │ │ └── popup.js
│ │ ├── sidebar.html
│ │ ├── background.html
│ │ ├── newtab.html
│ │ ├── options.html
│ │ ├── mypanel.html
│ │ ├── css
│ │ │ └── custom.css
│ │ ├── popup.html
│ │ └── manifest.json
│ └── page-action-demo
│ │ ├── img
│ │ └── icon.png
│ │ ├── popup.html
│ │ ├── js
│ │ └── background.js
│ │ └── manifest.json
└── BaiduAdBlock-master
│ └── BaiduAdBlock
│ ├── images
│ ├── icon16.png
│ └── icon48.png
│ ├── scripts
│ ├── background.js
│ └── content.js
│ ├── index.html
│ └── manifest.json
├── imgs
├── dep1.png
├── dep2.png
├── webs
│ ├── p
│ ├── ckxt.png
│ ├── h5.jpg
│ ├── pm.jpg
│ ├── web1.png
│ ├── webs.jpg
│ ├── wy.gif
│ ├── arch-1.gif
│ ├── arch-2.gif
│ ├── arch-3.gif
│ ├── fenli.png
│ ├── nodejs.png
│ ├── web2.JPEG
│ ├── web3.JPEG
│ ├── arch-cs.gif
│ ├── browser.png
│ ├── jineng1.PNG
│ ├── jineng2.JPEG
│ ├── jineng3.JPEG
│ ├── javascript.jpg
│ ├── xiaochengxu.jpg
│ └── xiaochengxu.png
├── 事件.png
├── 事件.xmind
├── anquan.png
├── event.png
├── logjs.png
├── popup.png
├── yewai.jpeg
├── anquan
│ ├── bg.jpg
│ ├── fb.jpg
│ ├── huazhu.jpg
│ └── 20161111165019365
├── anquan1.png
├── choujiang.png
├── console.png
├── reactDom.png
├── setState.png
├── xiaodao.jpeg
├── animation1.gif
├── animation2.gif
├── breakPoint.png
├── fiber-tree.png
└── setState.xmind
├── reactDom.xmind
├── src
├── npm木马.pptx
├── 大前端简介.pptx
├── 你不知道的js-上册.md
├── 前端面试题精选.md
├── react和vue对比.md
├── git回滚.md
├── nodejs加载机制.md
├── vscode路径别名问题.md
├── BFC.md
├── react16-setState流程.md
├── 黑科技-react如何获取父元素.md
├── js编写动画的方式.md
├── 黑科技-react如何从dom上获取fiber实例.md
├── 图片串行加载.md
├── redux插件原理详解.md
├── react16-事件系统分析.md
├── react源码分析-reactDom.render.md
├── 我是如何从你的网站盗取银行卡和密码的.md
├── 如何开发chrome-extension.md
├── 大前端简介.md
├── 如何阻止我从您的网站收集信用卡号码和密码.md
└── 自问自答.md
├── react-test
├── src
│ ├── index.css
│ ├── index.js
│ ├── App.test.js
│ ├── App.js
│ ├── App.css
│ ├── logo.svg
│ └── registerServiceWorker.js
├── public
│ ├── favicon.ico
│ ├── manifest.json
│ └── index.html
├── .gitignore
└── package.json
├── package.json
├── event-loop.md
├── README.md
└── the-super-tiny-compiler.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/examples/react-redux-test/mock/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/react-redux-test/.webpackrc:
--------------------------------------------------------------------------------
1 | {
2 | }
3 |
--------------------------------------------------------------------------------
/examples/react-redux-test/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "umi"
3 | }
4 |
--------------------------------------------------------------------------------
/examples/react-redux-test/.roadhogrc.mock.js:
--------------------------------------------------------------------------------
1 |
2 | export default {
3 | };
4 |
--------------------------------------------------------------------------------
/imgs/dep1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/dep1.png
--------------------------------------------------------------------------------
/imgs/dep2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/dep2.png
--------------------------------------------------------------------------------
/imgs/webs/p:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/webs/p
--------------------------------------------------------------------------------
/imgs/事件.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/事件.png
--------------------------------------------------------------------------------
/imgs/事件.xmind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/事件.xmind
--------------------------------------------------------------------------------
/imgs/anquan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/anquan.png
--------------------------------------------------------------------------------
/imgs/event.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/event.png
--------------------------------------------------------------------------------
/imgs/logjs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/logjs.png
--------------------------------------------------------------------------------
/imgs/popup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/popup.png
--------------------------------------------------------------------------------
/imgs/yewai.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/yewai.jpeg
--------------------------------------------------------------------------------
/reactDom.xmind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/reactDom.xmind
--------------------------------------------------------------------------------
/src/npm木马.pptx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/src/npm木马.pptx
--------------------------------------------------------------------------------
/src/大前端简介.pptx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/src/大前端简介.pptx
--------------------------------------------------------------------------------
/imgs/anquan/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/anquan/bg.jpg
--------------------------------------------------------------------------------
/imgs/anquan/fb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/anquan/fb.jpg
--------------------------------------------------------------------------------
/imgs/anquan1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/anquan1.png
--------------------------------------------------------------------------------
/imgs/choujiang.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/choujiang.png
--------------------------------------------------------------------------------
/imgs/console.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/console.png
--------------------------------------------------------------------------------
/imgs/reactDom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/reactDom.png
--------------------------------------------------------------------------------
/imgs/setState.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/setState.png
--------------------------------------------------------------------------------
/imgs/webs/ckxt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/webs/ckxt.png
--------------------------------------------------------------------------------
/imgs/webs/h5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/webs/h5.jpg
--------------------------------------------------------------------------------
/imgs/webs/pm.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/webs/pm.jpg
--------------------------------------------------------------------------------
/imgs/webs/web1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/webs/web1.png
--------------------------------------------------------------------------------
/imgs/webs/webs.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/webs/webs.jpg
--------------------------------------------------------------------------------
/imgs/webs/wy.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/webs/wy.gif
--------------------------------------------------------------------------------
/imgs/xiaodao.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/xiaodao.jpeg
--------------------------------------------------------------------------------
/imgs/animation1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/animation1.gif
--------------------------------------------------------------------------------
/imgs/animation2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/animation2.gif
--------------------------------------------------------------------------------
/imgs/breakPoint.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/breakPoint.png
--------------------------------------------------------------------------------
/imgs/fiber-tree.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/fiber-tree.png
--------------------------------------------------------------------------------
/imgs/setState.xmind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/setState.xmind
--------------------------------------------------------------------------------
/imgs/webs/arch-1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/webs/arch-1.gif
--------------------------------------------------------------------------------
/imgs/webs/arch-2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/webs/arch-2.gif
--------------------------------------------------------------------------------
/imgs/webs/arch-3.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/webs/arch-3.gif
--------------------------------------------------------------------------------
/imgs/webs/fenli.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/webs/fenli.png
--------------------------------------------------------------------------------
/imgs/webs/nodejs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/webs/nodejs.png
--------------------------------------------------------------------------------
/imgs/webs/web2.JPEG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/webs/web2.JPEG
--------------------------------------------------------------------------------
/imgs/webs/web3.JPEG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/webs/web3.JPEG
--------------------------------------------------------------------------------
/imgs/anquan/huazhu.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/anquan/huazhu.jpg
--------------------------------------------------------------------------------
/imgs/webs/arch-cs.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/webs/arch-cs.gif
--------------------------------------------------------------------------------
/imgs/webs/browser.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/webs/browser.png
--------------------------------------------------------------------------------
/imgs/webs/jineng1.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/webs/jineng1.PNG
--------------------------------------------------------------------------------
/imgs/webs/jineng2.JPEG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/webs/jineng2.JPEG
--------------------------------------------------------------------------------
/imgs/webs/jineng3.JPEG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/webs/jineng3.JPEG
--------------------------------------------------------------------------------
/imgs/webs/javascript.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/webs/javascript.jpg
--------------------------------------------------------------------------------
/imgs/webs/xiaochengxu.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/webs/xiaochengxu.jpg
--------------------------------------------------------------------------------
/imgs/webs/xiaochengxu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/webs/xiaochengxu.png
--------------------------------------------------------------------------------
/examples/react-redux-test/src/index.css:
--------------------------------------------------------------------------------
1 |
2 | html, body, :global(#root) {
3 | height: 100%;
4 | }
5 |
6 |
--------------------------------------------------------------------------------
/react-test/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/imgs/anquan/20161111165019365:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/imgs/anquan/20161111165019365
--------------------------------------------------------------------------------
/react-test/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/react-test/public/favicon.ico
--------------------------------------------------------------------------------
/examples/chrome-extension/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/examples/chrome-extension/icon.png
--------------------------------------------------------------------------------
/examples/react-redux-test/src/assets/yay.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/examples/react-redux-test/src/assets/yay.jpg
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/demo/img/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/examples/chrome-plugin-demo-master/demo/img/icon.png
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/demo/img/sds.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/examples/chrome-plugin-demo-master/demo/img/sds.png
--------------------------------------------------------------------------------
/examples/BaiduAdBlock-master/BaiduAdBlock/images/icon16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/examples/BaiduAdBlock-master/BaiduAdBlock/images/icon16.png
--------------------------------------------------------------------------------
/examples/BaiduAdBlock-master/BaiduAdBlock/images/icon48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/examples/BaiduAdBlock-master/BaiduAdBlock/images/icon48.png
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/demo/_locales/zh_CN/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "pluginDesc": {"message": "一个简单的Chrome插件demo"},
3 | "helloWorld": {"message": "你好啊,世界!"}
4 | }
--------------------------------------------------------------------------------
/examples/react-redux-test/src/services/example.js:
--------------------------------------------------------------------------------
1 | import request from '../utils/request';
2 |
3 | export function query() {
4 | return request('/api/users');
5 | }
6 |
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/page-action-demo/img/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luke93h/git-blog/HEAD/examples/chrome-plugin-demo-master/page-action-demo/img/icon.png
--------------------------------------------------------------------------------
/src/你不知道的js-上册.md:
--------------------------------------------------------------------------------
1 | # 你不知道德js-上册-读书笔记
2 |
3 | ## 目录
4 | - [第一章、作用域是什么](#作用域)
5 |
6 | ## 作用域
7 | js在执行前会经历三个步骤:
8 | 1. 词法分析:将字符串拆分为词法单元;
9 | 2. 语法分析:由词法单元生成抽象语法树
10 | 3. 代码生成
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/demo/_locales/en/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "pluginDesc": {"message": "A simple chrome extension demo"},
3 | "helloWorld": {"message": "Hello World!"}
4 | }
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/demo/devtools.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/examples/react-redux-test/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # production
7 | /dist
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log*
12 |
--------------------------------------------------------------------------------
/examples/react-redux-test/src/components/Example.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const Example = () => {
4 | return (
5 |
6 | Example
7 |
8 | );
9 | };
10 |
11 | Example.propTypes = {
12 | };
13 |
14 | export default Example;
15 |
--------------------------------------------------------------------------------
/react-test/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 | import registerServiceWorker from './registerServiceWorker';
6 |
7 | ReactDOM.render(, document.getElementById('root'));
8 | registerServiceWorker();
9 |
--------------------------------------------------------------------------------
/react-test/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render(, div);
8 | ReactDOM.unmountComponentAtNode(div);
9 | });
10 |
--------------------------------------------------------------------------------
/src/前端面试题精选.md:
--------------------------------------------------------------------------------
1 | # 前端面试题精选
2 |
3 | 该文章用于记录,比较好的面试题,并尝试给出最佳答案
4 |
5 | ### 怎么去设计一个组件封装
6 |
7 | 组件封装的目的是为了更好的复用,提高工作效率,设计一个优秀的组件可以从以下几方面考虑:
8 | 1. 单元测试。单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。
9 |
10 | * 从短期来看,单元测试会导致工作量大幅增加,降低开发效率;长期来看单元测试有利于项目的维护,升级,重构;
11 | * 使用频率高的模块,核心模块,开源组件应该写单元测试
12 |
13 | 2. 解耦。解耦是为了更加广阔的
14 |
15 |
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/demo/js/show-image-content-size.js:
--------------------------------------------------------------------------------
1 | // 鉴于浏览器默认不会显示图片的体积大小,每次都需要保存到本地才能查看到大小
2 | // 故通过插件的方式强行修改图片页的标题
3 | fetch(location.href).then(resp => resp.blob()).then(blob => {
4 | var size = blob.size;
5 | size = (size / 1024).toFixed(2) + ' kb';
6 | document.title = '(' + size + ')' + document.title;
7 | console.log(size);
8 | });
9 |
--------------------------------------------------------------------------------
/examples/react-redux-test/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
14 |
15 | [Makefile]
16 | indent_style = tab
17 |
--------------------------------------------------------------------------------
/examples/react-redux-test/src/index.js:
--------------------------------------------------------------------------------
1 | import dva from 'dva';
2 | import './index.css';
3 |
4 | // 1. Initialize
5 | const app = dva();
6 |
7 | // 2. Plugins
8 | // app.use({});
9 |
10 | // 3. Model
11 | app.model(require('./models/example').default);
12 |
13 | // 4. Router
14 | app.router(require('./router').default);
15 |
16 | // 5. Start
17 | app.start('#root');
18 |
--------------------------------------------------------------------------------
/src/react和vue对比.md:
--------------------------------------------------------------------------------
1 | Vue的优势是:
2 | 1. 模板和渲染函数的弹性选择
3 | 2. 简单的语法和项目配置
4 | 3. 更快的渲染速度和更小的体积
5 |
6 | React的优势是:
7 | 1. 更适合大型应用和更好的可测试性
8 | 2. Web端和移动端原生APP通吃
9 | 3. 更大的生态系统,更多的支持和好用的工具
10 |
11 | 共通的优点:
12 | 1. 用虚拟DOM实现快速渲染
13 | 2. 轻量级
14 | 3. 响应式组件
15 | 4. 服务端渲染
16 | 5. 集成路由工具,打包工具,状态管理工具的难度低
17 | 6. 优秀的支持和社区
18 |
19 | 综上所述,vue适用于小公司(招人方便),小项目(开发快),react适合大型的复杂项目。
--------------------------------------------------------------------------------
/react-test/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/examples/react-redux-test/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Dva Demo
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/react-test/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/src/git回滚.md:
--------------------------------------------------------------------------------
1 | ## git回滚
2 |
3 | 最近看到一个问题,虽然没遇到过使用场景,但觉得以后说不定能用上,此处记录一下。问题如下:
4 |
5 | 如果线上代码出了问题,需要代码回滚到之前的某次提交,应该如何操作?
6 |
7 | 方法一,revert:
8 | ```bash
9 | git revert HEAD
10 | git push origin master
11 | ```
12 |
13 | 方法二,reset:
14 | ```bash
15 | git reset --hard HEAD^
16 | git push origin master -f
17 | ```
18 |
19 | 方法三:回滚某次提交
20 |
21 | ```bash
22 | # 找到要回滚的commitID
23 | git log
24 | git revert commitID
25 | ```
--------------------------------------------------------------------------------
/src/nodejs加载机制.md:
--------------------------------------------------------------------------------
1 | 几种模块互用 nodejs加载机制 webpack HMR原理 几个加载器的实现 promise 顺序处理 js 序列化 http2 ant design 表单校验 react/vue 是如何转小程序的 面试了一天 除
2 | 还有一个如何实现直播间几万弹幕发送 送礼物 互不影响啥的 乱七八糟的 根本没明白什么需求
3 |
4 | nodejs模块引用机制
5 |
6 | 在node中已入模块时,需要经历三个步骤:
7 | 1. 路径分析
8 | 2. 文件定位
9 | 3. 编译执行
10 |
11 | 模块分类:
12 | 1. 核心模块
13 | 2. 文件模块
14 |
15 | 优先级:
16 |
17 | 缓存模块 > 核心模块 > 用户模块
18 |
19 | .js > .json > .node
20 |
21 | 自定义模块的路径查找
--------------------------------------------------------------------------------
/react-test/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-test",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "^16.4.1",
7 | "react-dom": "^16.4.1",
8 | "react-scripts": "1.1.4"
9 | },
10 | "scripts": {
11 | "start": "react-scripts start",
12 | "build": "react-scripts build",
13 | "test": "react-scripts test --env=jsdom",
14 | "eject": "react-scripts eject"
15 | }
16 | }
--------------------------------------------------------------------------------
/examples/react-redux-test/src/router.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Router, Route, Switch } from 'dva/router';
3 | import IndexPage from './routes/IndexPage';
4 |
5 | function RouterConfig({ history }) {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 | );
13 | }
14 |
15 | export default RouterConfig;
16 |
--------------------------------------------------------------------------------
/examples/react-redux-test/src/models/example.js:
--------------------------------------------------------------------------------
1 |
2 | export default {
3 |
4 | namespace: 'example',
5 |
6 | state: {
7 | count: 0
8 | },
9 |
10 |
11 | effects: {
12 | *fetch({ payload }, { call, put }) { // eslint-disable-line
13 | yield put({ type: 'save' });
14 | },
15 | },
16 |
17 | reducers: {
18 | add(state, action) {
19 | return { ...state, count: ++state.count};
20 | },
21 | },
22 |
23 | };
24 |
--------------------------------------------------------------------------------
/examples/react-redux-test/src/routes/Count.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'dva';
3 | let i = 0
4 | class Count extends React.Component {
5 | render(){
6 | console.log('from Count', ++i)
7 | return (
8 |
9 | {this.props.example.count}
10 |
11 | {this.props.count}
12 |
13 | );
14 | }
15 | }
16 |
17 | export default connect(state => ({
18 | example: state.example
19 | }))(Count);
--------------------------------------------------------------------------------
/examples/BaiduAdBlock-master/BaiduAdBlock/scripts/background.js:
--------------------------------------------------------------------------------
1 | chrome.runtime.onMessage.addListener(
2 | function (count, sender, sendResponse) {
3 | chrome.browserAction.setBadgeBackgroundColor({
4 | color: '#F00'
5 | });
6 |
7 | chrome.browserAction.setBadgeText({
8 | text: count.toString()
9 | });
10 |
11 | chrome.browserAction.setTitle({
12 | title: '已为您清除' + count + '了条广告'
13 | });
14 | }
15 | );
--------------------------------------------------------------------------------
/src/vscode路径别名问题.md:
--------------------------------------------------------------------------------
1 | ## vscode路径别名问题
2 |
3 | 最近在开发时遇到了这样一个问题,vscode是有模块跳转的功能的(一般为ctrl+左击或alt+左击),但是在设置了webpack的路径别名之后这个功能失效了。
4 |
5 | 网上查了资料后,找到了解决方式如下:
6 |
7 | 1. 在项目根位置创建一个jsconfig.json
8 | 2. 配置jsconfig.json
9 | ```jsx
10 | {
11 | "include": [
12 | "./src/**/*"
13 | ],
14 | "compilerOptions": {
15 | "baseUrl": ".",
16 | "paths": {
17 | "components/*": ["src/components/*"],
18 | "utils": ["src/utils/utils.js"],
19 | },
20 | }
21 | }
22 | ```
23 | 3. 重启ide,搞定!
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/page-action-demo/popup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | popup页
5 |
6 |
7 |
15 |
16 |
17 | pageAction演示
18 | 打开百度pageAction会点亮,打开其它页面pageAction会变灰。
19 |
20 |
--------------------------------------------------------------------------------
/react-test/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import logo from './logo.svg';
3 | import './App.css';
4 |
5 | class App extends Component {
6 | state = {
7 | a: 1,
8 | }
9 | onClick = () => {
10 | this.setState({
11 | a: this.state.a + 1
12 | })
13 | }
14 | render() {
15 | return (
16 |
17 |
18 | {this.state.a}
19 |
20 |
21 | );
22 | }
23 | }
24 |
25 | export default App;
26 |
--------------------------------------------------------------------------------
/react-test/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | }
16 |
17 | .App-title {
18 | font-size: 1.5em;
19 | }
20 |
21 | .App-intro {
22 | font-size: large;
23 | }
24 |
25 | @keyframes App-logo-spin {
26 | from { transform: rotate(0deg); }
27 | to { transform: rotate(360deg); }
28 | }
29 |
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/page-action-demo/js/background.js:
--------------------------------------------------------------------------------
1 | chrome.runtime.onInstalled.addListener(function(){
2 | chrome.declarativeContent.onPageChanged.removeRules(undefined, function(){
3 | chrome.declarativeContent.onPageChanged.addRules([
4 | {
5 | conditions: [
6 | // 只有打开百度才显示pageAction
7 | new chrome.declarativeContent.PageStateMatcher({pageUrl: {urlContains: 'baidu.com'}})
8 | ],
9 | actions: [new chrome.declarativeContent.ShowPageAction()]
10 | }
11 | ]);
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/demo/sidebar.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 侧边栏
5 |
6 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/examples/react-redux-test/src/routes/IndexPage.css:
--------------------------------------------------------------------------------
1 |
2 | .normal {
3 | font-family: Georgia, sans-serif;
4 | margin-top: 3em;
5 | text-align: center;
6 | }
7 |
8 | .title {
9 | font-size: 2.5rem;
10 | font-weight: normal;
11 | letter-spacing: -1px;
12 | }
13 |
14 | .welcome {
15 | height: 328px;
16 | background: url(../assets/yay.jpg) no-repeat center 0;
17 | background-size: 388px 328px;
18 | }
19 |
20 | .list {
21 | font-size: 1.2em;
22 | margin-top: 1.8em;
23 | list-style: none;
24 | line-height: 1.5em;
25 | }
26 |
27 | .list code {
28 | background: #f7f7f7;
29 | }
30 |
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/demo/js/devtools.js:
--------------------------------------------------------------------------------
1 | // 创建自定义面板,同一个插件可以创建多个自定义面板
2 | // 几个参数依次为:panel标题、图标(其实设置了也没地方显示)、要加载的页面、加载成功后的回调
3 | chrome.devtools.panels.create('MyPanel', 'img/icon.png', 'mypanel.html', function(panel)
4 | {
5 | console.log('自定义面板创建成功!'); // 注意这个log一般看不到
6 | });
7 |
8 | // 创建自定义侧边栏
9 | chrome.devtools.panels.elements.createSidebarPane("Images", function(sidebar)
10 | {
11 | // sidebar.setPage('../sidebar.html'); // 指定加载某个页面
12 | sidebar.setExpression('document.querySelectorAll("img")', 'All Images'); // 通过表达式来指定
13 | //sidebar.setObject({aaa: 111, bbb: 'Hello World!'}); // 直接设置显示某个对象
14 | });
--------------------------------------------------------------------------------
/examples/chrome-extension/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "manifest_version": 2,
3 |
4 | "name": "库存查询",
5 | "description": "自动查询库存量,有库存时及时通知用户",
6 | "version": "1.0",
7 |
8 | "permissions": [
9 | "https://secure.flickr.com/",
10 | "http://smart.supor.com:9097/",
11 | "https://smart.supor.com:9097/",
12 | "tabs",
13 | "storage",
14 | "activeTab"
15 | ],
16 | "browser_action": {
17 | "default_title": "库存查询",
18 | "default_icon": "icon.png",
19 | "default_popup": "popup.html"
20 | },
21 | "content_scripts":[{
22 | "matches": ["http://smart.supor.com:9097/*","https://smart.supor.com:9097/*"],
23 | "js": ["js/content.js"]
24 | }]
25 | }
26 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "git-blog",
3 | "version": "1.0.0",
4 | "description": "luke-blog",
5 | "main": "index.js",
6 | "directories": {
7 | "test": "test"
8 | },
9 | "scripts": {
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/luke93h/git-blog.git"
15 | },
16 | "keywords": [],
17 | "author": "",
18 | "license": "ISC",
19 | "bugs": {
20 | "url": "https://github.com/luke93h/git-blog/issues"
21 | },
22 | "homepage": "https://github.com/luke93h/git-blog#readme",
23 | "dependencies": {
24 | "create-react-app": "^1.5.2"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/BFC.md:
--------------------------------------------------------------------------------
1 | # BFC
2 |
3 | ## 定义
4 |
5 | > 块格式化上下文(Block Formatting Context,BFC) 是Web页面的可视化CSS渲染的一部分,是布局过程中生成块级盒子的区域,也是浮动元素与其他元素的交互限定区域。
6 |
7 | ## 生成方法
8 |
9 | >Floats, absolutely positioned elements, inline-blocks, table-cells, table-captions, and elements with ‘overflow’ other than ‘visible’ (except when that value has been propagated to the viewport) establish new block formatting contexts.
10 |
11 | 浮动,绝对定位,inline-block,table-cells, table-captions,或者overflow不为'visible'都会生成BFC
12 |
13 | ## 作用
14 |
15 | 影响浮动定位、清除浮动
16 |
17 | 1. 只有当元素在同一个BFC中时,垂直方向上的margin
18 | 才会clollpase.如果它们属于不同的BFC,则不会有margin collapse.因此我们可以再建立一个BFC去阻止margin collpase的发生。
19 |
20 | 2. 利用BFC去容纳浮动元素
21 |
22 | 3. 利用BFC阻止文本换行
--------------------------------------------------------------------------------
/src/react16-setState流程.md:
--------------------------------------------------------------------------------
1 | # react源码分析-setState分析
2 |
3 | 
4 |
5 | ## 前言
6 |
7 | 是否有过这样的疑问:
8 |
9 | 1. setState做了什么?
10 | 2. setState是如何触发ui变化的?
11 |
12 | ## isWorking
13 |
14 | 如果此时isWorking为true,react将不会立即执行更新操作,而是把更新操作交给正在working的任务。(例如:由onClick触发的working)
15 |
16 | 如果此时没有其他任务在执行,则自己主动申请执行任务(如setTimeout或ajax触发)
17 |
18 | ## 结尾语
19 |
20 | 没错,setState的逻辑就是这么简单。如果想了解requestWork阶段的内容,请访问[react源码分析-reactDom.render](https://github.com/luke93h/git-blog/issues/7)
21 |
22 | ## 相关
23 |
24 | - [react源码分析-reactDom.render](https://github.com/luke93h/git-blog/issues/7)
25 | - [事件系统分析](https://github.com/luke93h/git-blog/issues/10)
26 |
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/page-action-demo/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | // 清单文件的版本,这个必须写,而且必须是2
3 | "manifest_version": 2,
4 | // 插件的名称
5 | "name": "page-action-demo",
6 | // 插件的版本
7 | "version": "1.0.0",
8 | // 插件描述
9 | "description": "pageAction演示",
10 | // 图标,一般偷懒全部用一个尺寸的也没问题
11 | "icons":
12 | {
13 | "16": "img/icon.png",
14 | "48": "img/icon.png",
15 | "128": "img/icon.png"
16 | },
17 | // 当某些特定页面打开才显示的图标
18 | "page_action":
19 | {
20 | "default_icon": "img/icon.png",
21 | "default_title": "我是pageAction",
22 | "default_popup": "popup.html"
23 | },
24 | // 权限申请
25 | "permissions":
26 | [
27 | "declarativeContent"
28 | ],
29 | "background":
30 | {
31 | "scripts": ["js/background.js"]
32 | }
33 | }
--------------------------------------------------------------------------------
/examples/react-redux-test/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "start": "roadhog server",
5 | "build": "roadhog build",
6 | "lint": "eslint --ext .js src test",
7 | "precommit": "npm run lint"
8 | },
9 | "dependencies": {
10 | "dva": "^2.2.3",
11 | "react": "^16.2.0",
12 | "react-dom": "^16.2.0"
13 | },
14 | "devDependencies": {
15 | "babel-plugin-dva-hmr": "^0.3.2",
16 | "eslint": "^4.14.0",
17 | "eslint-config-umi": "^0.1.1",
18 | "eslint-plugin-flowtype": "^2.34.1",
19 | "eslint-plugin-import": "^2.6.0",
20 | "eslint-plugin-jsx-a11y": "^5.1.1",
21 | "eslint-plugin-react": "^7.1.0",
22 | "husky": "^0.12.0",
23 | "redbox-react": "^1.4.3",
24 | "roadhog": "^2.0.0"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/demo/background.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 背景页
5 |
6 |
7 |
15 |
16 |
17 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/examples/react-redux-test/src/routes/IndexPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'dva';
3 | import styles from './IndexPage.css';
4 | import Count from './Count'
5 | let i = 0
6 | class IndexPage extends React.Component {
7 | onClick = () => {
8 | this.props.dispatch({
9 | type: 'example/add'
10 | })
11 | }
12 | render(){
13 | console.log('From Parent', ++i)
14 | return (
15 |
16 |
21 |
22 |
23 | );
24 | }
25 | }
26 |
27 | export default connect(state => ({
28 | example: state.example
29 | }))(IndexPage);
30 |
--------------------------------------------------------------------------------
/examples/BaiduAdBlock-master/BaiduAdBlock/index.html:
--------------------------------------------------------------------------------
1 |
2 | 百度搜索广告过滤
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
百度搜索广告过滤
12 |
13 |
14 |
15 |
16 | 项目源代码
17 |
18 |
19 |
20 |
21 | 老九 2018/9
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/demo/newtab.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 新标签页
5 |
6 |
7 |
26 |
27 |
28 |
29 |
33 |
34 |
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/demo/js/inject.js:
--------------------------------------------------------------------------------
1 | // 通过postMessage调用content-script
2 | function invokeContentScript(code)
3 | {
4 | window.postMessage({cmd: 'invoke', code: code}, '*');
5 | }
6 | // 发送普通消息到content-script
7 | function sendMessageToContentScriptByPostMessage(data)
8 | {
9 | window.postMessage({cmd: 'message', data: data}, '*');
10 | }
11 |
12 | // 通过DOM事件发送消息给content-script
13 | (function() {
14 | var customEvent = document.createEvent('Event');
15 | customEvent.initEvent('myCustomEvent', true, true);
16 | // 通过事件发送消息给content-script
17 | function sendMessageToContentScriptByEvent(data) {
18 | data = data || '你好,我是injected-script!';
19 | var hiddenDiv = document.getElementById('myCustomEventDiv');
20 | hiddenDiv.innerText = data
21 | hiddenDiv.dispatchEvent(customEvent);
22 | }
23 | window.sendMessageToContentScriptByEvent = sendMessageToContentScriptByEvent;
24 | })();
25 |
--------------------------------------------------------------------------------
/examples/react-redux-test/src/utils/request.js:
--------------------------------------------------------------------------------
1 | import fetch from 'dva/fetch';
2 |
3 | function parseJSON(response) {
4 | return response.json();
5 | }
6 |
7 | function checkStatus(response) {
8 | if (response.status >= 200 && response.status < 300) {
9 | return response;
10 | }
11 |
12 | const error = new Error(response.statusText);
13 | error.response = response;
14 | throw error;
15 | }
16 |
17 | /**
18 | * Requests a URL, returning a promise.
19 | *
20 | * @param {string} url The URL we want to request
21 | * @param {object} [options] The options we want to pass to "fetch"
22 | * @return {object} An object containing either "data" or "err"
23 | */
24 | export default function request(url, options) {
25 | return fetch(url, options)
26 | .then(checkStatus)
27 | .then(parseJSON)
28 | .then(data => ({ data }))
29 | .catch(err => ({ err }));
30 | }
31 |
--------------------------------------------------------------------------------
/examples/BaiduAdBlock-master/BaiduAdBlock/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "百度搜索广告过滤",
3 | "version": "1.0.0",
4 | "manifest_version": 2,
5 | "description": "百度搜索广告过滤",
6 | "icons": {
7 | "16": "images/icon16.png",
8 | "48": "images/icon48.png"
9 | },
10 | "browser_action": {
11 | "default_title": "百度搜索广告过滤",
12 | "default_icon": "images/icon16.png",
13 | "default_popup": "index.html"
14 | },
15 | "background": {
16 | "scripts": ["scripts/background.js"],
17 | "persistent": false
18 | },
19 | "content_scripts": [{
20 | "js": [
21 | "scripts/jquery-1.7.1.min.js",
22 | "scripts/content.js"
23 | ],
24 | "matches": [
25 | "http://www.baidu.com/*",
26 | "https://www.baidu.com/*"
27 | ],
28 | "run_at": "document_start"
29 | }],
30 | "permissions": [
31 | "http://www.baidu.com/*",
32 | "https://www.baidu.com/*"
33 | ]
34 | }
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/demo/options.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 | 插件配置页
10 |
11 |
12 | 简单的配置页
13 | (功能很无聊,纯属演示功能)
14 |
15 |
16 |
23 |
24 |
25 |
26 |
27 | 保存配置
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/demo/js/options.js:
--------------------------------------------------------------------------------
1 | document.addEventListener('DOMContentLoaded', function() {
2 | var defaultConfig = {color: 'white', showImage: true}; // 默认配置
3 | // 读取数据,第一个参数是指定要读取的key以及设置默认值
4 | chrome.storage.sync.get(defaultConfig, function(items) {
5 | document.getElementById('color').value = items.color;
6 | document.getElementById('show_image').checked = items.showImage;
7 | });
8 | });
9 |
10 | document.getElementById('save').addEventListener('click', function() {
11 | var color = document.getElementById('color').value;
12 | var showImage = document.getElementById('show_image').checked;
13 | // 这里貌似会存在刷新不及时的问题
14 | chrome.extension.getBackgroundPage().showImage = showImage; // 让background即使生效
15 | chrome.storage.sync.set({color: color, showImage: showImage}, function() {
16 | // 注意新版的options页面alert不生效!
17 | // alert('保存成功!');
18 | document.getElementById('status').textContent = '保存成功!';
19 | setTimeout(() => {document.getElementById('status').textContent = '';}, 800);
20 | });
21 | });
--------------------------------------------------------------------------------
/event-loop.md:
--------------------------------------------------------------------------------
1 | # Event Loop
2 | 虽说目前chrome已经支持worker,js可以多线程运行了,但webworker仅仅能进行计算任务,不能操作DOM,所以本质上还是单线程。
3 |
4 | ## 线程
5 | 1. js运作在浏览器中,是单线程的,即js代码始终在一个线程上执行,这个线程称为js引擎线程。
6 | 2. 浏览器是多线程的,除了js引擎线程,它还有: UI渲染线程、浏览器事件触发线程、http请求线程、EventLoop轮询的处理线程...
7 | 3. 多线程之间会共享运行资源,浏览器端的js会操作dom,多个线程必然会带来同步的问题,所有js核心选择了单线程来避免处理这个麻烦。js可以操作dom,影响渲染,所以js引擎线程和UI线程是互斥的。这也就解释了js执行时会阻塞页面的渲染。
8 | ## 同步任务
9 | 在主线程排队支持的任务,前一个任务执行完毕后,执行后一个任务,形成一个执行栈,线程执行时在内存形成的空间为栈,进程形成堆结构,这是内存的结构。
10 | ## 异步任务
11 | 异步任务会被主线程挂起,不会进入主线程,而是进入消息队列,而且必须指定回调函数,只有消息队列通知主线程,并且执行栈为空时,该消息对应的任务才会进入执行栈获得执行的机会。
12 | ## js运行机制
13 | 1. 所有同步任务都在主线程上执行,形成一个执行栈。
14 | 2. 主线程之外,还存在一个”任务队列”。只要异步任务有了运行结果,就在”任务队列”之中放置一个事件。
15 | 3. 一旦”执行栈”中的所有同步任务执行完毕,系统就会读取”任务队列”,看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
16 | 4. 主线程不断重复上面的第三步。
17 | ## Event Loop
18 | 主线程从”任务队列”中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。
19 |
20 | 简单说,浏览器的两个线程:一个负责程序本身的运行,称为”主线程”;另一个负责主线程与其他进程(主要是各种I/O操作)的通信,被称为”Event Loop线程”(可以译为”消息线程”)。
21 | ## Task和Microtask
22 | * Task:是严格按照时间顺序压栈和执行的,所以浏览器能够使得 JavaScript 内部任务与 DOM 任务能够有序的执行。
23 | * Microtask 通常来说就是需要在当前 task 执行结束后立即执行的任务
24 |
25 |
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/demo/mypanel.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 新标签页
5 |
6 |
27 |
28 |
29 |
30 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/examples/BaiduAdBlock-master/BaiduAdBlock/scripts/content.js:
--------------------------------------------------------------------------------
1 | ;
2 | (function () {
3 | var counter = new function () {
4 | var _count = 0;
5 | var _hwdn = 0;
6 |
7 | function delay(handler, delay) {
8 | if (_hwdn) clearTimeout(_hwdn);
9 | _hwdn = setTimeout(handler, delay);
10 | };
11 |
12 | this.add = function (count) {
13 | _count = _count + count;
14 | delay(function () {
15 | _count = 0;
16 | }, 1000);
17 | return _count;
18 | };
19 |
20 | $(function () {
21 | $('[type="submit"]').click(function () {
22 | _count = 0;
23 | });
24 | });
25 | }
26 |
27 | function clearBaiduAd() {
28 | return $("#content_left div[data-click] span:contains('广告')")
29 | .parents("#content_left div[data-click]")
30 | .remove()
31 | .length;
32 | }
33 |
34 | $(document).bind("DOMNodeInserted", function (e) {
35 | var length = clearBaiduAd();
36 | var count = counter.add(length);
37 | chrome.runtime.sendMessage(count);
38 | });
39 | })();
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [Blog](https://github.com/luke93h/git-blog/issues)
2 |
3 | * [react-redux源码分析](https://github.com/luke93h/git-blog/issues/2)
4 | * [redux-saga源码分析](https://github.com/luke93h/git-blog/issues/3)
5 | * [redux源码分析](https://github.com/luke93h/git-blog/issues/4)
6 | * [the-super-tiny-compiler.js中文翻译](https://github.com/luke93h/git-blog/blob/master/the-super-tiny-compiler.js)/[源码地址](https://github.com/jamiebuilds/the-super-tiny-compiler)
7 | * [javascript之toFixed踩坑记录](https://github.com/luke93h/git-blog/issues/5)
8 | * [js线程](https://github.com/luke93h/git-blog/issues/6)
9 | * [react架构分析](https://github.com/luke93h/git-blog/issues/7)
10 | * [react事件系统分析](https://github.com/luke93h/git-blog/issues/10)
11 | * [reactsetState分析](https://github.com/luke93h/git-blog/issues/11)
12 | * [自问自答](https://github.com/luke93h/git-blog/issues/9)
13 | * [vscode路径别名问题](https://github.com/luke93h/git-blog/issues/12)
14 | * [git回滚 ](https://github.com/luke93h/git-blog/issues/13)
15 | * [黑科技-react如何获取父元素](https://github.com/luke93h/git-blog/issues/14)
16 | * [黑科技-react如何从dom上获取fiber实例](https://github.com/luke93h/git-blog/issues/15)
17 | * [redux插件原理详解](https://github.com/luke93h/git-blog/issues/16)
18 |
19 | > 文章保存在issue中
--------------------------------------------------------------------------------
/src/黑科技-react如何获取父元素.md:
--------------------------------------------------------------------------------
1 | ## 黑科技-react如何获取父元素
2 |
3 | 前段时间再学习react的源码,解决了自己的一些疑惑,也发现了一些黑科技操作方法,此处分享给大家。
4 |
5 | 通常父组件获得子组件的实例可以通过ref获取,那子组件如何获取父组件的实例呢?
6 |
7 | 这里提供一种黑科技思路供大家玩耍
8 | ```jsx
9 | import React from "react";
10 | import ReactDOM from "react-dom";
11 |
12 | import "./styles.css";
13 |
14 |
15 | class App extends React.Component {
16 | constructor(props){
17 | super(props)
18 | this.state={
19 | a: 1
20 | }
21 | }
22 | add = () => {
23 | this.setState({
24 | a: this.state.a + 1
25 | })
26 | }
27 | render() {
28 | return
29 |
{this.state.a}
30 |
31 |
32 | }
33 | }
34 |
35 | class Child extends React.Component{
36 | onClick = () => {
37 | let parent = this._reactInternalFiber.return.return.stateNode
38 | parent.add()
39 | }
40 | render(){
41 | return
42 | }
43 | }
44 |
45 | const rootElement = document.getElementById("root");
46 | ReactDOM.render(, rootElement);
47 |
48 | ```
49 |
50 | 此处需要注意的是:
51 | 1. this._reactInternalFiber返回的是fiber对象
52 | 2. Child的return是div,而child的return的return才是App
53 | 3. 通过fiber.stateNode获取组件实例
54 | 4. 如果想要自动找到classCommponent,可以通过判断fiber的tag是否为2向上遍历寻找,此处不再展开。
55 |
56 | [在线调试](https://codesandbox.io/s/ll39p3yo8z)
--------------------------------------------------------------------------------
/src/js编写动画的方式.md:
--------------------------------------------------------------------------------
1 | # js写动画的方式
2 |
3 | 1. setTimeout/setInterval
4 |
5 | ```jsx
6 | let start = (new Date()).getTime()
7 | function move(e, dis){
8 | let now = (new Date()).getTime()
9 | let elapsed = now - start
10 | let fraction = elapsed/time
11 | if( fraction < 1) {
12 | let x = dis * fraction
13 | e.style.left = x + 'px'
14 | setTimeout(animate, Math.min(25, time-elapsed))
15 | }else{
16 | e.style.left = dis + 'px'
17 | }
18 | }
19 | ```
20 |
21 | 2. requestAnimationFrame
22 |
23 | ```jsx
24 | var start = null;
25 | var element = document.getElementById('SomeElementYouWantToAnimate');
26 | element.style.position = 'absolute';
27 |
28 | function step(timestamp) {
29 | if (!start) start = timestamp;
30 | var progress = timestamp - start;
31 | element.style.left = Math.min(progress / 10, 200) + 'px';
32 | if (progress < 2000) {
33 | window.requestAnimationFrame(step);
34 | }
35 | }
36 |
37 | window.requestAnimationFrame(step);
38 | ```
39 |
40 | 3. className
41 |
42 | ```jsx
43 | dom.className = 'animate'
44 | ```
45 |
46 | ## 总结
47 |
48 | 推荐顺序: className > requestAnimationFrame > setTimeout/setInterval
49 |
50 |
51 | | 类别 | 优点 | 缺点 |
52 | | ------ | ------ | ------ |
53 | | setTimeout/setInterval | - | 性能 最差 |
54 | | requestAnimationFrame | 1.每一帧调用的时机通过浏览器来告知,动画更加流畅。2.可控性好 | 性能差 |
55 | | className | 1.通过css来写动画,性能好。2.js操作少,较为简单 | 只能完成简单的动画,可控性没有js动画高 |
--------------------------------------------------------------------------------
/src/黑科技-react如何从dom上获取fiber实例.md:
--------------------------------------------------------------------------------
1 | ## 黑科技-react如何获取父元素
2 |
3 | 前一篇讲了如何从获取父元素实例方法,本篇来介绍下如何从dom上获取fiber实例。
4 | ```jsx
5 |
6 | import React from "react";
7 | import ReactDOM from "react-dom";
8 |
9 | import "./styles.css";
10 |
11 | class App extends React.Component {
12 | constructor(props) {
13 | super(props);
14 | this.state = {
15 | a: 1
16 | };
17 | }
18 | add = () => {
19 | this.setState({
20 | a: this.state.a + 1
21 | });
22 | };
23 | render() {
24 | return (
25 |
26 |
{this.state.a}
27 |
28 |
29 | );
30 | }
31 | }
32 |
33 | class Child extends React.Component {
34 | onClick = e => {
35 | let internalKey = Object.keys(e.target).filter(
36 | key => key.indexOf("__reactInternalInstance") >= 0
37 | );
38 | let fiber = e.target[internalKey];
39 | let childFiber = getParentClassComponent(fiber);
40 | let parentFiber = getParentClassComponent(childFiber);
41 | parentFiber.stateNode.add();
42 | };
43 | render() {
44 | return ;
45 | }
46 | }
47 |
48 | function getParentClassComponent(fiber) {
49 | let parent = fiber.return;
50 | if (parent.tag === 2) {
51 | return parent;
52 | } else {
53 | return getParentClassComponent(parent);
54 | }
55 | }
56 | const rootElement = document.getElementById("root");
57 | ReactDOM.render(, rootElement);
58 |
59 |
60 |
61 | ```
62 |
63 |
64 | [在线调试](https://codesandbox.io/s/101k4mr1ol)
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/demo/js/mypanel.js:
--------------------------------------------------------------------------------
1 | // 检测jQuery
2 | document.getElementById('check_jquery').addEventListener('click', function()
3 | {
4 | // 访问被检查的页面DOM需要使用inspectedWindow
5 | // 简单例子:检测被检查页面是否使用了jQuery
6 | chrome.devtools.inspectedWindow.eval("jQuery.fn.jquery", function(result, isException)
7 | {
8 | var html = '';
9 | if (isException) html = '当前页面没有使用jQuery。';
10 | else html = '当前页面使用了jQuery,版本为:'+result;
11 | alert(html);
12 | });
13 | });
14 |
15 | // 打开某个资源
16 | document.getElementById('open_resource').addEventListener('click', function()
17 | {
18 | chrome.devtools.inspectedWindow.eval("window.location.href", function(result, isException)
19 | {
20 | chrome.devtools.panels.openResource(result, 20, function()
21 | {
22 | console.log('资源打开成功!');
23 | });
24 | });
25 | });
26 |
27 | // 审查元素
28 | document.getElementById('test_inspect').addEventListener('click', function()
29 | {
30 | chrome.devtools.inspectedWindow.eval("inspect(document.images[0])", function(result, isException){});
31 | });
32 |
33 | // 获取所有资源
34 | document.getElementById('get_all_resources').addEventListener('click', function()
35 | {
36 | chrome.devtools.inspectedWindow.getResources(function(resources)
37 | {
38 | alert(JSON.stringify(resources));
39 | });
40 | });
41 |
42 | var myconsole =
43 | {
44 | _log: function(obj)
45 | {
46 | // 不知为何,这种方式不行
47 | chrome.devtools.inspectedWindow('console.log('+JSON.stringify(obj)+')');
48 | },
49 | log: function(obj)
50 | {
51 | // 这里有待完善
52 | chrome.tabs.executeScript(chrome.devtools.inspectedWindow.tabId, {code: 'console.log(' + JSON.stringify(obj) + ')'}, function(){});
53 | }
54 | };
55 |
--------------------------------------------------------------------------------
/react-test/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
22 | React App
23 |
24 |
25 |
28 |
29 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/demo/css/custom.css:
--------------------------------------------------------------------------------
1 | .chrome-plugin-demo-panel {
2 | position: fixed;
3 | right: 0;
4 | bottom: 10px;
5 | background: #3385ff;
6 | padding: 10px;
7 | box-shadow: 0px 0px 10px #002761;
8 | border-radius: 3px;
9 | color: white;
10 | }
11 | .chrome-plugin-demo-panel a{
12 | color: white;
13 | text-decoration: none;
14 | font-size: 16px;
15 | }
16 | .chrome-plugin-demo-panel a:hover{
17 | text-decoration: underline;
18 | color: #ffee08;
19 | }
20 | .chrome-plugin-simple-tip {
21 | position: fixed;
22 | left: 20px;
23 | padding: 16px 10px;
24 | top: 30px;
25 | color: white;
26 | min-width: 150px;
27 | max-width: 700px;
28 | border-radius: 3px;
29 | text-align: center;
30 | font-size: 16px;
31 | background: #70a800;
32 | background-image: linear-gradient(to bottom, #95cc2a, #70a800);
33 | box-shadow: 0 0 3px rgba(0, 0, 0, .2);
34 | transition: top .4s;
35 | }
36 | .animated {
37 | -webkit-animation-duration: .5s;
38 | animation-duration: .5s;
39 | -webkit-animation-fill-mode: both;
40 | animation-fill-mode: both
41 | }
42 | @-webkit-keyframes slideInLeft {
43 | 0% {
44 | -webkit-transform: translate3d(-100%,0,0);
45 | transform: translate3d(-100%,0,0);
46 | visibility: visible
47 | }
48 |
49 | 100% {
50 | -webkit-transform: translate3d(0,0,0);
51 | transform: translate3d(0,0,0)
52 | }
53 | }
54 |
55 | @keyframes slideInLeft {
56 | 0% {
57 | -webkit-transform: translate3d(-100%,0,0);
58 | transform: translate3d(-100%,0,0);
59 | visibility: visible
60 | }
61 |
62 | 100% {
63 | -webkit-transform: translate3d(0,0,0);
64 | transform: translate3d(0,0,0)
65 | }
66 | }
67 |
68 | .slideInLeft {
69 | -webkit-animation-name: slideInLeft;
70 | animation-name: slideInLeft
71 | }
--------------------------------------------------------------------------------
/src/图片串行加载.md:
--------------------------------------------------------------------------------
1 | # 图片串行加载
2 |
3 | ## 背景
4 |
5 | 最近开发中遇到了一个比较好玩的问题:在一个页面中加载了20多张图片,其中第一张需要放大展示到中心区,由于所有图片时并行加载,导致中心图片加载特别慢,有很长时间是空白状态,体验非常差。思来想去,想到了如下方法,通过串行加载的方式来加载图片。
6 |
7 | ## 解决方式
8 |
9 | 通过render props的方式加入中间件
10 |
11 | ```jsx
12 | import React from 'react';
13 |
14 | class Index extends React.Component {
15 | constructor(props) {
16 | super(props);
17 | this.state = {
18 | loaded: {},
19 | };
20 | this.imgs = [];
21 | this.preloadImgs(props.imgs);
22 | }
23 | componentWillReceiveProps(nextProps) {
24 | let { imgs } = nextProps;
25 | this.preloadImgs(imgs);
26 | }
27 | preloadImgs = imgs => {
28 | let { defaultSrc = '', srcName = 'src', keyName = 'id' } = this.props;
29 | imgs.forEach(img => {
30 | let { id } = img;
31 | if (this.state.loaded[id]) {
32 | return;
33 | }
34 | if (this.imgs.some(item => item.id === img.id)) {
35 | return;
36 | }
37 | this.imgs.push(img);
38 | if (this.preloading) {
39 | return;
40 | }
41 | this.preload(this.imgs.length - 1);
42 | });
43 | };
44 | preload = index => {
45 | index = index || 0;
46 | if (index >= this.imgs.length) {
47 | this.preloading = false;
48 | return false;
49 | }
50 | this.preloading = true;
51 | let { id } = this.imgs[index];
52 | let oImg = new Image();
53 | oImg.onload = () => {
54 | this.setState({
55 | loaded: {
56 | ...this.state.loaded,
57 | [id]: true,
58 | },
59 | });
60 | this.preload(index + 1);
61 | };
62 | oImg.onerror = () => {
63 | this.preload(index + 1);
64 | };
65 | oImg.src = this.imgs[index].src;
66 | };
67 | render() {
68 | let { imgs, defaultSrc = '', srcName = 'src', keyName = 'id' } = this.props;
69 | let imgs=imgs.map(item => ({ ...item, src: this.state.loaded[item[idName]] ? item[keyName] : defaultSrc }))
70 | return this.props.children(imgs)
71 | }
72 | }
73 | export default Index;
74 | ```
75 |
--------------------------------------------------------------------------------
/examples/chrome-extension/js/content.js:
--------------------------------------------------------------------------------
1 | (function(){
2 | var listeners = []
3 | var iframe = document.getElementById('contentIFrame0')
4 | var intervalCode = 0
5 | iframe.addEventListener('load', function(){
6 | for(var i= 0;i=numberList.length){
24 | number = numberList[numberList.length-1]
25 | }else{
26 | number = numberList[i]
27 | }
28 | listeners.push(function(){
29 | var list = _document.querySelectorAll('#tableList tr.odd-row td')
30 | var name = list[1].innerText
31 | var stock = list[list.length-1].innerText
32 | var info = {name: name, stock: stock, code: code, number: number, time: getNowTime() }
33 | sendMessageToPopup({type:'refresh', payload:info});
34 | })
35 | _document.getElementById('txtProduct').value=codeList[i]
36 | _document.getElementById('btnSearch').click()
37 | if(i>=codeList.length-1){
38 | i=0
39 | }else{
40 | i++
41 | }
42 | }
43 | cb()
44 | intervalCode = setInterval(cb, interval*1000)
45 | }
46 | });
47 |
48 | function sendMessageToPopup(message){
49 | chrome.runtime.sendMessage('gcjefpdikjlgpndiafaiffmbnjdphkph', message)
50 | }
51 | function getNowTime(){
52 | var d = new Date()
53 | return d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds()
54 | }
55 | })()
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/demo/popup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | popup页
5 |
6 |
7 |
15 |
16 |
17 | 这是一个popup页面!
18 | background
19 |
26 | 窗口操作演示
27 |
34 | 标签操作演示
35 |
41 | popup与content-script交互
42 |
46 | DOM交互演示
47 |
51 | 国际化演示
52 |
53 |
(另外请到插件列表页查看描述的变化)
54 |
55 | 其它
56 |
62 | 更多
63 |
64 | 百度广告,右键菜单,omnibox,图片大小演示,devtools演示,sidebar演示,
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/examples/chrome-extension/popup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Getting Started Extension's Popup
8 |
50 |
51 |
52 |
53 |
54 | 自动查询库存量
55 |
56 |
57 | 商品码:
58 |
59 |
60 |
61 | 数量:
62 |
63 |
64 |
68 |
69 | 结果
70 |
71 |
72 |
73 | |
74 | 商品名
75 | |
76 |
77 | 最新库存量
78 | |
79 |
80 | 更新事件
81 | |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/react-test/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/demo/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | // 清单文件的版本,这个必须写,而且必须是2
3 | "manifest_version": 2,
4 | // 插件的名称
5 | "name": "demo",
6 | // 插件的版本
7 | "version": "1.0.0",
8 | // 插件描述
9 | "description": "__MSG_pluginDesc__",
10 | // 图标,一般偷懒全部用一个尺寸的也没问题
11 | "icons":
12 | {
13 | "16": "img/icon.png",
14 | "48": "img/icon.png",
15 | "128": "img/icon.png"
16 | },
17 | // 会一直常驻的后台JS或后台页面
18 | "background":
19 | {
20 | // 2种指定方式,如果指定JS,那么会自动生成一个背景页
21 | "page": "background.html"
22 | //"scripts": ["js/background.js"]
23 | },
24 | // 浏览器右上角图标设置,browser_action、page_action、app必须三选一
25 | "browser_action":
26 | {
27 | "default_icon": "img/icon.png",
28 | // 图标悬停时的标题,可选
29 | "default_title": "这是一个示例Chrome插件",
30 | "default_popup": "popup.html"
31 | },
32 | // 当某些特定页面打开才显示的图标
33 | /*"page_action":
34 | {
35 | "default_icon": "img/icon.png",
36 | "default_title": "我是pageAction",
37 | "default_popup": "popup.html"
38 | },*/
39 | // 需要直接注入页面的JS
40 | "content_scripts":
41 | [
42 | {
43 | //"matches": ["http://*/*", "https://*/*"],
44 | // "" 表示匹配所有地址
45 | "matches": [""],
46 | // 多个JS按顺序注入
47 | "js": ["js/jquery-1.8.3.js", "js/content-script.js"],
48 | // JS的注入可以随便一点,但是CSS的注意就要千万小心了,因为一不小心就可能影响全局样式
49 | "css": ["css/custom.css"],
50 | // 代码注入的时间,可选值: "document_start", "document_end", or "document_idle",最后一个表示页面空闲时,默认document_idle
51 | "run_at": "document_start"
52 | },
53 | // 这里仅仅是为了演示content-script可以配置多个规则
54 | {
55 | "matches": ["*://*/*.png", "*://*/*.jpg", "*://*/*.gif", "*://*/*.bmp"],
56 | "js": ["js/show-image-content-size.js"]
57 | }
58 | ],
59 | // 权限申请
60 | "permissions":
61 | [
62 | "contextMenus", // 右键菜单
63 | "tabs", // 标签
64 | "notifications", // 通知
65 | "webRequest", // web请求
66 | "webRequestBlocking", // 阻塞式web请求
67 | "storage", // 插件本地存储
68 | "http://*/*", // 可以通过executeScript或者insertCSS访问的网站
69 | "https://*/*" // 可以通过executeScript或者insertCSS访问的网站
70 | ],
71 | // 普通页面能够直接访问的插件资源列表,如果不设置是无法直接访问的
72 | "web_accessible_resources": ["js/inject.js"],
73 | // 插件主页,这个很重要,不要浪费了这个免费广告位
74 | "homepage_url": "https://www.baidu.com",
75 | // 覆盖浏览器默认页面
76 | "chrome_url_overrides":
77 | {
78 | // 覆盖浏览器默认的新标签页
79 | "newtab": "newtab.html"
80 | },
81 | // Chrome40以前的插件配置页写法
82 | "options_page": "options.html",
83 | // Chrome40以后的插件配置页写法,如果2个都写,新版Chrome只认后面这一个
84 | "options_ui":
85 | {
86 | "page": "options.html",
87 | // 添加一些默认的样式,推荐使用
88 | "chrome_style": true
89 | },
90 | // 向地址栏注册一个关键字以提供搜索建议,只能设置一个关键字
91 | "omnibox": { "keyword" : "go" },
92 | // 默认语言
93 | "default_locale": "zh_CN",
94 | // devtools页面入口,注意只能指向一个HTML文件,不能是JS文件
95 | "devtools_page": "devtools.html"
96 | }
--------------------------------------------------------------------------------
/src/redux插件原理详解.md:
--------------------------------------------------------------------------------
1 | # redux插件原理详解
2 |
3 |
4 | ## 前言
5 |
6 | redux本身代码量十分精简,出去注释,代码量也就100多行,大部分逻辑页非常好动。唯一有点难处的就是它的插件机制。
7 |
8 | 本文目标便是帮助给为彻底理解redux的插件机制
9 |
10 | ## 背景
11 |
12 | 1. 本文介绍基于[redux-4.0.0](https://github.com/reduxjs/redux)
13 | 2. 本文分析源码的源码文件为:
14 | - [createStore.js](https://github.com/reduxjs/redux/blob/master/src/createStore.js)
15 | - [applyMiddleware.js](https://github.com/reduxjs/redux/blob/master/src/applyMiddleware.js)
16 | - [compose.js](https://github.com/reduxjs/redux/blob/master/src/createStore.js)
17 |
18 | ## 使用方法
19 |
20 | ```jsx
21 | import { createStore, applyMiddleware } from 'redux'
22 | import reducer from './reducers'
23 | import middleware from './middleware'
24 |
25 | function logger(store) {
26 | return (next) => (action) => {
27 | let returnValue = next(action)
28 | return returnValue
29 | }
30 | }
31 |
32 | let store = createStore(
33 | reducer,
34 | [ 'Use Redux' ],
35 | applyMiddleware(middleware)
36 | )
37 | ```
38 |
39 | 可以看到createStore接受三个参数,第一个参数为reducer,第二个参数为state的初始值,第三个参数为enhancer。
40 |
41 | 接下来就让我们从createStore走进middleware。
42 |
43 | ## createStore
44 |
45 | ```jsx
46 | createStore(reducer, preloadedState, enhancer) {
47 |
48 | // enhancer必须为函数,直接返回由enhancer生成的store
49 | if (typeof enhancer !== 'undefined') {
50 | if (typeof enhancer !== 'function') {
51 | throw new Error('Expected the enhancer to be a function.')
52 | }
53 |
54 | return enhancer(createStore)(reducer, preloadedState)
55 | }
56 |
57 | ...
58 | }
59 | ```
60 |
61 | 可以看到一旦给createStore传入enhancer后,整个store都将由enhancer来生成,接下来我们来走进redux应用插件的enhancer,也就是前面的applyMiddleware(middleware)
62 |
63 | ## applyMiddleware
64 |
65 | ```jsx
66 | import compose from './compose'
67 |
68 | export default function applyMiddleware(...middlewares) {
69 | return createStore => (...args) => {
70 | // 通过传进来的createStore生成store
71 | const store = createStore(...args)
72 | // 构建middleware期间禁止调用dispatch
73 | let dispatch = () => {
74 | throw new Error(
75 | `Dispatching while constructing your middleware is not allowed. ` +
76 | `Other middleware would not be applied to this dispatch.`
77 | )
78 | }
79 | // 将要传给middleware的api
80 | const middlewareAPI = {
81 | getState: store.getState,
82 | dispatch: (...args) => dispatch(...args)
83 | }
84 | // 此处传入store
85 | const chain = middlewares.map(middleware => middleware(middlewareAPI))
86 | dispatch = compose(...chain)(store.dispatch)
87 |
88 | return {
89 | ...store,
90 | dispatch
91 | }
92 | }
93 | }
94 |
95 | ```
96 |
97 | 以上就是applymiddleWare的全部代码了,最后再来了解下compose
98 |
99 | ## compose
100 |
101 | ```jsx
102 | function compose(...funcs) {
103 | if (funcs.length === 0) {
104 | return arg => arg
105 | }
106 |
107 | if (funcs.length === 1) {
108 | return funcs[0]
109 | }
110 | // 注册时从左往右执行,
111 | return funcs.reduce((a, b) => (...args) => a(b(...args)))
112 | }
113 |
114 | ```
115 | 嗯,没错compose的代码更少,如果middleWare为[fn1, fn2, fn3],则compose后的顺序为fn1(fn2(fn3(dispatch)))
--------------------------------------------------------------------------------
/src/react16-事件系统分析.md:
--------------------------------------------------------------------------------
1 | # react源码分析-事件系统分析
2 | 
3 |
4 | ## 目录
5 | - [前言](#前言)
6 | - [注册](#注册)
7 | - [trapBubbledEvent](#trapBubbledEvent)
8 | - [触发](#触发)
9 | - [dispatchInteractiveEvent](#dispatchInteractiveEvent)
10 | - [dispatchEvent](#dispatchEvent)
11 | - [handleTopLevel](#handleTopLevel)
12 | - [runExtractedEventsInBatch](#runExtractedEventsInBatch)
13 | - [SyntheticEvent](#SyntheticEvent)
14 | - [traverseTwoPhase](#traverseTwoPhase)
15 | - [executeDispatchesInOrder](#executeDispatchesInOrder)
16 |
17 | ## 前言
18 |
19 | 在开发react项目时,是否有过这样的困惑:
20 | 1. react每次render后,会在dom上重新注册事件监听函数吗?
21 | 2. 事件监听函数里面的event是原生的event吗?如果不是,是如何生成的呢?
22 |
23 |
24 | ## 注册
25 |
26 | ## trapBubbledEvent
27 |
28 | 监听冒泡事件,由用户触发的事件绑定的监听函数为dispatchInteractiveEvent
29 |
30 | ## 触发
31 |
32 | ## dispatchInteractiveEvent
33 |
34 | 调用dispatchEvent
35 |
36 | ## dispatchEvent
37 |
38 | 在createInstance时,会在对应的dom对象上保存对应的fiber实例,dispatchEvent就是从dom实例上获取对应的fiber信息的
39 | ```jsx
40 | function precacheFiberNode(hostInst, node) {
41 | node[internalInstanceKey] = hostInst;
42 | }
43 | ```
44 |
45 | booking中保存有4个信息:
46 | 1. ancestors: 祖先元素
47 | 2. nativeEvent: 原生event对象
48 | 3. targetInst: target对应的fiber
49 | 4. topLevelType: 事件类型
50 |
51 | ## handleTopLevel
52 |
53 | handleTopLevel接受booking作为参数,在此步骤中会填充ancestors对象
54 |
55 | ## runExtractedEventsInBatch
56 |
57 | runExtractedEventsInBatch里面分为两个步骤,一是生成事件对象,而是触发事件
58 |
59 | ## SyntheticEvent
60 |
61 | 生成react的事件对象时,最终要的就是SyntheticEvent这个构造函数了。
62 | 接下来来分析下SyntheticEvent构造函数调用时所作的事情,以及一些方法
63 |
64 | ### 构造函数
65 |
66 | 会根据Interface上的内容,将原生对象上的属性拷贝到当前实例上
67 |
68 | ### preventDefault、stopPropagation
69 |
70 | 模拟原生的方法,并调用原生的方法,但只能组织到document一层,因为事件函数注册在document上,调用后会在event上标记变量
71 |
72 | ### persist
73 |
74 | 标记isPersistent为true
75 |
76 | ### destructor
77 |
78 | 将当前实例上的属性清空
79 |
80 | ### SyntheticEvent.Interface
81 |
82 | 接口,event上需要哪些数据
83 |
84 | ### SyntheticEvent.extend
85 |
86 | 扩展Interface,并生成新的构造函数
87 |
88 | ### addEventPoolingTo
89 |
90 | EventConstructor的扩展功能,有三个属性
91 | 1. eventPool:用于保存废弃的event
92 | 2. getPooled: 获取旧的event引用
93 | 3. release: 初始化并保存event实例
94 |
95 | ## traverseTwoPhase
96 | towPhase是指捕获阶段和冒泡阶段。
97 |
98 | 通过listenerAtPhase获取监听函数,然后在event上保存linstener和instance
99 | ```jsx
100 | function accumulateDirectionalDispatches(inst, phase, event) {
101 | var listener = listenerAtPhase(inst, event, phase);
102 | if (listener) {
103 | event._dispatchListeners = accumulateInto(event._dispatchListeners, listener);
104 | event._dispatchInstances = accumulateInto(event._dispatchInstances, inst);
105 | }
106 | }
107 | ```
108 |
109 | ## listenerAtPhase
110 |
111 | 通过node[internalEventHandlersKey]获取属性,然后获得相应的监听函数,该属性在createInstance阶段被保存在dom对象上
112 |
113 | ## executeDispatch
114 |
115 | 从event上获得instance和listener
116 |
117 | ## ReactErrorUtils.invokeGuardedCallbackAndCatchFirstError
118 |
119 | 创建一个fakeDom,在fakeDom上绑定事件,并处罚事件,在事件监听函数中调用listener
120 |
121 | ## 后续
122 |
123 | 在执行完事件监听函数后,流程跳转至performWorkOnRoot,会更新react tree
124 |
125 |
126 | ## 相关
127 |
128 |
129 | - [react源码分析-reactDom.render](https://github.com/luke93h/git-blog/issues/7)
130 | - [setState分析](https://github.com/luke93h/git-blog/issues/11)
131 |
--------------------------------------------------------------------------------
/react-test/src/registerServiceWorker.js:
--------------------------------------------------------------------------------
1 | // In production, we register a service worker to serve assets from local cache.
2 |
3 | // This lets the app load faster on subsequent visits in production, and gives
4 | // it offline capabilities. However, it also means that developers (and users)
5 | // will only see deployed updates on the "N+1" visit to a page, since previously
6 | // cached resources are updated in the background.
7 |
8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
9 | // This link also includes instructions on opting out of this behavior.
10 |
11 | const isLocalhost = Boolean(
12 | window.location.hostname === 'localhost' ||
13 | // [::1] is the IPv6 localhost address.
14 | window.location.hostname === '[::1]' ||
15 | // 127.0.0.1/8 is considered localhost for IPv4.
16 | window.location.hostname.match(
17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
18 | )
19 | );
20 |
21 | export default function register() {
22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
23 | // The URL constructor is available in all browsers that support SW.
24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
25 | if (publicUrl.origin !== window.location.origin) {
26 | // Our service worker won't work if PUBLIC_URL is on a different origin
27 | // from what our page is served on. This might happen if a CDN is used to
28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
29 | return;
30 | }
31 |
32 | window.addEventListener('load', () => {
33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
34 |
35 | if (isLocalhost) {
36 | // This is running on localhost. Lets check if a service worker still exists or not.
37 | checkValidServiceWorker(swUrl);
38 |
39 | // Add some additional logging to localhost, pointing developers to the
40 | // service worker/PWA documentation.
41 | navigator.serviceWorker.ready.then(() => {
42 | console.log(
43 | 'This web app is being served cache-first by a service ' +
44 | 'worker. To learn more, visit https://goo.gl/SC7cgQ'
45 | );
46 | });
47 | } else {
48 | // Is not local host. Just register service worker
49 | registerValidSW(swUrl);
50 | }
51 | });
52 | }
53 | }
54 |
55 | function registerValidSW(swUrl) {
56 | navigator.serviceWorker
57 | .register(swUrl)
58 | .then(registration => {
59 | registration.onupdatefound = () => {
60 | const installingWorker = registration.installing;
61 | installingWorker.onstatechange = () => {
62 | if (installingWorker.state === 'installed') {
63 | if (navigator.serviceWorker.controller) {
64 | // At this point, the old content will have been purged and
65 | // the fresh content will have been added to the cache.
66 | // It's the perfect time to display a "New content is
67 | // available; please refresh." message in your web app.
68 | console.log('New content is available; please refresh.');
69 | } else {
70 | // At this point, everything has been precached.
71 | // It's the perfect time to display a
72 | // "Content is cached for offline use." message.
73 | console.log('Content is cached for offline use.');
74 | }
75 | }
76 | };
77 | };
78 | })
79 | .catch(error => {
80 | console.error('Error during service worker registration:', error);
81 | });
82 | }
83 |
84 | function checkValidServiceWorker(swUrl) {
85 | // Check if the service worker can be found. If it can't reload the page.
86 | fetch(swUrl)
87 | .then(response => {
88 | // Ensure service worker exists, and that we really are getting a JS file.
89 | if (
90 | response.status === 404 ||
91 | response.headers.get('content-type').indexOf('javascript') === -1
92 | ) {
93 | // No service worker found. Probably a different app. Reload the page.
94 | navigator.serviceWorker.ready.then(registration => {
95 | registration.unregister().then(() => {
96 | window.location.reload();
97 | });
98 | });
99 | } else {
100 | // Service worker found. Proceed as normal.
101 | registerValidSW(swUrl);
102 | }
103 | })
104 | .catch(() => {
105 | console.log(
106 | 'No internet connection found. App is running in offline mode.'
107 | );
108 | });
109 | }
110 |
111 | export function unregister() {
112 | if ('serviceWorker' in navigator) {
113 | navigator.serviceWorker.ready.then(registration => {
114 | registration.unregister();
115 | });
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/demo/js/background.js:
--------------------------------------------------------------------------------
1 | //-------------------- 右键菜单演示 ------------------------//
2 | chrome.contextMenus.create({
3 | title: "测试右键菜单",
4 | onclick: function(){
5 | chrome.notifications.create(null, {
6 | type: 'basic',
7 | iconUrl: 'img/icon.png',
8 | title: '这是标题',
9 | message: '您刚才点击了自定义右键菜单!'
10 | });
11 | }
12 | });
13 | chrome.contextMenus.create({
14 | title: '使用度娘搜索:%s', // %s表示选中的文字
15 | contexts: ['selection'], // 只有当选中文字时才会出现此右键菜单
16 | onclick: function(params)
17 | {
18 | // 注意不能使用location.href,因为location是属于background的window对象
19 | chrome.tabs.create({url: 'https://www.baidu.com/s?ie=utf-8&wd=' + encodeURI(params.selectionText)});
20 | }
21 | });
22 |
23 |
24 |
25 | //-------------------- badge演示 ------------------------//
26 | /*(function()
27 | {
28 | var showBadge = false;
29 | var menuId = chrome.contextMenus.create({
30 | title: '显示图标上的Badge',
31 | type: 'checkbox',
32 | checked: false,
33 | onclick: function() {
34 | if(!showBadge)
35 | {
36 | chrome.browserAction.setBadgeText({text: 'New'});
37 | chrome.browserAction.setBadgeBackgroundColor({color: [255, 0, 0, 255]});
38 | chrome.contextMenus.update(menuId, {title: '隐藏图标上的Badge', checked: true});
39 | }
40 | else
41 | {
42 | chrome.browserAction.setBadgeText({text: ''});
43 | chrome.browserAction.setBadgeBackgroundColor({color: [0, 0, 0, 0]});
44 | chrome.contextMenus.update(menuId, {title: '显示图标上的Badge', checked: false});
45 | }
46 | showBadge = !showBadge;
47 | }
48 | });
49 | })();*/
50 |
51 | // 监听来自content-script的消息
52 | chrome.runtime.onMessage.addListener(function(request, sender, sendResponse)
53 | {
54 | console.log('收到来自content-script的消息:');
55 | console.log(request, sender, sendResponse);
56 | sendResponse('我是后台,我已收到你的消息:' + JSON.stringify(request));
57 | });
58 |
59 | $('#test_cors').click((e) => {
60 | $.get('https://www.baidu.com', function(html){
61 | console.log( html);
62 | alert('跨域调用成功!');
63 | });
64 | });
65 |
66 | $('#get_popup_title').click(e => {
67 | var views = chrome.extension.getViews({type:'popup'});
68 | if(views.length > 0) {
69 | alert(views[0].document.title);
70 | } else {
71 | alert('popup未打开!');
72 | }
73 | });
74 |
75 | // 获取当前选项卡ID
76 | function getCurrentTabId(callback)
77 | {
78 | chrome.tabs.query({active: true, currentWindow: true}, function(tabs)
79 | {
80 | if(callback) callback(tabs.length ? tabs[0].id: null);
81 | });
82 | }
83 |
84 | // 当前标签打开某个链接
85 | function openUrlCurrentTab(url)
86 | {
87 | getCurrentTabId(tabId => {
88 | chrome.tabs.update(tabId, {url: url});
89 | })
90 | }
91 |
92 | // 新标签打开某个链接
93 | function openUrlNewTab(url)
94 | {
95 | chrome.tabs.create({url: url});
96 | }
97 |
98 | // omnibox 演示
99 | chrome.omnibox.onInputChanged.addListener((text, suggest) => {
100 | console.log('inputChanged: ' + text);
101 | if(!text) return;
102 | if(text == '美女') {
103 | suggest([
104 | {content: '中国' + text, description: '你要找“中国美女”吗?'},
105 | {content: '日本' + text, description: '你要找“日本美女”吗?'},
106 | {content: '泰国' + text, description: '你要找“泰国美女或人妖”吗?'},
107 | {content: '韩国' + text, description: '你要找“韩国美女”吗?'}
108 | ]);
109 | }
110 | else if(text == '微博') {
111 | suggest([
112 | {content: '新浪' + text, description: '新浪' + text},
113 | {content: '腾讯' + text, description: '腾讯' + text},
114 | {content: '搜狐' + text, description: '搜索' + text},
115 | ]);
116 | }
117 | else {
118 | suggest([
119 | {content: '百度搜索 ' + text, description: '百度搜索 ' + text},
120 | {content: '谷歌搜索 ' + text, description: '谷歌搜索 ' + text},
121 | ]);
122 | }
123 | });
124 |
125 | // 当用户接收关键字建议时触发
126 | chrome.omnibox.onInputEntered.addListener((text) => {
127 | console.log('inputEntered: ' + text);
128 | if(!text) return;
129 | var href = '';
130 | if(text.endsWith('美女')) href = 'http://image.baidu.com/search/index?tn=baiduimage&ie=utf-8&word=' + text;
131 | else if(text.startsWith('百度搜索')) href = 'https://www.baidu.com/s?ie=UTF-8&wd=' + text.replace('百度搜索 ', '');
132 | else if(text.startsWith('谷歌搜索')) href = 'https://www.google.com.tw/search?q=' + text.replace('谷歌搜索 ', '');
133 | else href = 'https://www.baidu.com/s?ie=UTF-8&wd=' + text;
134 | openUrlCurrentTab(href);
135 | });
136 |
137 | // 预留一个方法给popup调用
138 | function testBackground() {
139 | alert('你好,我是background!');
140 | }
141 |
142 | // 是否显示图片
143 | var showImage;
144 | chrome.storage.sync.get({showImage: true}, function(items) {
145 | showImage = items.showImage;
146 | });
147 | // web请求监听,最后一个参数表示阻塞式,需单独声明权限:webRequestBlocking
148 | chrome.webRequest.onBeforeRequest.addListener(details => {
149 | // cancel 表示取消本次请求
150 | if(!showImage && details.type == 'image') return {cancel: true};
151 | // 简单的音视频检测
152 | // 大部分网站视频的type并不是media,且视频做了防下载处理,所以这里仅仅是为了演示效果,无实际意义
153 | if(details.type == 'media') {
154 | chrome.notifications.create(null, {
155 | type: 'basic',
156 | iconUrl: 'img/icon.png',
157 | title: '检测到音视频',
158 | message: '音视频地址:' + details.url,
159 | });
160 | }
161 | }, {urls: [""]}, ["blocking"]);
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/demo/js/content-script.js:
--------------------------------------------------------------------------------
1 | console.log('这是content script!');
2 |
3 | // 注意,必须设置了run_at=document_start 此段代码才会生效
4 | document.addEventListener('DOMContentLoaded', function()
5 | {
6 | // 注入自定义JS
7 | injectCustomJs();
8 | // 给谷歌搜索结果的超链接增加 _target="blank"
9 | if(location.host == 'www.google.com.tw')
10 | {
11 | var objs = document.querySelectorAll('h3.r a');
12 | for(var i=0; iinjected-script操作content-script演示区:
65 |
70 |
71 |
72 | `;
73 | document.body.appendChild(panel);
74 | }
75 |
76 | // 向页面注入JS
77 | function injectCustomJs(jsPath)
78 | {
79 | jsPath = jsPath || 'js/inject.js';
80 | var temp = document.createElement('script');
81 | temp.setAttribute('type', 'text/javascript');
82 | // 获得的地址类似:chrome-extension://ihcokhadfjfchaeagdoclpnjdiokfakg/js/inject.js
83 | temp.src = chrome.extension.getURL(jsPath);
84 | temp.onload = function()
85 | {
86 | // 放在页面不好看,执行完后移除掉
87 | this.parentNode.removeChild(this);
88 | };
89 | document.body.appendChild(temp);
90 | }
91 |
92 | // 接收来自后台的消息
93 | chrome.runtime.onMessage.addListener(function(request, sender, sendResponse)
94 | {
95 | console.log('收到来自 ' + (sender.tab ? "content-script(" + sender.tab.url + ")" : "popup或者background") + ' 的消息:', request);
96 | if(request.cmd == 'update_font_size') {
97 | var ele = document.createElement('style');
98 | ele.innerHTML = `* {font-size: ${request.size}px !important;}`;
99 | document.head.appendChild(ele);
100 | }
101 | else {
102 | tip(JSON.stringify(request));
103 | sendResponse('我收到你的消息了:'+JSON.stringify(request));
104 | }
105 | });
106 |
107 | // 主动发送消息给后台
108 | // 要演示此功能,请打开控制台主动执行sendMessageToBackground()
109 | function sendMessageToBackground(message) {
110 | chrome.runtime.sendMessage({greeting: message || '你好,我是content-script呀,我主动发消息给后台!'}, function(response) {
111 | tip('收到来自后台的回复:' + response);
112 | });
113 | }
114 |
115 | // 监听长连接
116 | chrome.runtime.onConnect.addListener(function(port) {
117 | console.log(port);
118 | if(port.name == 'test-connect') {
119 | port.onMessage.addListener(function(msg) {
120 | console.log('收到长连接消息:', msg);
121 | tip('收到长连接消息:' + JSON.stringify(msg));
122 | if(msg.question == '你是谁啊?') port.postMessage({answer: '我是你爸!'});
123 | });
124 | }
125 | });
126 |
127 | window.addEventListener("message", function(e)
128 | {
129 | console.log('收到消息:', e.data);
130 | if(e.data && e.data.cmd == 'invoke') {
131 | eval('('+e.data.code+')');
132 | }
133 | else if(e.data && e.data.cmd == 'message') {
134 | tip(e.data.data);
135 | }
136 | }, false);
137 |
138 |
139 | function initCustomEventListen() {
140 | var hiddenDiv = document.getElementById('myCustomEventDiv');
141 | if(!hiddenDiv) {
142 | hiddenDiv = document.createElement('div');
143 | hiddenDiv.style.display = 'none';
144 | hiddenDiv.id = 'myCustomEventDiv';
145 | document.body.appendChild(hiddenDiv);
146 | }
147 | hiddenDiv.addEventListener('myCustomEvent', function() {
148 | var eventData = document.getElementById('myCustomEventDiv').innerText;
149 | tip('收到自定义事件:' + eventData);
150 | });
151 | }
152 |
153 | var tipCount = 0;
154 | // 简单的消息通知
155 | function tip(info) {
156 | info = info || '';
157 | var ele = document.createElement('div');
158 | ele.className = 'chrome-plugin-simple-tip slideInLeft';
159 | ele.style.top = tipCount * 70 + 20 + 'px';
160 | ele.innerHTML = `${info}
`;
161 | document.body.appendChild(ele);
162 | ele.classList.add('animated');
163 | tipCount++;
164 | setTimeout(() => {
165 | ele.style.top = '-100px';
166 | setTimeout(() => {
167 | ele.remove();
168 | tipCount--;
169 | }, 400);
170 | }, 3000);
171 | }
--------------------------------------------------------------------------------
/src/react源码分析-reactDom.render.md:
--------------------------------------------------------------------------------
1 | # react源码分析-ReactDom.render流程总览
2 | 
3 |
4 | ## 目录
5 | - 前言
6 | - [背景](#背景)
7 | - [优化内容](#优化内容)
8 | - [初始阶段](#初始阶段)
9 | - [jsx](#jsx)
10 | - [ReactDom.render](#ReactDom.render)
11 | - [legacyCreateRootFromDOMContainer](#legacyCreateRootFromDOMContainer)
12 | - [Fiber](#Fiber)
13 | - [规划阶段](#规划阶段-scheduleWork)
14 | - [ExpirationTime](#ExpirationTime)
15 | - [priority](#priority)
16 | - [调和阶段](#调和-reconciliation)
17 | - [workLoop](#workLoop)
18 | - [beginWork](#beginWork)
19 | - [completeWork](#completeWork)
20 | - [更新阶段](#更新阶段)
21 | - [commitRoot](#commitRoot)
22 |
23 | - [小技巧](#小技巧)
24 | - [参考](#参考)
25 | - [后续](#后续)
26 |
27 | ## 背景
28 |
29 | 距离react16发布已经过去很久了,facebook开发团队耗时2年多,究竟做了什么呢。从下面两张图中可以很直观的看出,react16带来的性能优化
30 | 
31 |
32 | 
33 |
34 | 造成这样的现象主要是因为:单个网页由js、UI渲染线程、浏览器事件触发线程、http请求线程、EventLoop轮询的处理线程等线程组成,其中js引擎线程和ui渲染线程是互斥的,也就是说在处理js任务时,页面将停止渲染,一旦js占用时间过长,造成页面每秒渲染的帧数过低,就会给用造成很明显的卡顿感。
35 |
36 | ## 优化内容
37 |
38 | 1. 新增了Portals、Fragments的组件类型,新增了componentDidCatch、static getDerivedStateFromProps、getSnapshotBeforeUpdate声明周期,componentWillMount、componentWillReceiveProps、componentWillUpdate将会在未来被移除,支持自定义的dom属性,扩展了render函数可返回的类型
39 |
40 | 2. 引入异步架构,优化了包括动画,布局和手势的性能。
41 | - 把可中断的工作拆分成小任务
42 | - 对正在做的工作调整优先次序、重做、复用上次(做了一半的)成果
43 |
44 | 3. 项目体积大幅度缩小,相比前一个大版本,react + react-dom的体积从161.kb(49.8kb gzipped)缩减到了109kb(34.8 kb gzipped),优化幅度高达30%。
45 |
46 | ## jsx
47 |
48 | 编译前:
49 |
50 | ```jsx
51 | Hello, world!
52 | ```
53 |
54 | 编译后:
55 |
56 | ```jsx
57 | React.createElement("h1", {color: "red"}, "Hello, world!")
58 | ```
59 |
60 | ## ReactDom.render
61 |
62 | 将react元素渲染到真实dom中。
63 |
64 | ```jsx
65 | ReactDOM.render(
66 | element,
67 | container,
68 | [callback]
69 | )
70 | ```
71 | [在线尝试](https://codesandbox.io/s/v629p1y197)
72 |
73 | ## legacyRenderSubtreeIntoContainer
74 |
75 | 这个方法除主要做了两件事:
76 | 1. 清除dom容器元素的子元素
77 | ```jsx
78 | while ((rootSibling = container.lastChild)) {
79 | container.removeChild(rootSibling);
80 | }
81 | ```
82 | 2. 创建ReactRoot对象
83 |
84 | ## Fiber
85 |
86 | react在进行组件渲染时,从setState开始到渲染完成整个过程是同步的(“一气呵成”)。
87 | 如果需要渲染的组件比较庞大,js执行会占据主线程时间较长,会导致页面响应度变差,使得react在动画、手势等应用中效果比较差。
88 | 为了解决这个问题,react团队经过两年的工作,重写了react中核心算法——reconciliation。
89 |
90 |
91 | ## 规划阶段-scheduleWork
92 |
93 | 规划更新的过期时间和优先级
94 |
95 | ## ExpirationTime
96 |
97 | 在react16中,随处可见expirationTime这个值,这个值的含义是:
98 | - 所谓的到期时间(ExpirationTime),是相对于调度器初始调用的起始时间而言的一个时间段;调度器初始调用后的某一段时间内,需要调度完成这项更新,这个时间段长度值就是到期时间值。
99 | - 目前react16的异步更新和优先级更新尚未完善,因此本文对此功能将暂不做深究。
100 |
101 | ## priority
102 |
103 | 组件更新的优先级,react16暂未启用,不做深究。
104 |
105 | ## 调和-reconciliation
106 |
107 | React算法,用于计算新旧树上需要更新的部分
108 |
109 | ## workLoop
110 |
111 | 生成FiberTree
112 | 
113 |
114 | ## beginWork
115 |
116 | 根据fiber.tag类型,更新不同的fiber节点。
117 | 节点类型如下:
118 | ```jsx
119 | switch (workInProgress.tag) {
120 | case IndeterminateComponent:
121 | return mountIndeterminateComponent(current, workInProgress, renderExpirationTime);
122 | case FunctionalComponent:
123 | return updateFunctionalComponent(current, workInProgress);
124 | case ClassComponent:
125 | return updateClassComponent(current, workInProgress, renderExpirationTime);
126 | case HostRoot:
127 | return updateHostRoot(current, workInProgress, renderExpirationTime);
128 | case HostComponent:
129 | return updateHostComponent(current, workInProgress, renderExpirationTime);
130 | case HostText:
131 | return updateHostText(current, workInProgress);
132 | case TimeoutComponent:
133 | return updateTimeoutComponent(current, workInProgress, renderExpirationTime);
134 | case HostPortal:
135 | return updatePortalComponent(current, workInProgress, renderExpirationTime);
136 | case ForwardRef:
137 | return updateForwardRef(current, workInProgress);
138 | case Fragment:
139 | return updateFragment(current, workInProgress);
140 | case Mode:
141 | return updateMode(current, workInProgress);
142 | case Profiler:
143 | return updateProfiler(current, workInProgress);
144 | case ContextProvider:
145 | return updateContextProvider(current, workInProgress, renderExpirationTime);
146 | case ContextConsumer:
147 | return updateContextConsumer(current, workInProgress, renderExpirationTime);
148 | default:
149 | invariant_1(false, 'Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue.');
150 | }
151 | ```
152 |
153 | ## completeWork
154 |
155 | 创建dom节点,初始化dom属性
156 |
157 | ## 更新阶段
158 |
159 | 根据前面计算出来的更新类型,在真实dom树上执行对应的操作
160 |
161 | ## commitRoot
162 |
163 | 执行更新操作,分三次递归
164 | 1. commitBeforeMutationLifecycles:调用getSnapshotBeforeUpdate声明周期
165 | 2. commitAllHostEffects:执行所有会产生副作用的操作,插入、更新、移除、ref的unmount
166 | 3. commitAllLifeCycles:生命周期
167 |
168 | ## 小技巧
169 |
170 | - 阅读源码时,可以在本地用create-react-app新建一下小demo项目,然后直接在node_modules中的react-dom.development.js和react.development.js两个文件里的对应方法打断点。
171 |
172 | ## 参考
173 |
174 | - [React16.2源码解析](https://juejin.im/post/5b1b4daff265da6e0f70b5a9)
175 | - [React 16 Fiber源码速览](http://zxc0328.github.io/2017/09/28/react-16-source/)
176 | - [react官方文档](https://reactjs.org/docs/react-dom.html)
177 | - [React Fiber](https://juejin.im/post/5ab7b3a2f265da2378403e57)
178 | - [React Fiber初探](http://blog.codingplayboy.com/2017/12/02/react_fiber/#alternate_fiber)
179 | - [React Fiber Architecture](https://github.com/acdlite/react-fiber-architecture)
180 |
181 | # 后续
182 |
183 | - [事件系统分析](https://github.com/luke93h/git-blog/issues/10)
184 | - [setState分析](https://github.com/luke93h/git-blog/issues/11)
--------------------------------------------------------------------------------
/examples/chrome-plugin-demo-master/demo/js/popup.js:
--------------------------------------------------------------------------------
1 | $(function() {
2 | // 加载设置
3 | var defaultConfig = {color: 'white'}; // 默认配置
4 | chrome.storage.sync.get(defaultConfig, function(items) {
5 | document.body.style.backgroundColor = items.color;
6 | });
7 |
8 | // 初始化国际化
9 | $('#test_i18n').html(chrome.i18n.getMessage("helloWorld"));
10 |
11 |
12 | });
13 |
14 | // 打开后台页
15 | $('#open_background').click(e => {
16 | window.open(chrome.extension.getURL('background.html'));
17 | });
18 |
19 | // 调用后台JS
20 | $('#invoke_background_js').click(e => {
21 | var bg = chrome.extension.getBackgroundPage();
22 | bg.testBackground();
23 | });
24 |
25 | // 获取后台页标题
26 | $('#get_background_title').click(e => {
27 | var bg = chrome.extension.getBackgroundPage();
28 | alert(bg.document.title);
29 | });
30 |
31 | // 设置后台页标题
32 | $('#set_background_title').click(e => {
33 | var title = prompt('请输入background的新标题:', '这是新标题');
34 | var bg = chrome.extension.getBackgroundPage();
35 | bg.document.title = title;
36 | alert('修改成功!');
37 | });
38 |
39 | // 自定义窗体大小
40 | $('#custom_window_size').click(() => {
41 | chrome.windows.getCurrent({}, (currentWindow) => {
42 | var startLeft = 10;
43 | chrome.windows.update(currentWindow.id,
44 | {
45 | left: startLeft * 10,
46 | top: 100,
47 | width: 800,
48 | height: 600
49 | });
50 | var inteval = setInterval(() => {
51 | if(startLeft >= 40) clearInterval(inteval);
52 | chrome.windows.update(currentWindow.id, {left: (++startLeft) * 10});
53 | }, 50);
54 | });
55 | });
56 |
57 | // 最大化窗口
58 | $('#max_current_window').click(() => {
59 | chrome.windows.getCurrent({}, (currentWindow) => {
60 | // state: 可选 'minimized', 'maximized' and 'fullscreen'
61 | chrome.windows.update(currentWindow.id, {state: 'maximized'});
62 | });
63 | });
64 |
65 |
66 | // 最小化窗口
67 | $('#min_current_window').click(() => {
68 | chrome.windows.getCurrent({}, (currentWindow) => {
69 | // state: 可选 'minimized', 'maximized' and 'fullscreen'
70 | chrome.windows.update(currentWindow.id, {state: 'minimized'});
71 | });
72 | });
73 |
74 | // 打开新窗口
75 | $('#open_new_window').click(() => {
76 | chrome.windows.create({state: 'maximized'});
77 | });
78 |
79 | // 关闭全部
80 | $('#close_current_window').click(() => {
81 | chrome.windows.getCurrent({}, (currentWindow) => {
82 | chrome.windows.remove(currentWindow.id);
83 | });
84 | });
85 |
86 | // 新标签打开网页
87 | $('#open_url_new_tab').click(() => {
88 | chrome.tabs.create({url: 'https://www.baidu.com'});
89 | });
90 |
91 | // 当前标签打开网页
92 | $('#open_url_current_tab').click(() => {
93 | getCurrentTabId(tabId => {
94 | chrome.tabs.update(tabId, {url: 'http://www.so.com'});
95 | });
96 | });
97 |
98 | // 获取当前标签ID
99 | $('#get_current_tab_id').click(() => {
100 | getCurrentTabId(tabId => {
101 | alert('当前标签ID:' + tabId);
102 | });
103 | });
104 |
105 | // 高亮tab
106 | $('#highlight_tab').click(() => {
107 | chrome.tabs.highlight({tabs: 0});
108 | });
109 |
110 | // popup主动发消息给content-script
111 | $('#send_message_to_content_script').click(() => {
112 | sendMessageToContentScript('你好,我是popup!', (response) => {
113 | if(response) alert('收到来自content-script的回复:'+response);
114 | });
115 | });
116 |
117 | // 监听来自content-script的消息
118 | chrome.runtime.onMessage.addListener(function(request, sender, sendResponse)
119 | {
120 | console.log('收到来自content-script的消息:');
121 | console.log(request, sender, sendResponse);
122 | sendResponse('我是popup,我已收到你的消息:' + JSON.stringify(request));
123 | });
124 |
125 | // popup与content-script建立长连接
126 | $('#connect_to_content_script').click(() => {
127 | getCurrentTabId((tabId) => {
128 | var port = chrome.tabs.connect(tabId, {name: 'test-connect'});
129 | port.postMessage({question: '你是谁啊?'});
130 | port.onMessage.addListener(function(msg) {
131 | alert('收到长连接消息:'+msg.answer);
132 | if(msg.answer && msg.answer.startsWith('我是'))
133 | {
134 | port.postMessage({question: '哦,原来是你啊!'});
135 | }
136 | });
137 | });
138 | });
139 |
140 | // 获取当前选项卡ID
141 | function getCurrentTabId(callback)
142 | {
143 | chrome.tabs.query({active: true, currentWindow: true}, function(tabs)
144 | {
145 | if(callback) callback(tabs.length ? tabs[0].id: null);
146 | });
147 | }
148 |
149 | // 这2个获取当前选项卡id的方法大部分时候效果都一致,只有少部分时候会不一样
150 | function getCurrentTabId2()
151 | {
152 | chrome.windows.getCurrent(function(currentWindow)
153 | {
154 | chrome.tabs.query({active: true, windowId: currentWindow.id}, function(tabs)
155 | {
156 | if(callback) callback(tabs.length ? tabs[0].id: null);
157 | });
158 | });
159 | }
160 |
161 | // 向content-script主动发送消息
162 | function sendMessageToContentScript(message, callback)
163 | {
164 | getCurrentTabId((tabId) =>
165 | {
166 | chrome.tabs.sendMessage(tabId, message, function(response)
167 | {
168 | if(callback) callback(response);
169 | });
170 | });
171 | }
172 |
173 | // 向content-script注入JS片段
174 | function executeScriptToCurrentTab(code)
175 | {
176 | getCurrentTabId((tabId) =>
177 | {
178 | chrome.tabs.executeScript(tabId, {code: code});
179 | });
180 | }
181 |
182 |
183 | // 演示2种方式操作DOM
184 |
185 | // 修改背景色
186 | $('#update_bg_color').click(() => {
187 | executeScriptToCurrentTab('document.body.style.backgroundColor="red";')
188 | });
189 |
190 | // 修改字体大小
191 | $('#update_font_size').click(() => {
192 | sendMessageToContentScript({cmd:'update_font_size', size: 42}, function(response){});
193 | });
194 |
195 | // 显示badge
196 | $('#show_badge').click(() => {
197 | chrome.browserAction.setBadgeText({text: 'New'});
198 | chrome.browserAction.setBadgeBackgroundColor({color: [255, 0, 0, 255]});
199 | });
200 |
201 | // 隐藏badge
202 | $('#hide_badge').click(() => {
203 | chrome.browserAction.setBadgeText({text: ''});
204 | chrome.browserAction.setBadgeBackgroundColor({color: [0, 0, 0, 0]});
205 | });
206 |
207 | // 显示桌面通知
208 | $('#show_notification').click(e => {
209 | chrome.notifications.create(null, {
210 | type: 'image',
211 | iconUrl: 'img/icon.png',
212 | title: '祝福',
213 | message: '骚年,祝你圣诞快乐!Merry christmas!',
214 | imageUrl: 'img/sds.png'
215 | });
216 | });
217 |
218 | $('#check_media').click(e => {
219 | alert('即将打开一个有视频的网站,届时将自动检测是否存在视频!');
220 | chrome.tabs.create({url: 'http://www.w3school.com.cn/tiy/t.asp?f=html5_video'});
221 | });
--------------------------------------------------------------------------------
/src/我是如何从你的网站盗取银行卡和密码的.md:
--------------------------------------------------------------------------------
1 | # 我是如何从你的网站盗取银行卡和密码的
2 | > 译者:本文翻译自[hackermoon上的文章](https://hackernoon.com/im-harvesting-credit-card-numbers-and-passwords-from-your-site-here-s-how-9a8cb347c5b5),希望本文能唤起广大前端工作者的安全意识,以下为正文:
3 |
4 | ***
5 |
6 | > 以下是一个真实的故事。或者它可能只是基于一个真实的故事。也许这根本不是真的。
7 |
8 | 这周是一个安全恐慌周——似乎每天都有一个新的漏洞被发现。当家里人询问我相关的事情时,我需要假装我很懂行,这真的让我感到很煎熬。
9 |
10 | 看到与我亲近的人都在忧虑“网络安全”,这确实让我有所感触。
11 |
12 | 所以,我怀着沉重的心情,决定干净利落地告诉你,我过去几年是如何偷你的网站上的用户名,密码和信用卡号码。
13 |
14 | ***
15 |
16 | 恶意代码本身非常简单,当它在满足以下条件的页面上运行时,它就能发挥作用:
17 |
18 | * 该页面有一个\