0%

数据库

  • 使用mysql模块操作MySQL数据库 npm i mysql
  • 使用docker run -itd –name mysql-test -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql在docker中创建mysql容器
  • 使用navicat连接数据库(localhost root 123456 3306(尽量用3306端口))
    • 出错1:ER_ACCESS_DENIED_ERROR: Access denied for user ‘root‘@’172.17.0.1’ (using password: YES)
      1
      2
      3
      4
      5
      mysql>  CREATE USER 'root'@'172.17.0.1' IDENTIFIED BY 'password';
      mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'172.17.0.1' WITH GRANT OPTION;
      mysql> flush privileges;
      mysql> exit
      参考:https://medium.com/tech-learn-share/docker-mysql-access-denied-for-user-172-17-0-1-using-password-yes-c5eadad582d3
    • 出错2:ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client
      1
      2
      3
      ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';
      flush privileges;
      参考:https://stackoverflow.com/questions/50093144/mysql-8-0-client-does-not-support-authentication-protocol-requested-by-server
  • 使用delete语句会把真正的数据从表中删除,为了保险起见,推荐使用标记删除的形式,设置status状态字段,标记该数据是否被删除(1表示删除)–>转化为update

两种web开发模式

  • 服务端渲染:服务器发送给客户端html页面,是服务器通过字符串的拼接动态生成的,因此客户端不需要使用Ajax这样的技术额外请求页面的数据
  • 前后端分离:依赖于Ajax技术的广泛使用,后端只负责提供API接口,前端使用Ajax调用接口
  • 如何选择?
    • 企业级网站:主要功能是展示而没有复杂交互,需要良好的SEO,使用服务端渲染
    • 后台管理:交互性比较强,不需要考虑SEO,前后端分离 (可以利用vue,react提供的SSR技术解决SEO问题)
    • 有时候为了同时兼顾首页的加载速度和前后端分离的开发效率,采用首屏服务端渲染+其他页面前后端分离开发模式

      身份认证

  • 服务端推荐采用Session认证机制 前后端分离推荐使用JWT认证机制
  • 存储在用户浏览器中一段不超过4KB的字符串,不同域名下的Cookie各自独立,每当客户端发送请求时,会自动把当前域名下所有未过期的Cookie一同发送到服务器 (自动发送 域名独立 过期时限 4KB限制)
  • 客户端第一次请求服务器的时候,服务器通过响应头的形式向客户端发送一个身份认证的Cookie,客户端会自动保存到浏览器中;随后当客户端浏览器每次请求服务器时,浏览器自动将身份认证相关的Cookie通过请求头的形式发送给服务器,服务器即可验证客户端身份
  • Cookie不具有安全性(用户可以伪造Cookie)

    Session

Token

中间件

本质上是一个function处理函数,形参列表中必须包含next参数,next函数是实现多个中间件连续调用的关键,把流转关系转交给下一个中间件或路由(路由是最终处理环节)

  • 作用:多个中间件之间,共享同一份req和res,因此可以在上游中间件中统一为req和res对象添加自定义的属性或方法,供下游的中间件或路由进行使用
  • 全局生效中间件:客户端发送的任何请求到达服务器后都会触发的中间件;
    • 方式:调用app.use(中间件函数)
  • 定义多个全局中间价:使用app.use()连续定义多个全局中间件,客户端请求到达服务器之后,会按照中间件定义的先后顺序依次调用
    docker+express搭建后端并发布
  • 局部生效中间件:不使用app.use()
    1
    2
    3
    4
    5
    6
    7
    const mw1 = function(req,res,next){
    console.log("这是中间件函数")
    next()
    }
    app.get('/',[mw1,mw2],function(req,res){
    res.send('Home page')
    })//mw只会影响当前路由
  • 注意事项
    • 一定要在路由之前注册中间件
  • 分类
    • 应用级别 绑定到app上
    • 路由级别 绑定到router上
    • 错误级别 必须4个形参(err,req,res,next) 必须注册在所有路由之后
    • Express内置 express.static .json .urlencoded
    • 第三方

默认情况下,如果不配置解析表单数据的中间件,则req.body默认等于undefined

1
2
app.use(express.json())//解析raw json格式数据 否则req.body undefined
app.use(express.urlencoded({extended:false}))//解析urlecoded格式数据,否则req.body为空对象
  • 自定义中间件

npm与包

  • 包的语义化版本规范:大版本 功能版本 Bug修复版本
  • npm uninsall 指定包名 开发依赖:-D/–save-dev(devDependencies/开发依赖包只用于开发,dependencies/核心依赖包开发和上线都能用到)

references

http://escook.cn:8088/

