JS是單線程的,為了防止一個函數執行時間過長阻塞后面的代碼,所以會先將同步代碼壓入執行棧中,依次執行,將異步代碼推入異步隊列,異步隊列又分為宏任務隊列和微任務隊列,因為宏任務隊列的執行時間較長,所以微任務隊列要優先于宏任務隊列。微任務隊列的代表就是,Promise.then,MutationObserver,宏任務的話就是setImmediate setTimeout setInterval
ajax是一種異步通信的方法,從服務端獲取數據,達到局部刷新頁面的效果。 過程:
1. 創建XMLHttpRequest對象;
【資料圖】
2. 調用open方法傳入三個參數 請求方式(GET/POST)、url、同步異步(true/false);
3. 監聽onreadystatechange事件,當readystate等于4時返回responseText;
4. 調用send方法傳遞參數。
event.stopPropagation() 或者 ie下的方法 event.cancelBubble = true; //阻止事件冒泡
MVVM是Model-View-ViewModel縮寫,也就是把MVC中的Controller演變成ViewModel。Model層代表數據模型,View代表UI組件,ViewModel是View和Model層的橋梁,數據會綁定到viewModel層并自動將數據渲染到頁面中,視圖變化的時候會通知viewModel層更新數據。
每個Vue實例在創建時都會經過一系列的初始化過程,vue的生命周期鉤子,就是說在達到某一階段或條件時去觸發的函數,目的就是為了完成一些動作或者事件
create階段:vue實例被創建 beforeCreate: 創建前,此時data和methods中的數據都還沒有初始化 created: 創建完畢,data中有值,未掛載mount階段: vue實例被掛載到真實DOM節點 beforeMount:可以發起服務端請求,去數據 mounted: 此時可以操作Domupdate階段:當vue實例里面的data數據變化時,觸發組件的重新渲染 beforeUpdate updateddestroy階段:vue實例被銷毀 beforeDestroy:實例被銷毀前,此時可以手動銷毀一些方法 destroyed因為對象是一個引用數據類型,如果data是一個對象的情況下會造成所有組件共用一個data。而當data是一個函數的情況下,每次函數執行完畢后都會返回一個新的對象,這樣的話每個組件都會維護一份獨立的對象(data)
watch 屬性監聽是一個對象,鍵是需要觀察的屬性,值是對應回調函數,主要用來監聽某些特定數據的變化,從而進行某些具體的業務邏輯操作,監聽屬性的變化,需要在數據變化時執行異步或開銷較大的操作時使用
computed 計算屬性屬性的結果會被緩存,當computed中的函數所依賴的屬性沒有發生改變的時候,那么調用當前函數的時候結果會從緩存中讀取。除非依賴的響應式屬性變化時才會重新計算,主要當做屬性來使用computed中的函數必須用return返回最終的結果 computed更高效,優先使用
使用場景computed:當一個屬性受多個屬性影響的時候使用,例:購物車商品結算功能 watch:當一條數據影響多條數據的時候使用,例:搜索數據
1. key的作用主要是為了更高效的對比虛擬DOM中每個節點是否是相同節點;
2. Vue在patch過程中判斷兩個節點是否是相同節點,key是一個必要條件,渲染一組列表時,key往往是唯一標識,所以如果不定義key的話,Vue只能認為比較的兩個節點是同一個,哪怕它們實際上不是,這導致了頻繁更新元素,使得整個patch過程比較低效,影響性能;
3. 從源碼中可以知道,Vue判斷兩個節點是否相同時主要判斷兩者的key和元素類型等,因此如果不設置key,它的值就是undefined,則可能永 遠認為這是兩個相同的節點,只能去做更新操作,這造成了大量的dom更新操作,明顯是不可取的。
父子組件通信
父->子props,子->父 $on、$emit` 獲取父子組件實例 parent、parent、children Ref 獲取實例的方式調用組件的屬性或者方法 Provide、inject` 官方不推薦使用,但是寫組件庫時很常用
兄弟組件通信
Event Bus 實現跨組件通信 Vue.prototype.$bus = new Vue() Vuex
跨級組件通信
$attrs、$listeners Provide、inject
1. 使用router-link進行路由導航,傳遞參數
2. 直接調用$router.push 實現攜帶參數的跳轉
3. 通過路由屬性中的name來確定匹配的路由,通過params來傳遞參數
4. 使用path來匹配路由,然后通過query來傳遞參數,這種情況下 query傳遞的參數會顯示在url
對于Vue 這類漸進式前端開發框架,為了構建SPA(單頁面應用),需要引入前端路由系統,這也就是Vue-router存在的意義。前端路由的核心,就在于改變視圖的同時不會向后端發出請求。 1、hash ——即地址欄URL中的#符號,它的特點在于:hash 雖然出現URL中,但不會被包含在HTTP請求中,對后端完全沒有影響,因此改變hash不會重新加載頁面。
2、history ——利用了HTML5 History Interface 中新增的pushState() 和replaceState() 方法。這兩個方法應用于瀏覽器的歷史記錄站,在當前已有的back、forward、go 的基礎之上,它們提供了對歷史記錄進行修改的功能。只是當它們執行修改是,雖然改變了當前的URL,但你瀏覽器不會立即向后端發送請求。history模式,會出現404 的情況,需要后臺配置。
當一個Vue實例創建時,Vue會遍歷data選項的屬性,用 Object.defineProperty將它們轉為 getter/setter并且在內部追蹤相關依賴,在屬性被訪問和修改時通知變化。每個組件實例都有相應的 watcher 程序實例,它會在組件渲染的過程中把屬性記錄為依賴,之后當依賴項的 setter 被調用時,會通知 watcher重新計算,從而致使它關聯的組件得以更新。
1. vue中雙向綁定是一個指令v-model,可以綁定一個動態值到視圖,同時視圖中變化能改變該值。v-model是語法糖,默認情況下相于:value和@input。
2. 使用v-model可以減少大量繁瑣的事件處理代碼,提高開發效率,代碼可讀性也更好
3. 通常在表單項上使用v-model
4. 原生的表單項可以直接使用v-model,自定義組件上如果要使用它需要在組件內綁定value并處理輸入事件
5. 我做過測試,輸出包含v-model模板的組件渲染函數,發現它會被轉換為value屬性的綁定以及一個事件監聽,事件回調函數中會做相應變量更新操作,這說明神奇魔法實際上是vue的編譯器完成的。
思考:為什么先注入再提供呢??
1、首先來自祖輩的數據要和當前實例的data,等判重,相結合,所以注入數據的initInjections一定要在InitState的上面。
2. 從上面注入進來的東西在當前組件中轉了一下又提供給后代了,所以注入數據也一定要在上面。
作用:實現組件緩存
鉤子函數:
`activated `組件渲染后調用
`deactivated `組件銷毀后調用
原理:Vue.js內部將DOM節點抽象成了一個個的VNode節點,keep-alive組件的緩存也是基于VNode節點的而不是直接存儲DOM結構。它將滿足條件(pruneCache與pruneCache)的組件在cache對象中緩存起來,在需要重新渲染的時候再將vnode節點從cache對象中取出并渲染。
配置屬性:
include 字符串或正則表達式。只有名稱匹配的組件會被緩存
exclude 字符串或正則表達式。任何名稱匹配的組件都不會被緩存
max 數字、最多可以緩存多少組件實例
vuex是一個專門為vue.js應用程序開發的狀態管理庫。 核心概念:
state(單一狀態樹) getter/Mutation顯示提交更改stateAction類似Mutation,提交Mutation,可以包含任意異步操作。module(當應用變得龐大復雜,拆分store為具體的module模塊)在js中,渲染真實DOM的開銷是非常大的, 比如我們修改了某個數據,如果直接渲染到真實DOM, 會引起整個dom樹的重繪和重排。那么有沒有可能實現只更新我們修改的那一小塊dom而不要更新整個dom呢?此時我們就需要先根據真實dom生成虛擬dom, 當虛擬dom某個節點的數據改變后會生成有一個新的Vnode, 然后新的Vnode和舊的Vnode作比較,發現有不一樣的地方就直接修改在真實DOM上,然后使舊的Vnode的值為新的Vnode。
diff的過程就是調用patch函數,比較新舊節點,一邊比較一邊給真實的DOM打補丁。在采取diff算法比較新舊節點的時候,比較只會在同層級進行。 在patch方法中,首先進行樹級別的比較 new Vnode不存在就刪除 old Vnodeold Vnode 不存在就增加新的Vnode 都存在就執行diff更新 當確定需要執行diff算法時,比較兩個Vnode,包括三種類型操作:屬性更新,文本更新,子節點更新 新老節點均有子節點,則對子節點進行diff操作,調用updatechidren 如果老節點沒有子節點而新節點有子節點,先清空老節點的文本內容,然后為其新增子節點 如果新節點沒有子節點,而老節點有子節點的時候,則移除該節點的所有子節點 老新老節點都沒有子節點的時候,進行文本的替換
updateChildren 將Vnode的子節點Vch和oldVnode的子節點oldCh提取出來。 oldCh和vCh各有兩個頭尾的變量StartIdx和EndIdx,它們的2個變量相互比較,一共有4種比較方式。如果4種比較都沒匹配,如果設置了key,就會用key進行比較,在比較的過程中,變量會往中間靠,一旦StartIdx>EndIdx表明oldCh和vCh至少有一個已經遍歷完了,就會結束比較。
三個方面:
網絡篇:
1. 構建請求
2. 查找強緩存
3. DNS解析
4. 建立TCP連接(三次握手)
5. 發送HTTP請求(網絡請求后網絡響應)
瀏覽器解析篇:
1. 解析html構建DOM樹
2. 解析css構建CSS樹、樣式計算
3. 生成布局樹(Layout Tree)
瀏覽器渲染篇:
1. 建立圖層樹(Layer Tree)
2. 生成繪制列表
3. 生成圖塊并柵格化
4. 顯示器顯示內容
5. 最后斷開連接:TCP 四次揮手
1.`HTTP` 是不安全的,而 HTTPS 是安全的
2.`HTTP` 標準端口是80 ,而 HTTPS 的標準端口是443
3.`HTTP` 無法加密,而HTTPS 對傳輸的數據進行加密
4.`HTTP`無需證書,而HTTPS 需要CA的SSL證書
1.GET在瀏覽器回退不會再次請求,POST會再次提交請求
2.GET請求會被瀏覽器主動緩存,POST不會,要手動設置
3.GET請求參數會被完整保留在瀏覽器歷史記錄里,POST中的參數不會
4.GET請求在URL中傳送的參數是有長度限制的,而POST沒有限制
5.GET參數通過URL傳遞,POST放在Request body中
6.GET參數暴露在地址欄不安全,POST放在報文內部更安全
7.GET一般用于查詢信息,POST一般用于提交某種信息進行某些修改操作
8.GET產生一個TCP數據包;POST產生兩個TCP數據包
XSS(Cross-Site Scripting,跨站腳本攻擊)是一種代碼注入攻擊。攻擊者在目標網站上注入惡意代碼,當被攻擊者登陸網站時就會執行這些惡意代碼,這些腳本可以讀取 cookie,session tokens,或者其它敏感的網站信息,對用戶進行釣魚欺詐,甚至發起蠕蟲攻擊等。
CSRF(Cross-site request forgery)跨站請求偽造:攻擊者誘導受害者進入第三方網站,在第三方網站中,向被攻擊網站發送跨站請求。利用受害者在被攻擊網站已經獲取的注冊憑證,繞過后臺的用戶驗證,達到冒充用戶對被攻擊的網站執行某項操作的目的。
XSS避免方式:
1. url參數使用encodeURIComponent方法轉義
2. 盡量不是有InnerHtml插入HTML內容
3. 使用特殊符號、標簽轉義符。
CSRF避免方式:
1. 添加驗證碼
2. 使用token
服務端給用戶生成一個token,加密后傳遞給用戶
用戶在提交請求時,需要攜帶這個token
服務端驗證token是否正確
比如:
200響應成功
301永久重定向
302臨時重定向
304資源緩存
403服務器禁止訪問
404服務器資源未找到
500 502服務器內部錯誤
504 服務器繁忙
1xx Informational(信息狀態碼) 接受請求正在處理
2xx Success(成功狀態碼) 請求正常處理完畢
3xx Redirection(重定向狀態碼) 需要附加操作已完成請求
4xx Client Error(客戶端錯誤狀態碼) 服務器無法處理請求
5xx Server Error(服務器錯誤狀態碼) 服務器處理請求出錯復制代碼
1. 強緩存==>Expires(過期時間)/Cache-Control(no-cache)(優先級高) 協商緩存 ==>Last-Modified/Etag(優先級高)Etag適用于經常改變的小文件 Last-Modefied適用于不怎么經常改變的大文件
2. 強緩存策略和協商緩存策略在緩存命中時都會直接使用本地的緩存副本,區別只在于協商緩存會向服務器發送一次請求。它們緩存不命中時,都會向服務器發送請求來獲取資源。在實際的緩存機制中,強緩存策略和協商緩存策略是一起合作使用的。瀏覽器首先會根據請求的信息判斷,強緩存是否命中,如果命中則直接使用資源。如果不命中則根據頭信息向服務器發起請求,使用協商緩存,如果協商緩存命中的話,則服務器不返回資源,瀏覽器直接使用本地資源的副本,如果協商緩存不命中,則瀏覽器返回最新的資源給瀏覽器。
一個域下的js腳本未經允許的情況下,不能訪問另一個域下的內容。通常判斷跨域的依據是協議、域名、端口號是否相同,不同則跨域。同源策略是對js腳本的一種限制,并不是對瀏覽器的限制,像img,script腳本請求不會有跨域限制。
Ajax : 短連接
Websocket : 長連接,雙向的。
Form表單:最原始的
解決方案:
1. jsonp(利用script標簽沒有跨域限制的漏洞實現。缺點:只支持GET請求)
2. CORS(設置Access-Control-Allow-Origin:指定可訪問資源的域名)
3. postMessage(message, targetOrigin, [transfer])(HTML5新增API 用于多窗口消息、頁面內嵌iframe消息傳遞),通過onmessage監聽 傳遞過來的數據
4. Websocket是HTML5的一個持久化的協議,它實現了瀏覽器與服務器的全雙工通信,同時也是跨域的一種解決方案。
5. Node中間件代理
6. Nginx反向代理
7. 各種嵌套iframe的方式,不常用。
8. 日常工作中用的最對的跨域方案是CORS和Nginx反向代理
module.exports={
entry: {},
output: {},
plugins: [],
module: [rules:[{}]]
}
1.入口起點:使用 entry 配置手動地分離代碼。
2.防止重復:使用 CommonsChunkPlugin 去重和分離 chunk。
3.動態導入:通過模塊的內聯函數調用來分離代碼。
loader: 是一個導出為函數的javascript模塊,根據rule匹配文件擴展名,處理文件的轉換器。
file-loader:把文件輸出到一個文件夾中,在代碼中通過相對 URL 去引用輸出的文件 (處理圖片和字體)
url-loader: 與file-loader類似,區別是用戶可以設置一個閾值,大于閾值會交給file-loader處理,小于閾值時返回文件base64 形式編碼 (處理圖片和字體)
image-loader:加載并且壓縮圖片文件
babel-loader:把 ES6 轉換成 ES5
sass-loader:將SCSS/SASS代碼轉換成CSS
css-loader:加載 CSS,支持模塊化、壓縮、文件導入等特性
style-loader:把 CSS 代碼注入到 JavaScript 中,通過 DOM 操作去加載 CSS
postcss-loader:擴展 CSS 語法,使用下一代 CSS,可以配合 autoprefixer 插件自動補齊 CSS3 前綴 eslint-loader:通過 ESLint 檢查 JavaScript 代碼
plugin:本質是插件,基于事件流框架 Tapable,插件可以擴展 Webpack 的功能,在 Webpack 運行的生命周期中會廣播出許多事件,Plugin 可以監聽這些事件,在合適的時機通過 Webpack 提供的 API 改變輸出結果。
html-webpack-plugin:簡化 HTML 文件創建 (依賴于 html-loader)
uglifyjs-webpack-plugin:壓縮js文件
clean-webpack-plugin:目錄清除
mini-css-extract-plugin:分離樣式文件,CSS 提取為獨立文件,支持按需加載 (替代extract-text-webpack-plugin)
CommonJS
CommonJS是服務器端模塊的規范,由Node推廣使用,webpack也采用這種規范編寫
commonJs規范:
CommonJS模塊規范主要分為三部分:模塊定義、模塊標識、模塊引用。
模塊定義:module對象:在每一個模塊中,module對象代表該模塊自身。 export屬性:module對象的一個屬性,它向外提供接口。輸出模塊變量的最好方法是使用module.exports對象。一個單獨的文件就是一個模塊。每一個模塊都是一個單獨的作用域,也就是說,在該模塊內部定義的變量,無法被其他模塊讀取,除非定義為global對象的屬性。
模塊標識:傳遞給require方法的參數,必須是符合小駝峰命名的字符串,或者以 . 、.. 、開頭的相對路徑,或者絕對路徑。
模塊引用:加載模塊使用require(同步加載),該方法讀取一個文件并執行,返回文件內部的module.exports對象。
優勢:
在后端,JavaScript的規范遠遠落后并且有很多缺陷,這使得難以使用JavaScript開發大型應用。比如:沒有模塊系統、標準庫較少、沒有標準接口、缺乏包管理系統、列表內容
CommonJS模塊規范很好地解決變量污染問題,每個模塊具有獨立空間,互不干擾,命名空間相比之下就不太好。
CommonJS規范定義模塊十分簡單,接口十分簡潔。
CommonJS模塊規范支持引入和導出功能,這樣可以順暢地連接各個模塊,實現彼此間的依賴關系
CommonJS規范的提出,主要是為了彌補JavaScript沒有標準的缺陷,已達到像Python、Ruby和Java那樣具備開發大型應用的基礎能力,而不是停留在開發瀏覽器端小腳本程序的階段
缺點:
沒有并行加載機制
由于CommonJS是同步加載模塊,這對于服務器端是很不好的,因為所有的模塊都放在本地硬盤。等待模塊時間就是硬盤讀取文件時間,很小。但是,對于瀏覽器而言,它需要從服務器加載模塊,涉及到網速,代理等原因,一旦等待時間過長,瀏覽器處于”假死”狀態。
所以瀏覽器端不是很適合Common.Js,出現另一種規范AMD
AMD
AMD 是運行在瀏覽器環境的一個異步模塊定義規范 ,是RequireJS 在推廣過程中對模塊定義的規范化產出。
AMD規范
AMD推崇依賴前置,在定義模塊的時候就要聲明其依賴的模塊
優點
用戶體驗好,因為沒有延遲,依賴模塊提前執行了。
CMD
CMD是一個通用模塊定義規范;是SeaJs推廣過程中對模塊定義的規范化產出
CMD規范
CMD推崇依賴就近,只有在用到某個模塊的時候才會去require
優點
性能好,因為只有用戶需要的時候才執行。
防抖節流
函數防抖關注一定時間連續觸發,只在最后執行一次,而函數節流側重于一段時間內只執行一次。
//定義:觸發事件后在n秒內函數只能執行一次,如果在n秒內又觸發了事件,則會重新計算函數執行時間。//搜索框搜索輸入。只需用戶最后一次輸入完,再發送請求//手機號、郵箱驗證輸入檢測 onchange oninput事件//窗口大小Resize。只需窗口調整完成后,計算窗口大小。防止重復渲染。更多》》
const debounce = (fn, wait, immediate) => { let timer = null; return function (...args) { if (timer) clearTimeout(timer); if (immediate && !timer) { fn.call(this, args); } timer = setTimeout(() => { fn.call(this, args); }, wait); }; };const betterFn = debounce(() => console.log("fn 防抖執行了"), 1000, true);document.addEventListener("scroll", betterFn);
//定義:當持續觸發事件時,保證隔間時間觸發一次事件。//1. 懶加載、滾動加載、加載更多或監聽滾動條位置;//2. 百度搜索框,搜索聯想功能;//3. 防止高頻點擊提交,防止表單重復提交;更多》》function throttle(fn,wait){ let pre = 0; return function(...args){ let now = Date.now(); if( now - pre >= wait){ fn.apply(this,args); pre = now; } }}function handle(){ console.log(Math.random());}window.addEventListener("mousemove",throttle(handle,1000));
//淺拷貝 1. Object.assign(target,source)2. es6對象擴展運算符。//深拷貝 function deepClone(obj) { if (!obj || typeof obj !== "object") return; let newObj = Array.isArray(obj) ? [] : {}; for (let key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = typeof obj[key] === "object" ? deepClone(obj[key]) : obj[key]; } } return newObj;}
//數組const arr = [2,7,5,7,2,8,9];console.log([...new Set(arr)]);// [2,7,5,8,9];//對象const list = [{age:18,name:"張三"},{age:18,name:"李四"},{age:18,name:"王五"}]let hash = {};const newArr = arr.reduce((item, next) => { hash[next.age] ? "" : hash[next.age] = true && item.push(next); return item;}, []);console.log(list);
function flatten(arr) { return arr.reduce((result, item) => { return result.concat(Array.isArray(item) ? flatten(item) : item); }, []);}
編碼階段
盡量減少data中的數據,data中的數據都會增加getter和setter,會收集對應的watcher
v-if和v-for不能連用
如果需要使用v-for給每項元素綁定事件時使用事件代理
SPA 頁面采用keep-alive緩存組件
在更多的情況下,使用v-if替代v-show
key保證唯一
使用路由懶加載、異步組件
防抖、節流
第三方模塊按需導入
長列表滾動到可視區域動態加載
圖片懶加載
SEO優化
預渲染
服務端渲染SSR
打包優化
壓縮代碼
Tree Shaking/Scope Hoisting
使用cdn加載第三方模塊
多線程打包happypack
splitChunks抽離公共文件
sourceMap優化
用戶體驗
骨架屏
PWA
還可以使用緩存(客戶端緩存、服務端緩存)優化、服務端開啟gzip壓縮等。
寫的比較匆忙,可能有諸多問題,望各位大佬指正。
?