- 观察者模式 基于 发布订阅模式
- promise 用于解决异步方案 promise函数中的executor函数会立即执行
- promise三大状态:
- pending 等待状态
- resolved(fulfilled) 成功状态
- rejected 失败状态
- generator async+awite 支持try{}catch(e){}
- co库源码
function co(it){
return new promise(()=>{
function next(val){
let {value,done} = it.next(val);
if(done){
return resolve(value)
}
Promise.resolve(value).then(data=>{
next(data)
})
}
})
}
- var let const 区别:
- var 变量提升 全局
- let 解决重复定义 拥有自己的作用域
- const 常亮 不会变的量(地址不变即可)
- 展开运算符(...)
let a = [1,2,3];
let b =[4,5,6];
let c = [...a,...b]
- 深拷贝
function deepCopy(options,hash=new WeakMap()){
if(options == null) return options;
if(options instanceof Date) return new Date(options);
if(options instanceof RegExp) return new Date(options);
if(typeof options !== 'object') return options;
//如果 weakmap中有对象 就直接返回
if(hash.has(options))return hash.get(options);
let cloneOptions = new options.constructor;
hash.set(obj,cloneOptions );
for(let key in options){
if (obj.hasOwnProperty(key)) {
//如果赋值的对象 就把这个对象放到weakmap中
cloneOptions[key] = deepCopy(obj[key],hash)
}
}
return cloneOptions
}
-
object.defineProperty()属性 不支持数组更新(push sclice...)
- enumerable : true/false 是否可枚举
- configurable : true/false 是否可删除
- writable : true/false 是否可重新
- get(){} //不能和writable 同时存在
- set(){} //不能和writable 同时存在
-
object.proxy()
let proxy = new Proxy(arr,{ set(target,key,value){ if( key === 'length'){ return true } //不能操作原数组 return Reflect.set(target,key,value) // target[key] = value }, get(target,key){ return Reflect.get(target,key) //return target[key] } })
reduce原理
Array.prototype.my_reduce = function(cb, prev) {
for (let i = 0; i < this.length; i++) {
if (typeof prev !== 'undefined') {
prev = cb(prev, this[i], this)
} else {
prev = cb(this[i], this[++i], this);
i++;
}
}
return prev
};
some() 找到对应值就返回true
every() 找到对应值就返回false
-
原型
- 每个实例上的proto 都指向所属类的原型(prototype)
object.create()原理
function create(parentPrototype){
let Fn = function(){}
Fn.prototype = parentPrototype;
let fn = new Fn();
return fn
}
- 装饰器
- 需安装
- @babel/plugin-proposal-decorators
- @babel/plugin-proposal-class-properties
*注 插件有顺序
@flag
class Animal{
//实例属性
@readonly
PI = 3.14;
//静态属性(自己拥有)
static name = 'sss';
//原型上
say(){}
}
function flag(_class){}
function readonly(target,property,descriptor){}
-
node事件环
- 栈 先进后出
- 队列 先进先出
-
node
- 解决跨域问题
- 高并发高性能服务器
- 适合I/O密集型(fs)
- 不适合cpu密集型(加密 运算)
-
node 事件环
- timers阶段
setTimeout
- poll(轮询) 阶段
I/O
- check阶段
setImmediate
- timers阶段
path 模块
path.extname //获取文件扩展名
path.basename //文件名(无后缀)
path.join() //路径拼接
path.resolve() //把文件路径转换成绝对路径
path.dirname() // 获取父级目录
__dirname //目录名 文件名
__filename //文件名
- 字符串执行方法
1.eval()
2. new Function(argument,str)
3. vm (沙箱 node核心模块)
- npm link 把包链接到全局上
- 文件运行方式
#!/usr/bin/env node
- chmod -R 777 路径
修改目录权限
pack.json文件中:
bin :{
"命令名":"运行文件"
}
process.cwd() //当前执行文件路径
-
宏任务/微任务
- 微任务:
process.nextTick promise MutationObserver
- 微任务:
script setTimeout setInterval MessgeChannel I/O UI rendering
- 微任务:
node 包
utils EventEmitter buffer
fs
access() 判断是否有权限访问该路径(是否存在)
function next(index){
fs.access(path,(err)=>{
if(err){
fs.mkdir(currentpath,()=>next(index+1))
}else{
next(index)
}
})
}
删除目录 rmdirSync(dir)
删除文件 unlinkSync(dir)
文件状态 statSync(dir)
读取目录readdirSync(dir)
判断是文件夹还是文件 isDirectory()
let rs = fs.createReadStream(path,{
flags:'r',//r, r+, w, w+, a,
highWaterMark:1,//字节数
mode:0o666, //可读可写
start:0,//开始位置
end:3,//结束位置
//encoding:'utf8'
autoClose:true
})
rs.on("open", ()=>{}) //打开文件
rs.on("close",()=>{}) //关闭文件
rs.on("error",()=>{}) //读取文件出错
rs.on("data", (chunk)=>{}) //读取文件
rs.on("end", ()=>{}) //读取完毕
rs.resume() //恢复
res.pause() //暂停
- readStream 源码:
let fs = require('fs');
let EventEmitter = require('events')
class ReadStream extends EventEmitter {
constructor(path, options = {}) {
super();
this.path = path;
this.flags = options.flags || 'r';
this.mode = options.mode || 438;
this.start = options.start || 0;
this.end = open.end;
this.autoClose = options.autoClose;
this.highWaterMark = options.highWaterMark || 64 * 1024;
this.encoding = options.encoding || null;
this.flowing = null; //开始读取 修改成true
// 读取文件 需打开文件
this.open();
// 同步
this.on("newListener", (type) => {
if (type === 'data') {
this.flowing = true;
this.read() //开始读取文件
}
})
this.pos = this.start;
}
read() {
if (typeof this.fd !== 'number') {
return this.once('open', () => this.read())
}
let howMuchToRead = this.end ? Math.min((this.end - this.pos + 1), this.highWaterMark) : this.highWaterMark;
let buffer = Buffer.alloc(howMuchToRead);
fs.read(this.fd, buffer, 0, buffer.length, this.pos, (err, bytesRead) => {
if (bytesRead > 0) {
this.pos += bytesRead;
this.emit("data", this.encoding ? buffer.toString(this.encoding) : buffer);
if (this.flowing) {
this.read()
} else {
this.emit('end');
if (this.autoClose) {
fs.close(this.fd, () => {
this.emit("close");
this.flowing = null;
})
}
}
}
})
}
//异步
open() {
fs.open(this.path, this.flags, (err, fd) => {
if (err) {
this.emit('error');
return
}
this.fd = fd; //文件描述符
this.emit('open', this.fd)
})
}
}
module.exports = ReadStream;
- writeStream 源码:
/**
* 第一次 向文件中写入
* 第二次 把内容存放到缓存中
* 第三次 第一次写入成功后,清空缓存第一项 依次清空
* 第四次 都清空后看是否触发drain事件
*/
let fs = require('fs');
let EventEmitter = require('events')
class WriteStream extends EventEmitter{
constructor(path,options){
super();
this.path= path;
this.mode = options.mode||0o666;
this.autoClose = options.autoClose|| true;
this.highWaterMark = options.highWaterMark || 64 * 1024;
this.encoding = options.encoding || 'utf8';
this.start = options.start || 0;
this.flags = options.flags || 'w';
this.open();
this.cache=[];//暂存
this.len;
this.needDrain = false;
this.writing = false;
this.pos =this.start;
}
open(){
fs.open(this.path,this.flags,(err,data)=>{
if(err){
return this.emit("error")
}
this.fd = fd;
this.emit("open")
})
}
write(chunk,encoding=this.encoding,callback=()=>{}){
chunk =Buffer.isBuffer(chunk)?chunk:Buffer.from(chunk);
this.len += chunk.length;
if(this.len >= this.highWaterMark){
this.needDrain = true;
}
if(this.writing){
this.cache.push({chunk,encoding,callback})
}else{
this.writing = true;
this._write(chunk,encoding,()=>{
callback();
this.clearBuffer()// 清理数组第一项
})
}
return !this.needDrain;
}
clearBuffer(){
let obj = this.cache.shift();
if(obj){
this._write(obj.chunk,obj.encoding,()=>{
obj.callback();
this.clearBuffer();
})
}else{
if(this.needDrain){
this.needDrain =false;
this.writing = false;
this.emit("drain")
}
}
}
_write(chunk,encoding,callback){
if(typeof this.fd != 'number'){
return this.once("open",()=>{
return this._write(chunk,encoding,callback)
})
}
fs.write(this.fd,chunk,0,chunk.length,this.pos,(err,written)=>{
this.pos = written;
this.len -= written
callback()
})
}
}
module.exports = WriteStream
- process.stdout.write()
可写流
- process.stdin.on("data",(chunk)=>{})
可读流
- process.stdin.pipe()
- HTTP 状态码:
- 1xx(临时响应)
表示临时响应并需要请求者继续执行操作的状态代码。
- 100 (继续) 请求者应当继续提出请求。
- 101 (切换协议) 请求者已要求服务器切换协议,服务器已确认并准备切换。
- 1xx(临时响应)
- 2xx (成功)
表示成功处理了请求的状态代码。
- 200 (成功) 服务器已成功处理了请求。
- 201 (已创建) 请求成功并且服务器创建了新的资源。
- 202 (已接受) 服务器已接受请求,但尚未处理。
- 203 (非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源。
- 204 (无内容) 服务器成功处理了请求,但没有返回任何内容。
- 205 (重置内容) 服务器成功处理了请求,但没有返回任何内容。
- 206 (部分内容 断点续传(range:bytes=0-5)) 服务器成功处理了部分 GET 请求。
3xx (重定向)
表示要完成请求,需要进一步操作。
+ 300 (多种选择) 针对请求,服务器可执行多种操作。
+ 301 (永久移动) 请求的网页已永久移动到新位置。
+ 302 (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
+ 303 (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。
+ 304 (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。
+ 305 (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。
+ 307 (临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。4xx(请求错误)
这些状态代码表示请求可能出错,妨碍了服务器的处理。
+ 400 (错误请求) 服务器不理解请求的语法。
+ 401 (未授权) 请求要求身份验证。
+ 403 (禁止) 服务器拒绝请求。
+ 404 (未找到) 服务器找不到请求的网页。
+ 405 (方法禁用) 禁用请求中指定的方法。
+ 406 (不接受) 无法使用请求的内容特性响应请求的网页。
+ 407 (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。
+ 408 (请求超时) 服务器等候请求时发生超时。
+ 409 (冲突) 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。
+ 410 (已删除) 如果请求的资源已永久删除,服务器就会返回此响应。
+ 411 (需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。
+ 412 (未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。
+ 413 (请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。
+ 414 (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。
+ 415 (不支持的媒体类型) 请求的格式不受请求页面的支持。
+ 416 (请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码。
+ 417 (未满足期望值) 服务器未满足”期望”请求标头字段的要求。5xx(服务器错误)
这些状态代码表示服务器在尝试处理请求时发生内部错误。
+ 500 (服务器内部错误) 服务器遇到错误,无法完成请求。
+ 501 (尚未实施) 服务器不具备完成请求的功能。
+ 502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
+ 503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
+ 504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。
+ 505 (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。-
http头:
- 设置语言
Accept - language:zh-CN, jp;q=0.8
- 断点续传
Content-Rang:bytes 0-5/total
- 防盗链(referer)
let refererHost = url.parse(req.headers['referer']).host; let host = req.headers['host'] if(refererHost != host){ 不是同一网站 }
- 压缩
zlib核心包 fs.createReadStream(path).pipe(zilb.createGzip()).pipe(res)
- 设置语言
高阶函数 (callback)解决异步问题 并发 基于回调(回调地狱 错误处理很复杂)
promise原理(必会 手写源码)
defer 实现defer的延迟对象(必会)
-
promise的优缺点:
- 解决回调地狱 链式调用
co + generator (saga) yield *
async + await
-
es6
- 箭头函数(没有this argument prototype) 原型链 各种继承
- 解构 模板字符串 剩余运算符
- 递归拷贝 + 解决循环应用 weakmap
- Set,Map(去重 交差补) Symbol instanceof
- Object.defineProperty -> proxy(解决数组问题 触发两次)+reflect 递归
- class
-
eventloop事件环
- 宏任务: settimeout messageCheenl setimmidate UI线程
- 微任务:promise.then mutationobserver nexttick