http协议是TCP协议的典型应用,是浏览器与服务器交流的主要方式,服务器会监听80端口,等待客户端连接

本blog在创建socket客户端和服务端的基础上,采用python socket和多线程构造一个简易的tinyHTTP,可以通过多线程并发支持多客户端请求,同时对客户端进行响应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# 由socket服务端改造为httpServer,
import socket
import threading
import os

#处理http客户端请求
def handle_http_client(c, addr):
print(addr, "connected.")
WEBROOT = os.path.dirname(__file__)
print("WEBROOT",WEBROOT)
with c:
request = c.recv(1024)

# Parse HTTP headers
headers = request.split(b"\r\n")
print(headers)
file = headers[0].split()[1].decode()
print("file",file)
# Load file content
if file == "/":
file = "index.html"

try:
with open(WEBROOT + file, "rb") as f:
content = f.read()
response = b"HTTP/1.0 200 OK\r\n\r\n" + content
except FileNotFoundError:
response = b"HTTP/1.0 404 NOT FOUND\r\n\r\nFile not found!"
# Send HTTP response
c.sendall(response)

#处理socket客户端请求
def handle_client(c,addr):
print(addr,"connected.")
while True:
data = c.recv(1024)
if not data:
break
c.sendall(data)

with socket.socket(socket.AF_INET,socket.SOCK_STREAM) as s:
s.bind(("0.0.0.0",1234))
s.listen()

while True:
c, addr = s.accept()
t = threading.Thread(target=handle_http_client, args=(c,addr))
t.start()
1
2
3
4
5
6
7
8
# socket客户端 这里未实现http客户端(直接用浏览器代替)
import socket

with socket.socket(socket.AF_INET,socket.SOCK_STREAM) as s:
s.connect(("127.0.0.1",1234))
s.sendall(b"Hello,Xiaoming!")
data = s.recv(1024)
print("Received:",repr(data))

异步编程

  • fs文件操作
  • 数据库操作
  • AJAX
  • 定时器
    旧方案单纯回调函数形式处理

为什么要用Promise

  • 支持链式调用,解决回调地狱问题
  • 指定回调函数的方式更加灵活
    • 旧的:必须在启动异步任务前指定
    • promise: 启动异步任务 => 返回promise对象 => 给promise对象绑定回调函数(甚至可以在异步任务结束之后指定/多个)

针对跨域
http-proxy-middleware在客户端配置
cors在服务端配置

Promise的状态

实例对象中的一个属性 【PromiseState】

  • pending 未决定的
  • resolved/fullfilled 成功
  • rejected 失败
  • Promise状态改变:只有两种,且一个promise对象只能改变一次

Promise对象的值

实例对象的另一个属性 【PromiseResult】
保存的是异步任务【成功/失败】的结果

API

1
2
3
4
5
6
7
8
Promise.prototype.then((value)=>{},(reason)=>{})
Promise.prototype.catch((reason)=>{})//是上面第二个函数对应的语法糖
Promise.resolve();
//如果传入的参数为非promise类型的对象,则返回结果为成功promise对象
//如果传入参数是pr omise对象,则参数的结果决定了resolve的结果
Promise.reject(reason);//返回一个失败的promise对象,值是传入的值(即使他是一个promise)
Promise.all(promises) //参数:n个promise的数组 返回一个新的promise(只有所有的promise都成功才成功,只要一个失败则直接失败,成功结果是每个promise成功结果组成的一个数组,失败结果是数组中失败的那个promise对应的结果)
Promise.race(promises) //参数:n个promise的数组 返回一个新的promise(第一个完成的promise的结果状态就是最终的结果状态)

几个关键问题

  1. 如何改变promise的状态
  • resolve(value)
  • reject(reason)
  • throw Error抛出异常
  1. 一个promise指定多个成功/失败回调函数,则都会调用
    1
    2
    3
    4
    5
    const p = new Promise((resolve,rejected)=>{
    resolve('ok')
    })
    p.then(value=>console.log(value))
    p.then(value=>alert(value))
  2. 改变promise状态和指定回调函数谁先谁后?
  3. promise.then()返回的新promise的结果状态由什么决定?

—由then()指定的回调函数执行的结果决定
5. promise如何串联多个操作任务
—通过then的链式调用串联多个同步/异步任务
6. promise异常穿透
7. 中断promise链
方法:在回调函数中返回一个pending状态的promise对象(状态没有改变,后续.then方法都不能执行)

手写Promise

