lefter / blog Goto Github PK
View Code? Open in Web Editor NEWPlayground & Live
Playground & Live
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import './styles.scss';
const getRandomColor = () => {
const letters = '0123456789ABCDEF';
let color = '#';
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)]
}
return color;
};
const translateY = (value) => {
return `translateY(${value}px)`;
}
const DynamicBarChart = (props) => {
const [dataQueue, setDataQueue] = useState([]);
const [activeItemIdx, setActiveItemIdx] = useState(0);
const [highestValue, setHighestValue] = useState(0);
const [currentValues, setCurrentValues] = useState({});
const [firstRun, setFirstRun] = useState(false);
let iterationTimeoutHolder = null;
function start () {
if (activeItemIdx > 1) {
return;
}
nextStep(true);
}
function setNextValues () {
if (!dataQueue[activeItemIdx]) {
iterationTimeoutHolder = null;
return;
}
const roundData = dataQueue[activeItemIdx].values;
const nextValues = {};
let highestValue = 0;
roundData.map((c) => {
nextValues[c.id] = {
...c,
color: c.color || (currentValues[c.id] || {}).color || getRandomColor()
};
if (Math.abs(c.value) > highestValue) {
highestValue = Math.abs(c.value);
}
return c;
});
console.table(highestValue);
setCurrentValues(nextValues);
setHighestValue(highestValue);
setActiveItemIdx(activeItemIdx + 1);
}
function nextStep (firstRun = false) {
setFirstRun(firstRun);
setNextValues();
}
useEffect(() => {
setDataQueue(props.data);
}, []);
useEffect(() => {
start();
}, [dataQueue]);
useEffect(() => {
iterationTimeoutHolder = window.setTimeout(nextStep, 1000);
return () => {
if (iterationTimeoutHolder) {
window.clearTimeout(iterationTimeoutHolder);
}
};
}, [activeItemIdx]);
const keys = Object.keys(currentValues);
const { barGapSize, barHeight, showTitle, data } = props;
console.table('data', data);
const maxValue = highestValue / 0.85;
const sortedCurrentValues = keys.sort((a, b) => currentValues[b].value - currentValues[a].value);
const currentItem = dataQueue[activeItemIdx - 1] || {};
return (
<div className="live-chart">
{
<React.Fragment>
{
showTitle &&
<h1>{currentItem.name}</h1>
}
<section className="chart">
<div className="chart-bars" style={{ height: (barHeight + barGapSize) * keys.length }}>
{
sortedCurrentValues.map((key, idx) => {
const currentValueData = currentValues[key];
const value = currentValueData.value
let width = Math.abs((value / maxValue * 100));
let widthStr;
if (isNaN(width) || !width) {
widthStr = '1px';
} else {
widthStr = `${width}%`;
}
return (
<div className={`bar-wrapper`} style={{ transform: translateY((barHeight + barGapSize) * idx), transitionDuration: 200 / 1000 }} key={`bar_${key}`}>
<label>
{
!currentValueData.label
? key
: currentValueData.label
}
</label>
<div className="bar" style={{ height: barHeight, width: widthStr, background: typeof currentValueData.color === 'string' ? currentValueData.color : `linear-gradient(to right, ${currentValueData.color.join(',')})` }} />
<span className="value" style={{ color: typeof currentValueData.color === 'string' ? currentValueData.color : currentValueData.color[0] }}>{currentValueData.value}</span>
</div>
);
})
}
</div>
</section>
</React.Fragment>
}
</div>
);
};
DynamicBarChart.propTypes = {
showTitle: PropTypes.bool,
iterationTimeout: PropTypes.number,
data: PropTypes.array,
startRunningTimeout: PropTypes.number,
barHeight: PropTypes.number,
barGapSize: PropTypes.number,
baseline: PropTypes.number,
};
DynamicBarChart.defaultProps = {
showTitle: true,
iterationTimeout: 200,
data: [],
startRunningTimeout: 0,
barHeight: 50,
barGapSize: 20,
baseline: null,
};
export {
DynamicBarChart
};
function createStore(reducer, initialState){
var currentReducer = reducer;
var currentState = initialState;
var listener = ()=>{}
return {
getState (){
return currentState;
},
dispatch(action){
currentState = currentReducer(currentState, action);
listener(); // 注意这行!
return action;
},
subscribe(newListener){
listener = newListener;
}
}
}
//reducer
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
case 'SETVALUE':
return action.payload
default:
return state
}
}
var store = createStore(counter);
store.subscribe(() =>
console.log(store.getState())
)
store.dispatch({ type: 'INCREMENT' });
store.dispatch({ type: 'DECREMENT' });
store.dispatch({ type: 'SETVALUE', payload:10 });
#运行用户
#user somebody;
#启动进程,通常设置成和cpu的数量相等
worker_processes 1;
#全局错误日志
error_log D:/Tools/nginx-1.10.1/logs/error.log;
error_log D:/Tools/nginx-1.10.1/logs/notice.log notice;
error_log D:/Tools/nginx-1.10.1/logs/info.log info;
#PID文件,记录当前启动的nginx的进程ID
pid D:/Tools/nginx-1.10.1/logs/nginx.pid;
#工作模式及连接数上限
events {
worker_connections 1024; #单个后台worker process进程的最大并发链接数
}
#设定http服务器,利用它的反向代理功能提供负载均衡支持
http {
#设定mime类型(邮件支持类型),类型由mime.types文件定义
include D:/Tools/nginx-1.10.1/conf/mime.types;
default_type application/octet-stream;
#设定日志
log_format main '[$remote_addr] - [$remote_user] [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log D:/Tools/nginx-1.10.1/logs/access.log main;
rewrite_log on;
#sendfile 指令指定 nginx 是否调用 sendfile 函数(zero copy 方式)来输出文件,对于普通应用,
#必须设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为 off,以平衡磁盘与网络I/O处理速度,降低系统的uptime.
sendfile on;
#tcp_nopush on;
#连接超时时间
keepalive_timeout 120;
tcp_nodelay on;
#gzip压缩开关
#gzip on;
#设定实际的服务器列表
upstream zp_server1{
server 127.0.0.1:8089;
}
#HTTP服务器
server {
#监听80端口,80端口是知名端口号,用于HTTP协议
listen 80;
#定义使用www.xx.com访问
server_name www.helloworld.com;
#首页
index index.html
#指向webapp的目录
root D:\01_Workspace\Project\github\zp\SpringNotes\spring-security\spring-shiro\src\main\webapp;
#编码格式
charset utf-8;
#代理配置参数
proxy_connect_timeout 180;
proxy_send_timeout 180;
proxy_read_timeout 180;
proxy_set_header Host $host;
proxy_set_header X-Forwarder-For $remote_addr;
#反向代理的路径(和upstream绑定),location 后面设置映射的路径
location / {
proxy_pass http://zp_server1;
}
#静态文件,nginx自己处理
location ~ ^/(images|javascript|js|css|flash|media|static)/ {
root D:\01_Workspace\Project\github\zp\SpringNotes\spring-security\spring-shiro\src\main\webapp\views;
#过期30天,静态文件不怎么更新,过期可以设大一点,如果频繁更新,则可以设置得小一点。
expires 30d;
}
#设定查看Nginx状态的地址
location /NginxStatus {
stub_status on;
access_log on;
auth_basic "NginxStatus";
auth_basic_user_file conf/htpasswd;
}
#禁止访问 .htxxx 文件
location ~ /\.ht {
deny all;
}
#错误处理页面(可选择性配置)
#error_page 404 /404.html;
#error_page 500 502 503 504 /50x.html;
#location = /50x.html {
# root html;
#}
}
}
上一个例子中,代理仅仅指向一个服务器。
但是,网站在实际运营过程中,多半都是有多台服务器运行着同样的 app,这时需要使用负载均衡来分流。
nginx 也可以实现简单的负载均衡功能。
假设这样一个应用场景:将应用部署在 192.168.1.11:80、192.168.1.12:80、192.168.1.13:80 三台 linux 环境的服务器上。网站域名叫 www.helloworld.com,公网 IP 为 192.168.1.11。在公网 IP 所在的服务器上部署 nginx,对所有请求做负载均衡处理。
http {
#设定mime类型,类型由mime.type文件定义
include /etc/nginx/mime.types;
default_type application/octet-stream;
#设定日志格式
access_log /var/log/nginx/access.log;
#设定负载均衡的服务器列表
upstream load_balance_server {
#weigth参数表示权值,权值越高被分配到的几率越大
server 192.168.1.11:80 weight=5;
server 192.168.1.12:80 weight=1;
server 192.168.1.13:80 weight=6;
}
upstream product_server{
server www.helloworld.com:8081;
}
upstream admin_server{
server www.helloworld.com:8082;
}
upstream finance_server{
server www.helloworld.com:8083;
}
#HTTP服务器
server {
#侦听80端口
listen 80;
#定义使用www.xx.com访问
server_name www.helloworld.com;
#对所有请求进行负载均衡请求
location / {
root /root; #定义服务器的默认网站根目录位置
index index.html index.htm; #定义首页索引文件的名称
proxy_pass http://load_balance_server ;#请求转向load_balance_server 定义的服务器列表
#以下是一些反向代理的配置(可选择性配置)
#proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
#后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
proxy_set_header X-Forwarded-For $remote_addr;
proxy_connect_timeout 90; #nginx跟后端服务器连接超时时间(代理连接超时)
proxy_send_timeout 90; #后端服务器数据回传时间(代理发送超时)
proxy_read_timeout 90; #连接成功后,后端服务器响应时间(代理接收超时)
proxy_buffer_size 4k; #设置代理服务器(nginx)保存用户头信息的缓冲区大小
proxy_buffers 4 32k; #proxy_buffers缓冲区,网页平均在32k以下的话,这样设置
proxy_busy_buffers_size 64k; #高负荷下缓冲大小(proxy_buffers*2)
proxy_temp_file_write_size 64k; #设定缓存文件夹大小,大于这个值,将从upstream服务器传
client_max_body_size 10m; #允许客户端请求的最大单文件字节数
client_body_buffer_size 128k; #缓冲区代理缓冲用户端请求的最大字节数
}
location / {
proxy_pass http://product_server;
}
location /product/{
proxy_pass http://product_server;
}
location /admin/ {
proxy_pass http://admin_server;
}
location /finance/ {
proxy_pass http://finance_server;
}
}
}
举例:www.helloworld.com 网站是由一个前端 app ,一个后端 app 组成的。前端端口号为 9000, 后端端口号为 8080。
首先,在 enable-cors.conf 文件中设置 cors :
# allow origin list
set $ACAO '*';
# set single origin
if ($http_origin ~* (www.helloworld.com)$) {
set $ACAO $http_origin;
}
if ($cors = "trueget") {
add_header 'Access-Control-Allow-Origin' "$http_origin";
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
if ($request_method = 'OPTIONS') {
set $cors "${cors}options";
}
if ($request_method = 'GET') {
set $cors "${cors}get";
}
if ($request_method = 'POST') {
set $cors "${cors}post";
}
```
接下来,在你的服务器中 `include enable-cors.conf` 来引入跨域配置:
```nginx
# ----------------------------------------------------
# 此文件为项目 nginx 配置片段
# 可以直接在 nginx config 中 include(推荐)
# 或者 copy 到现有 nginx 中,自行配置
# www.helloworld.com 域名需配合 dns hosts 进行配置
# 其中,api 开启了 cors,需配合本目录下另一份配置文件
# ----------------------------------------------------
upstream front_server{
server www.helloworld.com:9000;
}
upstream api_server{
server www.helloworld.com:8080;
}
server {
listen 80;
server_name www.helloworld.com;
location ~ ^/api/ {
include enable-cors.conf;
proxy_pass http://api_server;
rewrite "^/api/(.*)$" /$1 break;
}
location ~ ^/ {
proxy_pass http://front_server;
}
}
```
实现数据绑定的做法有大致如下几种:
发布者-订阅者模式backbone.js: 一般通过sub, pub的方式实现数据和视图的绑定监听,更新数据方式通常做法是 vm.set('property', value)
脏值检查: angular.js 是通过脏值检测的方式比对数据是否有变更,来决定是否更新视图,最简单的方式就是通过 setInterval() 定时轮询检测数据变动,当然Google不会这么low,angular只有在指定的事件触发时进入脏值检测,大致如下:
数据劫持: vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
要实现mvvm的双向绑定,就必须要实现以下几点:
let data = { price: 5, quantity: 2 };
let target = null;
class Dep {
constructor() {
this.subscribers = [];
}
depend() {
if (target && !this.subscribers.includes(target)) {
this.subscribers.push(target);
}
}
notify() {
this.subscribers.forEach(sub => sub());
}
}
Object.keys(data).forEach(key => {
let internalValue = data[key];
const dep = new Dep();
Object.defineProperty(data, key, {
get() {
dep.depend();
return internalValue;
},
set(newVal) {
internalValue = newVal;
dep.notify();
}
});
});
function watcher(myFun) {
target = myFun;
target();
target = null;
}
watcher(() => {
data.total = data.price * data.quantity;
});
console.log('total = ' + data.total);
data.price = 20;
console.log('total = ' + data.total);
data.quantity = 10;
console.log('total = ' + data.total);
<script>
class Vue {
constructor(options) {
this.$el = document.querySelector(options.el)
this.$methods = options.methods
this._binding = {}
this._observe(options.data)
this._compile(this.$el)
}
_pushWatcher(watcher) {
//如果 this._binding[watcher.key] 为空,就初始化,然后向里面添加一个 监听器
if (!this._binding[watcher.key]) this._binding[watcher.key] = []
this._binding[watcher.key].push(watcher)
}
_observe(data) {
var that = this
// 把代理器返回的对象存到 this.$data 里面
this.$data = new Proxy(data, {
set(target, key, value) {
// 利用 Reflect 还原默认的赋值操作
let res = Reflect.set(target, key, value)
// 这行就是监控代码了,当触发set的时候,就会执行 that._binding[key].map(item => {item.update()})
//这句代码的作用就是执行 该属性名下的所有 "监视器"
that._binding[key].map(item => { item.update() })
return res
}
})
}
//"编译" html 模板,把有 v-bind、v-model、v-click 都给加上对应的 通知 和 监控
_compile(root) {
const nodes = Array.prototype.slice.call(root.children)
let data = this.$data
nodes.map(node => {
debugger;
// 如果不是末尾节点,就递归
if (node.children.length > 0) this._complie(node)
// 处理 v-bind 指令
if (node.hasAttribute('v-bind')) {
let key = node.getAttribute('v-bind')
this._pushWatcher(new Watcher(node, 'innerHTML', data, key))
}
// 处理 v-model 指令
if (node.hasAttribute('v-model')) {
let key = node.getAttribute('v-model')
this._pushWatcher(new Watcher(node, 'value', data, key))
node.addEventListener('input', () => { data[key] = node.value })
}
// 处理 v-click 指令
if (node.hasAttribute('v-click')) {
let methodName = node.getAttribute('v-click')
let mothod = this.$methods[methodName].bind(data)
node.addEventListener('click', mothod)
}
})
}
}
class Watcher {
constructor(node, attr, data, key) {
this.node = node
this.attr = attr
this.data = data
this.key = key
}
update() {
debugger;
this.node[this.attr] = this.data[this.key]
}
}
// 实例化一个Vue 测试用
window.onload = function () {
window.$app = new Vue({
el: '#app',
data: {
num: 0
},
methods: {
add() {
this.num++
},
sub() {
this.num--
}
}
})
}
</script>
//Use
import useReactRouter from 'use-react-router';
const MyPath = () => {
const { history, location, match } = useReactRouter();
return (
<div>
My location is {location.pathname}!
</div>
);
};
//source
import { LocationState } from 'history';
import { Context, useContext, useEffect } from 'react';
import { __RouterContext, RouteComponentProps, StaticContext } from 'react-router';
import useForceUpdate from 'use-force-update';
type AnyContext = Context<RouteComponentProps<any, any, any>>;
const INCORRECT_VERSION_ERROR: Error =
new Error('use-react-router may only be used with react-router@^5.');
const MISSING_CONTEXT_ERROR: Error =
new Error('useReactRouter may only be called within a <Router /> context.');
export default function useRouter<
P extends { [K in keyof P]?: string } = {},
C extends StaticContext = StaticContext,
S = LocationState,
>(): RouteComponentProps<P, C, S> {
// If this version of react-router does not support Context,
if (!__RouterContext) {
throw INCORRECT_VERSION_ERROR;
}
// If the react-router Context is not a parent Component,
const context: RouteComponentProps<P, C, S> =
useContext<RouteComponentProps<P, C, S>>(
__RouterContext as AnyContext as Context<RouteComponentProps<P, C, S>>,
);
if (!context) {
throw MISSING_CONTEXT_ERROR;
}
const forceUpdate: VoidFunction = useForceUpdate();
useEffect(
(): VoidFunction =>
context.history.listen(forceUpdate),
[ context ],
);
return context;
}
class Scoreboard {
constructor(x) {
this.element = document.getElementById(x);
}
update(score) {
let msg = ''
for (let i in score) {
//Iterating over own properties only
if (score.hasOwnProperty(i)) {
msg += `${i}: ${score[i]}`
}
}
this.element.innerHTML = msg;
}
}
class Player {
constructor(name) {
this.name = name;
this.point = 0;
}
play() {
this.point += 1;
mediator.played();
}
}
class Mediator {
constructor(name) {
this.players = {}
}
setup() {
var players = this.players;
players.home = new Player('Home');
players.guest = new Player('Guest');
}
played() {
let players = this.players;
let score = {
Home: players.home.point,
Guest: players.guest.point,
}
scoreboard.update(score);
}
keypress(e) {
if (e.which == 49) {
mediator.players.home.play();
return;
}
if (e.which == 48) {
mediator.players.guest.play();
return;
}
}
}
var mediator = new Mediator();
var scoreboard = new Scoreboard('result');
mediator.setup();
window.onkeypress = mediator.keypress;
setTimeout(() => {
window.onkeypress = null;
alert('Game Over!');
}, 1e4)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.