一、event loop 事件循環:
浏覽器 eventloop
- eventloop事件循環是一種執行模型一種運作機制,在不同的地方有不同的實作,主要分為浏覽器的event loop和nodejs的event loop;在事件循環中有兩個重要的概念,宏隊列和微隊列
- 首先,對于浏覽器的event loop來說,是html5定義的規範,但是是在浏覽器實作的,在浏覽器中:宏隊列主要包括settimeout和setinterval,微隊列主要有promise。主要執行過程是:
- 浏覽器首先會将同步任務執行完畢,這時調用棧會被清空
- 之後會從微任務隊列中取出位于隊首的回調任務,遵從先進先出的原則依次放入調用棧中執行,直到棧空,如果此時回調函數中又生成了微任務,将其放在隊尾等待調用
- 當微任務隊列為空的時候,這時将調用宏隊列,将隊首任務放入調用棧執行;(一次隻能執行一個宏隊列)如果宏任務中産生了微任務,就去先調用微任務,再去調用下一個宏任務
- 然後重複步驟,這就是浏覽器的eventloop
nodejs eventloop
nodejs的eventloop是基于libuv實作的,在事件循環執行宏隊列時,nodejs的回調任務有6個階段,timer(settimeout和setinterval)、I/O callback階段、idle,prepare階段、poll階段、check階段、close 階段。這6個階段構成了4個宏隊列分别是:Timers Queue、IO Callback Queue、Check Queue、close callback Queue;
-nodejs 事件循環和浏覽器事件循環最主要的差別就是:浏覽器可以看做一個宏隊列一個微隊列;而nodejs是4個宏隊列和2個隊列,是以就會有隊列的執行先後問題,在微隊列中首先會執行NextTick Queue(process.nexttick) 在執行傳統的微隊列比如promise等,在執行宏隊列任務時,需要将每一類宏隊列的任務全部執行完畢,才執行對應産生的微隊列。
二、浏覽器緩存:強緩存和協商緩存
HTTP封包就是浏覽器和伺服器間通信時發送及響應的資料塊。
浏覽器向伺服器請求資料,發送請求(request)封包;伺服器向浏覽器傳回資料,傳回響應(response)封包。
封包資訊主要分為兩部分
1.包含屬性的首部(header)————————–附加資訊(cookie,緩存資訊等)與緩存相關的規則資訊,均包含在header中
2.包含資料的主體部分(body)———————–HTTP請求真正想要傳輸的部分
強緩存
當我在沒有緩存,第一次請求伺服器的時候,伺服器會将資料和緩存規則一并傳回,緩存規則存放在響應頭中, 主要是Expires/Cache-Control來表明緩存失效規則,因為在expires中緩存到期時間是伺服器的時間,而用戶端和伺服器的時間可能存在差異,是以先在基本上都使用的cache-control,強緩存主要設定max-age屬性,即到期時間,在這個期間用戶端通路資料均走緩存
協商緩存
在第一次請求伺服器時,伺服器會傳回資源,并且傳回一個資源的緩存辨別,一起存到浏覽器的緩存資料庫。
當第二次請求資源時,浏覽器會首先将緩存辨別發送給伺服器,伺服器拿到辨別後判斷辨別是否比對,
如果不比對,表示資源有更新,伺服器會将新資料和新的緩存辨別一起傳回到浏覽器;
如果緩存辨別比對,表示資源沒有更新,并且傳回 304 狀态碼,浏覽器就讀取本地緩存伺服器中的資料。
在學号是協商緩存中主要有:
last-Modified/If-Modified-Since :伺服器傳回的資源最後修改時間
etag/if-none-match:資源在伺服器的唯一辨別
三、節流和防抖
防抖:對于短時間内,連續出發的事件,防抖的含義是讓某個時間限内,事件處理函數隻執行最後一次或最開始的第一次。
//實作防抖函數
function debounce(fn, timer) {
let time = null;
return function () {
if (time) {
clearTimeout(time)
}
time = setTimeout(fn, timer)
}
}
節流:如果短時間内大量觸發同一事件,那麼在函數執行一次之後,該函數在指定的時間期限内不再工作,直至過了這段時間才重新生效。
//實線節流函數
function throttle(fn, timer) {
let flag = true
return function () {
if (!flag) {
return false
} //在一段時間内flag始終為false
flag = false
setTimeout(() => {
fn();
flag = true;
}, timer)
}
}
三、web worker
Web Worker 的作用,就是為 JavaScript 創造多線程環境,允許主線程建立 Worker 線程,将一些任務配置設定給後者運作。在主線程運作的同時,Worker 線程在背景運作,兩者互不幹擾。等到 Worker 線程完成計算任務,再把結果傳回給主線程。這樣的好處是,一些計算密集型或高延遲的任務,被 Worker 線程負擔了,主線程(通常負責 UI 互動)就會很流暢,不會被阻塞或拖慢。
Web Worker 有以下幾個使用注意點。
(1)同源限制
配置設定給 Worker 線程運作的腳本檔案,必須與主線程的腳本檔案同源。
(2)DOM 限制
Worker 線程所在的全局對象,與主線程不一樣,無法讀取主線程所在網頁的 DOM 對象,也無法使用document、window、parent這些對象。但是,Worker 線程可以navigator對象和location對象。
(3)通信聯系
Worker 線程和主線程不在同一個上下文環境,它們不能直接通信,必須通過消息完成。
(4)腳本限制
Worker 線程不能執行alert()方法和confirm()方法,但可以使用 XMLHttpRequest 對象發出 AJAX 請求。
(5)檔案限制
Worker 線程無法讀取本地檔案,即不能打開本機的檔案系統(file://),它所加載的腳本,必須來自網絡。
四、原型鍊
prototype 在JavaScript中,每個函數都有一個prototype屬性,這個屬性指向函數的原型對象。
proto 這是每個對象(除null外)都會有的屬性,叫做__proto__,這個屬性會指向該對象的原型。
- 當讀取執行個體的屬性時,如果找不到,就會查找與對象關聯的原型中的屬性,如果還查不到,就去找原型的原型,一直找到最頂層為止
- 每個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而執行個體都包含一個指向原型對象的内部指針。
五、new一個構造函數的過程
- 建立一個新對象,将它的引用指派給this,繼承函數的原型
- 通過this将構造函數的屬性添加給這個對象
- 最後傳回這個this指向的新對象,也就是執行個體
let newMethods = function (Parent, ...rest) {
let child = Object.create(Parent.prototype);
let ruselt = Parent.apply(child, rest)
return typeof result === 'object' ? result : child;
}
const child = newMethods(ssss, "zdd");
六、promise原理
- 首先promise解決的異步問題,同時他的應用場景主要是解決回到地獄的問題,promise 可以實作在多個請求發送完成後,再得到或者處理某個結果,
- promise的原理:promise主要三個狀态 pending、Fulfilled、rejected,當promise構造函數需要傳入一個函數,函數中有兩個參數分别是resolve和reject,在promise中有一個then,他的主要功能是當promise對象狀态發生改變時執行相應操作,當然promise是基于釋出訂閱者模式實作的
function myPromise(constructor) {
let self = this;
self.status = "pending";
self.value = undefined;
self.reason = undefined;
//定義觀察數組
self.onFullfilledArray = []
self.onRejectedArray = []
function resolve(value) {
if (self.status == "pending") {
self.value = value;
self.status = "resolved"
self.onFullfilledArray.forEach(fn => {
fn(self.value)
});
}
}
function reject(reason) {
if (self.status == "pending") {
self.reason = reason;
self.status = "rejected"
self.onRejectedArray.forEach(fn => {
fn(self.reason)
})
}
}
try {
constructor(resolve, reject);
} catch (e) {
reject(e);
}
}
myPromise.prototype.then = function (onFullfilled, onRejected) {
let self = this;
switch (self.status) {
case "pending":
self.onFullfilledArray.push(function () {
onFullfilled(self.value)
})
self.onRejectedArray.push(function () {
onRejected(self.reason)
})
break;
case "resolved":
onFullfilled(self.value);
break;
case "rejected":
onRejected(self.reason);
break;
default:
}
}
new myPromise((resolve, reject) => {
console.log(123);
// resolve(222)
setTimeout(function () {
resolve(222)
}, 2000)
}).then(data => {
console.log(data);
})
七、Content-type
服務端通常是根據請求頭(headers)中的 Content-Type 字段來獲知請求中的消息主體是用何種方式編碼,再對主體進行解析。
application/x-www-form-urlencoded
- 這應該是最常見的 POST 送出資料的方式了。浏覽器的原生 表單,如果不設定 enctype 屬性,那麼最終就會以 application/x-www-form-urlencoded 方式送出資料。送出的資料按照 key1=val1&key2=val2 的方式進行編碼,key 和 val 都進行了 URL 轉碼。
multipart/form-data
- 這又是一個常見的 POST 資料送出的方式。我們使用表單上傳檔案時,必須讓 表單的enctype 等于 multipart/form-data。
application/json
- 通過序列化json字元串的方式進行編碼,可以友善的送出複雜的結構化資料,特别适合 RESTful 的接口。
text/xml
- 忽略xml頭所指定bai編碼du格式而預設采用zhius-ascii編碼
八、mouseover和mouseleave的差別
- mouseover:隻要滑鼠指針移入事件綁定的元素及其子元素,都會觸發mouseover事件
- mouseleave:隻有滑鼠指針移入事件綁定的元素時,才會觸發mouseleave事件