async与await

  • async函数的返回值为promise对象,对象结果由async函数执行的返回值决定(和.then()的返回结果相同)
  • await右侧的表达式如果是promise对象,则await返回的是promise成功的值,如果表达式是其他值,直接将此值作为await的返回值
  • await必须写在async函数中,但async函数可以没有await;如果await的promise失败了,就会抛出异常,需要通过try…catch捕获处理

背景

react中要求老状态是不可变对象,保证老状态随时可做diff对比去用,如果把老状态直接改了,那diff老状态和新状态就没有区别了

引入Immutable

实现原理:持久化数据结构,使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时为了避免deepCopy把所有节点都复制一遍所带来的性能损耗,Immutable使用了结构共享,即如果对象树中一个节点发生变化,只修改这个节点和受他影响的父节点,其他节点则进行共享。

着色不考虑其他物体的存在,只考虑自己,因此没有阴影(局部性)

凹凸贴图和位移贴图

Blin-Phong模型

很经验的模型但是有一定的物理道理
所有向量均为单位向量,因为只需要夹角参数
Blinn-Phong对Phong的改进:使用半程向量h=bisector(v,1)和n的夹角代替R和v的夹角(反射方向计算量比较大,而半程向量很好算)
高光$k_d$可以定义为白色
环境光和l,v,n均无关,其实是一个常数,就是某一种特定的颜色(实际上不是这回事,精确计算需要全局光照的知识)(其实一个点凹下去的话环境光应该暗一些,而不是和其他点都一样)

shading frequency

  • falt shading 逐三角形
  • Gouraud shading 逐顶点
  • Phong 逐像素

给定顶点法向(平均或者加权平均(和三角形面积加权)),如何插值中间的法线呢
*重心坐标

图形管线(实时渲染管线)
从三位场景到最后渲染出一副二维的图的一个基本操作,集成在显卡中
其中顶点和像素如何着色是可编程的(顶点着色还是像素着色,以及如何着色 )

shader programs

纹理映射

三角形的每个点对应木头纹理上面的每个点
定义任何一个点的属性
三维物体表面其实是二维的,因此可以和一张图有一一对应关系
物体表面一点和纹理上一点的对应关系
怎么把空间上的一个三角形映射到纹理上,我们不管,我们就认为已经有了这么一个映射关系,三角形上的任何一个顶点已经规定好了它在纹理上的坐标
需要纹理上的坐标,因此需要定义纹理上的坐标系,这个坐标系用uv来表示,都认为u在[0,1],v也在[0,1],方便处理,不管分辨率和长宽比
三角形每个顶点都对应一个uv,这就是纹理映射,怎么知道的,假设已经知道了
一个场景可能需要很多个纹理,像贴瓷砖一样,这就涉及到纹理之间的裂缝问题
纹理的无缝衔接的合成

知道了三角形三个顶点对应的纹理坐标uv,如何知道三角形内部三个顶点对应的纹理坐标uv

纹理定义着色时候需要的各个不同点的属性,我不希望着色的时候每个顶点以一种相同的方式来着色,然后用纹理的方式改变一些逐点的属性

如何定义不同的材质或者表面,与光线如何作用,我们就会得到一种怎样的看上去的外观,光线与材质如何作用?

Mipmap只能做近似的正方形的范围查询

利用重心坐标进行插值

重心坐标在投影操作下会发生变化,因此三维空间的属性建议在三维空间中做插值,然后再将值对应在二维结果上

响应式布局是同一页面在不同的屏幕上有不同的布局,即只需要一套代码使页面适应不同的屏幕

Three.js是基于原生WebGL(Javascript的3D图形接口,把JavaScript和OpenGL ES 2.0结合在一起。)封装运行的三维引擎
三要素是:场景(Scene)、相机(Camera)、渲染器(Renderer),下面通过三要素在浏览器中创建几何体并显示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import * as THREE from "three"
// three.js最基本的创建流程
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
camera.position.set(0,0,10)
scene.add(camera)
const cubeGeometry = new THREE.BoxGeometry()
const cubeMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 })
//根据几何体和材质创建物体
const cube = new THREE.Mesh(cubeGeometry,cubeMaterial)
//将几何体添加到场景中
scene.add(cube)
//初始化渲染器
const renderer = new THREE.WebGLRenderer()
//设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight)
//将webgl渲染的canvas内容添加到body
document.body.appendChild(renderer.domElement)
//使用渲染器,通过相机将场景渲染进来
renderer.render(scene,camera)

threejs开源项目目录结构

…后续补坑

References
https://juejin.cn/post/7020396322062598181

git基本命令

