- 觀察者模式 基于 發(fā)布訂閱模式
- promise 用于解決異步方案 promise函數(shù)中的executor函數(shù)會立即執(zhí)行
- promise三大狀態(tài):
- pending 等待狀態(tài)
- resolved(fulfilled) 成功狀態(tài)
- rejected 失敗狀態(tài)
- 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 區(qū)別:
- 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()屬性 不支持數(shù)組更新(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 } //不能操作原數(shù)組 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;
//靜態(tài)屬性(自己擁有)
static name = 'sss';
//原型上
say(){}
}
function flag(_class){}
function readonly(target,property,descriptor){}
-
node事件環(huán)
- 棧 先進后出
- 隊列 先進先出
-
node
- 解決跨域問題
- 高并發(fā)高性能服務器
- 適合I/O密集型(fs)
- 不適合cpu密集型(加密 運算)
-
node 事件環(huán)
- timers階段
setTimeout
- poll(輪詢) 階段
I/O
- check階段
setImmediate
- timers階段
path 模塊
path.extname //獲取文件擴展名
path.basename //文件名(無后綴)
path.join() //路徑拼接
path.resolve() //把文件路徑轉換成絕對路徑
path.dirname() // 獲取父級目錄
__dirname //目錄名 文件名
__filename //文件名
- 字符串執(zhí)行方法
1.eval()
2. new Function(argument,str)
3. vm (沙箱 node核心模塊)
- npm link 把包鏈接到全局上
- 文件運行方式
#!/usr/bin/env node
- chmod -R 777 路徑
修改目錄權限
pack.json文件中:
bin :{
"命令名":"運行文件"
}
process.cwd() //當前執(zhí)行文件路徑
-
宏任務/微任務
- 微任務:
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)
文件狀態(tài) statSync(dir)
讀取目錄readdirSync(dir)
判斷是文件夾還是文件 isDirectory()
let rs = fs.createReadStream(path,{
flags:'r',//r, r+, w, w+, a,
highWaterMark:1,//字節(jié)數(shù)
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 源碼:
/**
* 第一次 向文件中寫入
* 第二次 把內容存放到緩存中
* 第三次 第一次寫入成功后锉走,清空緩存第一項 依次清空
* 第四次 都清空后看是否觸發(fā)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()// 清理數(shù)組第一項
})
}
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 狀態(tài)碼:
- 1xx(臨時響應)
表示臨時響應并需要請求者繼續(xù)執(zhí)行操作的狀態(tài)代碼涣易。
- 100 (繼續(xù)) 請求者應當繼續(xù)提出請求。
- 101 (切換協(xié)議) 請求者已要求服務器切換協(xié)議般眉,服務器已確認并準備切換。
- 1xx(臨時響應)
- 2xx (成功)
表示成功處理了請求的狀態(tài)代碼。
- 200 (成功) 服務器已成功處理了請求。
- 201 (已創(chuàng)建) 請求成功并且服務器創(chuàng)建了新的資源匆瓜。
- 202 (已接受) 服務器已接受請求,但尚未處理未蝌。
- 203 (非授權信息) 服務器已成功處理了請求驮吱,但返回的信息可能來自另一來源。
- 204 (無內容) 服務器成功處理了請求萧吠,但沒有返回任何內容左冬。
- 205 (重置內容) 服務器成功處理了請求,但沒有返回任何內容纸型。
- 206 (部分內容 斷點續(xù)傳(range:bytes=0-5)) 服務器成功處理了部分 GET 請求拇砰。
3xx (重定向)
表示要完成請求梅忌,需要進一步操作。
+ 300 (多種選擇) 針對請求除破,服務器可執(zhí)行多種操作牧氮。
+ 301 (永久移動) 請求的網(wǎng)頁已永久移動到新位置。
+ 302 (臨時移動) 服務器目前從不同位置的網(wǎng)頁響應請求瑰枫,但請求者應繼續(xù)使用原有位置來進行以后的請求踱葛。
+ 303 (查看其他位置) 請求者應當對不同的位置使用單獨的 GET 請求來檢索響應時,服務器返回此代碼光坝。
+ 304 (未修改) 自從上次請求后尸诽,請求的網(wǎng)頁未修改過。 服務器返回此響應時教馆,不會返回網(wǎng)頁內容逊谋。
+ 305 (使用代理) 請求者只能使用代理訪問請求的網(wǎng)頁。 如果服務器返回此響應土铺,還表示請求者應使用代理胶滋。
+ 307 (臨時重定向) 服務器目前從不同位置的網(wǎng)頁響應請求,但請求者應繼續(xù)使用原有位置來進行以后的請求悲敷。4xx(請求錯誤)
這些狀態(tài)代碼表示請求可能出錯究恤,妨礙了服務器的處理。
+ 400 (錯誤請求) 服務器不理解請求的語法后德。
+ 401 (未授權) 請求要求身份驗證部宿。
+ 403 (禁止) 服務器拒絕請求。
+ 404 (未找到) 服務器找不到請求的網(wǎng)頁瓢湃。
+ 405 (方法禁用) 禁用請求中指定的方法理张。
+ 406 (不接受) 無法使用請求的內容特性響應請求的網(wǎng)頁。
+ 407 (需要代理授權) 此狀態(tài)代碼與 401(未授權)類似绵患,但指定請求者應當授權使用代理雾叭。
+ 408 (請求超時) 服務器等候請求時發(fā)生超時。
+ 409 (沖突) 服務器在完成請求時發(fā)生沖突落蝙。 服務器必須在響應中包含有關沖突的信息织狐。
+ 410 (已刪除) 如果請求的資源已永久刪除,服務器就會返回此響應筏勒。
+ 411 (需要有效長度) 服務器不接受不含有效內容長度標頭字段的請求移迫。
+ 412 (未滿足前提條件) 服務器未滿足請求者在請求中設置的其中一個前提條件。
+ 413 (請求實體過大) 服務器無法處理請求管行,因為請求實體過大厨埋,超出服務器的處理能力。
+ 414 (請求的 URI 過長) 請求的 URI(通常為網(wǎng)址)過長捐顷,服務器無法處理揽咕。
+ 415 (不支持的媒體類型) 請求的格式不受請求頁面的支持悲酷。
+ 416 (請求范圍不符合要求) 如果頁面無法提供請求的范圍,則服務器會返回此狀態(tài)代碼亲善。
+ 417 (未滿足期望值) 服務器未滿足”期望”請求標頭字段的要求设易。5xx(服務器錯誤)
這些狀態(tài)代碼表示服務器在嘗試處理請求時發(fā)生內部錯誤。
+ 500 (服務器內部錯誤) 服務器遇到錯誤蛹头,無法完成請求顿肺。
+ 501 (尚未實施) 服務器不具備完成請求的功能。
+ 502 (錯誤網(wǎng)關) 服務器作為網(wǎng)關或代理渣蜗,從上游服務器收到無效響應屠尊。
+ 503 (服務不可用) 服務器目前無法使用(由于超載或停機維護)。 通常耕拷,這只是暫時狀態(tài)讼昆。
+ 504 (網(wǎng)關超時) 服務器作為網(wǎng)關或代理,但是沒有及時從上游服務器收到請求骚烧。
+ 505 (HTTP 版本不受支持) 服務器不支持請求中所用的 HTTP 協(xié)議版本浸赫。-
http頭:
- 設置語言
Accept - language:zh-CN, jp;q=0.8
- 斷點續(xù)傳
Content-Rang:bytes 0-5/total
- 防盜鏈(referer)
let refererHost = url.parse(req.headers['referer']).host; let host = req.headers['host'] if(refererHost != host){ 不是同一網(wǎng)站 }
- 壓縮
zlib核心包 fs.createReadStream(path).pipe(zilb.createGzip()).pipe(res)
- 設置語言
高階函數(shù) (callback)解決異步問題 并發(fā) 基于回調(回調地獄 錯誤處理很復雜)
promise原理(必會 手寫源碼)
defer 實現(xiàn)defer的延遲對象(必會)
-
promise的優(yōu)缺點:
- 解決回調地獄 鏈式調用
co + generator (saga) yield *
async + await
-
es6
- 箭頭函數(shù)(沒有this argument prototype) 原型鏈 各種繼承
- 解構 模板字符串 剩余運算符
- 遞歸拷貝 + 解決循環(huán)應用 weakmap
- Set,Map(去重 交差補) Symbol instanceof
- Object.defineProperty -> proxy(解決數(shù)組問題 觸發(fā)兩次)+reflect 遞歸
- class
-
eventloop事件環(huán)
- 宏任務: settimeout messageCheenl setimmidate UI線程
- 微任務:promise.then mutationobserver nexttick