1
2
3
4
5
6
7
8
9
10
11
12
13
* git config --global user.name ""
* git config --global user.email ...
* git status查看当前工作流状态
* git log查看提交信息
* git commit -a -m commit_name(-a执行git add) 直接从工作区跳到本地版本库
为当前仓库新增文件,但是该文件还不能确定是否需要,可以在主分支中创建新分支
* git branch branch_name 创建分支
* git checkout branch_name 切换分支
* git checkout -b 创建并切换分支
* git branch -d branch_name 删除分支(不会立即删除,因为没有合并分支,非常确定要删除的时候可以使用 -D)
* git merge branch_name(将分支合并到主分支)
* git remote -v 查看本地仓库和哪些远程仓库有联系(默认用origin表示远程仓库的名字)
* 使用github destop push速度更快

Github

  • PR 是一种通知机制。你修改了他人的代码,将你的修改通知原来的作者,希望他合并你的修改,这就是 Pull Request
  • actions 将持续集成过程变成了一个 actions 的组合

GitLab

  • GitLab有完善的管理界面和权限控制,一般用于在企业、学校等内部网络搭建Git私服。
  • 从代码的私有性上来看,GitLab 是一个更好的选择。但是对于开源项目而言,GitHub 依然是代码托管的首选。

GitBook

(GitBook) 是一个使用 Git 和 Markdown 来构建书籍的工具。它可以将你的书输出很多格式:PDF,ePub,mobi,或者输出为静态网页。

References

https://www.ruanyifeng.com/blog/2019/09/getting-started-with-github-actions.html
https://learngitbranching.js.org/

相关名词介绍

  • ECMA 欧洲计算机制造商协会 制定标准的组织
  • ECMA-262是其中(标准)的一个,即ECMAscript
  • ES6版本变动内容最多,具有里程碑意义,加入很多新语法特性,编程更加简单高效
  • ECMA-262只是纸面标准,实践当中需要每个浏览器厂商对标准进行实现,因此有兼容性的问题

let

  • 变量不能重复声明(var可以)
    1
    2
    let a=1
    let a=2//出错
  • 块级作用域 只在代码块有效
  • 不存在变量提升
    • 变量提升:变量可以在声明之前进行初始化和使用。
    • 只会提升声明,不会提升其初始化
  • 不影响作用域链
  • 经典案例:循环绑定事件
    1
    2
    3
    4
    5
    6
    for (var i=1;i<items.length;i++){
    items[i].onclick = function(){
    items[i].style.background = 'pink'//绑定完事件后i=3,当点击触发click事件时该语句作用域内找不到i,向上级找,在全局window中找到了i,但此时i是3,出错
    }
    }
    //解决方法:1.var 改成let,2.this.style.background

const

  • 一定要赋初始值
  • 一般常量名是用大写
  • 常量值不能修改
  • 块级作用域
  • 对于数组和对象的元素修改,不算做对常量的修改(常量指向的引用地址没有改变)

async/await

  • 用同步的方法写异步代码
  • async函数永远返回一个promise,async/await是基于Promise的语法糖
    js是单线程编程语言(界面逻辑,网络请求,数据处理等都运行在一个进程) :
    • 无需考虑线程同步或资源竞争问题
    • 从源头上避免了线程之间的频繁切换,降低了线程自身的开销

js两种实现异步的方式

  • 回调函数 会产生如下图示的回调地狱
  • Promise应运而生(fetch是js中一个使用了Promise的API)(承诺这个请求会在未来某个时刻返回数据)
    1
    2
    3
    4
    5
    fetch("https://...")
    .then((res)=> res.json())
    .then((json)=>console.log(json))
    .catch((error)=>console.log(error))//如果之前任一个then出现错误,那么catch会被触发,后面的then将不会执行
    .finally(()=>{})//执行清理工作
    promise的链式调用避免了代码的层层嵌套,提升了可读性
    async/await es8/ECMA17引入,基于promise之上的一个语法糖,让异步操作更加简洁

闭包

  • 如何产生闭包
    当一个嵌套的内部子函数引用了嵌套的外部父函数的变量(函数)时,就产生了闭包
  • 闭包到底是什么
    包含被引用变量(函数)的对象(闭包存在于嵌套的内部函数中)
  • 产生闭包的条件 函数嵌套+内部函数引用了外部函数的数据(变量/函数)+执行内部函数定义(可以不调用内部函数)
    1
    2
    3
    4
    5
    6
    7
    function fn1(){
    var a=2//调用fn1执行到此处时已经产生了闭包(函数提升) 对应此处的执行上下文如下图
    function fn2(){
    console.log(a)
    }//如果采用var fn2 = function()的方式定义函数,则只有在执行到这里时才会产生闭包,var a=2那里函数对象还没创建呢,是undefined,也就不存在闭包了
    }
    fn1()
Read more »