前端面試題
- 2021 年 6 月 8 日
- 筆記
html
常用標籤
文本,表格,表單,列表等
h1-h6,p,span,label,strong/b,i/em,img,a,div,li,ul,ol,tr,td
區分行內元素,行內塊級元素,塊級元素
行內:同行顯示,不支持寬高,span,a,label等;
行內塊:同行顯示,支持寬高,默認有5px間距,input,img,td,button,select等等
塊級:獨佔一行,支持寬高,h,p,table,tr等
如何理解HTML語義化?
根據內容的結構化(內容語義化),選擇合適的標籤(代碼語義化)便於開發者閱讀和寫出更優雅的代碼的同時讓瀏覽器的爬蟲更好地解析。 使用語義化標籤有諸多好處:
-
因為像部分標籤自帶樣式如h1系列,p等,使用語義化的標籤可以在樣式加載不出的時候有基本樣式,而不顯混亂
-
語義化標籤也有利於SEO,語義化標籤可以有利於爬蟲抓取到網頁,因為爬蟲依賴於標籤來確定上下文和各個關鍵字的權重。
-
語義化標籤的實現有利於一些特殊設備的解析,比如盲人閱讀器,這為他們瀏覽網頁帶來了便利
-
語義化標籤代碼可讀性良好,便於代碼維護
css
link和@import異同?
都可以在html中引入css文件
區別:
link是服務於整個網頁,@import服務於css
link是一個標籤,@import是一種語法
link不只可以引入css文件,還可以引入其他文件格式,@import只能引入文件
加載時間:link加載css文件,隨着頁面的加載而加載,@import等待頁面加載完成之後再加載css文件
兼容性:link兼容比@import要好一些
JavaScript可以操作link引入樣式,@import不能被操作。
如何讓一個盒子在水平方向和垂直方向都居中
通過設置絕對定位和margin自動計算:給四個方向都為0,在配合margin:auto auto;
通過絕對定位:top:50%,left:50% margin top/left 自身寬高的一半;
通過彈性布局:搭配 justify-content 主軸居中 align-item 縱軸居中
less或者sass相比於css有什麼優勢?
支持嵌套
支持變量定義
支持’模板函數(自己定義的名稱)’:有些CSS需要做兼容前綴的話,你可以這樣使用一個模板函數定義一下,調用的時候傳入正常值就可以了。會自動生成前綴的CSS
如何做響應式布局或者如何適配
em/rem:em基於父級元素的字體大小,rem基於根標籤的字體大小
flex彈性盒模型
媒體查詢
使用百分比布局
通過vw/vh來實現自適應
css sprite(雪碧圖或者精靈圖) 有什麼優缺點?
將多張圖片放在一起構成一張圖,從而減少請求服務器次數,來優化網頁;
缺點:更改圖片時不易更改
你知道哪些css3新特性和h5新特性
css3:透明度、背景圖片、陰影、動畫、圓角、彈性盒模型
html5:語義化標籤:header,footer,nav etc.、canvas 畫布、audio, video、drag 拖拽、本地存儲 localStorage, sessionStorage、webSocket 長連接、定位、增強型表單 input number, datalist, keygen, output, progress、svg 矢量繪圖、webWorker 實現js多進程。
rgba()和opacity的透明效果有什麼不同
rgba() 和 opacity 都能實現透明效果,但最⼤的不同是 opacity 作⽤於元素,以及元
素內的所有html標籤及文本的透明度,
⽽ rgba() 只作⽤於元素的顏⾊或其背景⾊。(設置 rgba 透明的元素的⼦元素不會繼承
透明效果!)
js
js數據類型有哪些?有什麼區別
引用類型:object 數據存放在堆中,棧中存放指針指向堆中的數據
其他都是基本數據類型
number,string,object,undefined,boolean,null,symbol,BigInt
談一下你對作用域的理解
作用域指在運行代碼中的某些特定部分中變量,函數和對象的可訪問的範圍
主要分為全局作用域,函數作用域和塊級作用域
全局作用於全局,在代碼任何地方都能夠訪問到;
函數作用域指在函數內部的變量,只作用域函數內部;
塊級作用域指lethe const聲明,所聲明的變量在指定塊的作用域外無法被訪問;
談一下你對原型的理解
原型:構造函數的prototype.constructor指向自身,每個實例對象(object)都有一個私有屬性(稱之為proto)指向它的構造函數的原型對象(prototype)。該原型對象也有一個自己的原型對象(proto),層層向上直到一個對象的原型對象為null。根據定義,null沒有原型,並作為這個原型鏈中的最後一個環節。
原型鏈:對象在訪問某個屬性時,會現在本對象上找,如果沒有找到,則去對應的原型里找,找到了直接使用,如果還沒找到,如果原型對象上還有原型,那麼會繼續往上一層原型對象中查找,直到原型對象為object類為止,如果到object類還沒找到,則返回undefined
什麼是閉包
閉包就是能夠讀取其他函數內部變量的函數;
嵌套的內部函數,包含被引用變量(函數)的對象;
優點:閉包會延長變量的聲明周期;缺點:會造成內存佔用
如何修改函數的this指向,這些方法之間有什麼區別?
三個方法:call,apply,bind
三個功能相同,區別在於參數的不同或是否立即調用:
call和apply之間唯一區別就是傳參的不同。第一個參數仍都是指的執行對象,call方法從第二個參數開始,會將後續的參數當成函數所需的數據。而apply則吧函數所需的數據都放在數組裏面,數組作為apply方法的第二個參數。(apply傳遞參數需要使用數組包裹);
call和bind之間的區別是call是立即調用所需的函數,只能調用一次。而bind參數跟call是一樣的,不過bind不會馬上執行,而是將所需要的函數給返回,這樣就可以重複的使用所需的函數(apply,call會立即執行一次,bind是創建一個新函數,不會立即執行)
bind只生效一次。
理解=>前兩個會立即執行,bind返回一個新的函數,並指向參數
事件委託或者事件代理的原理是什麼?
事件委託是利用事件冒泡原理實現的,給父級或祖先標籤設置一個事件處理程序,然後利用event對象里的target來判斷實際觸發事件的標籤,然後調用對應的處理代碼
事件冒泡和事件捕獲的區別是什麼?
冒泡:執行一次完整的冒泡,即從具體子標籤開始觸發,直到window對象為止,即從目標節點傳導回window
對象(從底層傳回上層)。
捕獲:從window對象觸發,一直到具體的子標籤為止,即從window
對象傳導到目標節點(上層傳到底層)。
你知道的es6新特性有哪些?
let和const,object.keys(),for…of,擴展運算符,set和map,模板字符串,結構賦值,默認參數,rest參數,箭頭函數,解構賦值
js異步編程方式有幾種
回調函數,事件監聽,Promise,async/await, generator
promise有幾種狀態
pending fulfilled rejected 當我們創建一個Promise對象的時候,它的狀態默認是pending ,要修改它的狀態必須調用resolve方法或者reject方法
const myPromiseObj = new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve() }) }) myPromiseObj.then(()=>{}).catch(()=>{})
js如何淺拷貝和深拷貝一個對象
淺拷貝是指複製指向某個對象的指針(地址)而不複製對象本身,新舊對象還是共享同一塊內存,修改一個另一個也會改變。
深拷貝會另外創造一個一模一樣的對象,新對象跟原對象不共享內存,修改新對象不會改到原對象。
淺拷貝:Object.assign 或者拓展運算符...,concat(),賦值 = slice
深拷貝:const deepCopiedObj = JONS.parse(JSON.stringify(obj))
rem和em和px的區別
px是固定單位,rem和em是響應式單位,1rem的大小取決於根節點html的字體大小(即font-size屬性),1em的大小取決於其父節點的字體大小,在移動端我們一般用rem,但是要注意:這時html的fontSize屬性應該是動態計算的,而不是寫死,一般是把當前可視窗口的寬度除以一個經驗值得到的比值作為html的fontSize屬性值的。
for循環中break和continue的區別是什麼?
break:跳出整個循環
continue:跳出檔次循環,繼續執行後面的循環
如何用原生js給一個按鈕的點擊事件綁定兩個事件處理函數
addEventListener
js引擎如何實現異步的?
js引擎是通過事件循環(Event Loop)實現異步的;js引擎在執行代碼的過程中,如果遇到異步任務,則跳過該異步任務,繼續執行後面的同步任務,同步任務執行完了,再執行異步代碼
完整:瀏覽器是多線程,js引擎只是瀏覽器的其中一個線程,除此之外,它還有http請求線程,事件處理線程,定時觸發線程,GUI渲染線程
js引擎線程:執行js代碼
執行棧:所有的js代碼都要在執行棧裏面執行
任務隊列:關於異步任務的回調函數最終都會被放到任務隊列中來等待執行 先進先出
異步微任務對列(優先級更高) :promise.then proccess.nextTick
異步宏任務隊列 setTimeout setintval
http請求線程:發送http請求
事件觸發線程:監聽用戶事件
定時觸發線程:計時
GUI渲染線程:界面的渲染,該線程和js引擎線程是互斥的,兩個只能同時執行一個
js引擎如何實現異步
當js引擎在執行棧中執行js代碼的時候,如果遇到了異步任務(比如發送請求),則js引擎會把該異步任務交給瀏覽器的其他線程處理(http請求線程)。
js引擎繼續之後後面的同步任務,當執行棧中的任務清空之後,js引擎就會到任務隊列裏面去查找有沒有待執行的回調,有的話,就拿到執行棧中去執行,執行完了,又會去任務隊列中去查找有沒有待執行的回調,有,就拿到執行棧中執行,如此循環往複的過程就是事件循環(Event Loop),理解了事件循環就相當於理解js引擎如何實現異步。
其他線程(http請求線程)也在同時的工作,當其他線程把異步處理完了(http請求線程接口發送成功)之後,它會把我們設置的回調函數推送到js引擎的任務隊列里
什麼是事件循環??
js引擎裏面有兩個非常重要的部分:執行棧和任務隊列
所有的代碼都要加載到執行棧裏面進行執行
在執行過程中如果發現有異步任務,則js引擎會把這個異步任務交給瀏覽器的其他線程去處理,比如在執行的時候遇到
接口發送,則js引擎會把它交給http請求線程去處理,然後js引擎繼續執行後邊的同步任務,但是同http請求線程也在同時
運作,當請求發送成功之後,即數據拿到之後,http請求線程會將我們之前在js裏面設置的回調函數推送到js引擎的任務隊列裏面
當js引擎在執行棧裏面把任務清空之後,則回到任務隊列裏面去尋找有沒有待執行的回調函數,有則拿到執行棧裏面去執行
執行完了之後,又會到任務隊列裏面去尋找有沒有待執行的回調,如此循環往複的過程就是事件循環,理解了事件循環就理解了
* 瀏覽器是多線程的,js引擎只是其中一個線程,除此之外還有http請求線程,定時觸發線程,事件處理線程,GUI渲染線程
什麼是函數柯理化?
通過函數返回函數的方式(閉包),讓一個一次性接受多個參數的函數,分解為一次只接受一個參數的若干函數的組合
其作用是為了參數的復用,
函數柯理化:把原本會一次性接收多個參數的函數,利用閉包的形式變成一次只會接收一個參數的多個函數;
作用:復用參數
function towSum(a,b){ return a + b; } //現在對上面的函數進行柯理化 function towSum(a){ return function(b){ return a + b; } } 或者 const res = (a)=>(b)=>a+b; 調用: towSum(1)(2); 或者 const res = towSum(1)(2); res(3)
微任務和宏任務的區別
DOMContentLoaded和load事件的區別
防抖和節流有什麼區別,如何實現
在高頻觸發的事件中,可能會導致一些性能問題,比如在PC端瀏覽器縮放時(resize事件),我們在事件處理函數裏面如果操作DOM,則用戶縮放的時候,可能會導致瀏覽器卡頓,這是我們就可以通過防抖節流來控制操作DOM的頻率,避免過快的操作DOM,但是這兩者的區別在於:
防抖的思路是:設置一個延時器,延時n秒在執行相應的邏輯(即頻繁執行可能會影響性能的邏輯),如果在n秒內,再次執行了,則清空延時器,並從當下開始從新設置延時器,n秒後再執行。
節流的思路是:在特定的時間段內,相應的邏輯必須有且只能執行一次。
//防抖 function debunce(func,time){ let timer = null; return function(){ if(timer)clearInterval(timer); timer = setTimeout(()=>{ func.apply(this,arguments) },time); } } //節流 function throttle(func,time){ let preTime = +new Date() //上一次執行的時間戳 return function(){ const curTime = +new Date() //本次執行的時間戳 if(curTime - preTime >= time){ //對比當前執行時間和之前執行時間 是否大於time秒 大於則執行func的邏輯 func.apply(this,arguments); preTime = curTime; } } }
代碼題
var a = {}; var b = {key:"b"}; var c = {key:"c"}; a[b] = "b"; a[c] = "c"; console.log("a[b]",a[b]);//???
-
var age = 100; let years = 6; if(age > 12){ let age = 10; var years = age*3; } //問:以上代碼有問題嗎?
-
componentDidMount() { this.setState({ count: this.state.count + 1 }); console.log('1', this.state.count); this.setState({ count: this.state.count + 1 }); console.log('2', this.state.count); setTimeout(() => { this.setState({ count: this.state.count + 1 }); console.log('3', this.state.count); this.setState({ count: this.state.count + 1 }); console.log('4', this.state.count); }, 0); } //打印結果
-
function Cat() { let showName = function () { console.log(1); } return this; } Cat.showName = function () { console.log(2) }; Cat.prototype.showName = function () { console.log(3) }; var showName = function () { console.log(4) }; function showName() { console.log(5) }; Cat.showName(); showName(); Cat().showName(); showName(); new Cat.showName(); new Cat().showName(); new new Cat().showName(); //打印結果??
-
function Cat() { showName = function () { console.log(1); } console.log('this',this) return this; } Cat.showName = function () { console.log(2) }; Cat.prototype.showName = function () { console.log(3) }; var showName = function () { console.log(4) }; function showName() { console.log(5) }; Cat.showName(); showName(); Cat().showName(); showName(); new Cat.showName(); new Cat().showName(); new new Cat().showName(); //打印結果,注意跟上一題的區別
-
這段代碼有什麼問題嗎?
this.setState((state,props)=>{ return {total:state.total + props.count} });
-
查看一下代碼:如果你在頁面中創建了一個React元素,請完成他的組件定義?
<Profile username="sofn"> {user=>user===null ? <Loading/> : <Badge info={user}/>}{" "} </Profile> import React ,{Component} from 'react'; import PropTypes from 'prop-types'; import fetchUser from 'utils'; //fetchUser接收用戶名,並返回promise //當得到用戶數據的時候返回resolve狀態 class Profile extends Component{ //在這裡寫下你的代碼 }
vue
vue組件中watch和computed的區別
1. watch中一個值的變化可能會引起多個值的變化,而compouted中多個值的變化會只會影響一個值的變化(即該計算屬性返回的值)
-
在watch中我們可能會有副作用,比如發送請求等,而computed則沒有副作用,僅僅是根據母體數據衍生出新的數據而已。
vue常用的生命周期鉤子函數有哪些?分別有什麼作用?
鉤子函數 | created | mounted | updated | beforeDestory |
---|---|---|---|---|
執行時機 | 數據初始化完畢之後 | DOM渲染完畢之後 | 數據更新完畢並且DOM更新完畢之後 | 組件卸載之前 |
作用 | 發送請求 | 發送請求、獲取DOM等 | 發送請求(注意加上條件判斷)、獲取DOM等 | 性能優化相關,比如清除定時器、延時器、解綁事件等 |
vue如何實現組件通信(組件傳值)? 父子 兄弟 複雜組件關係
組件關係 | 父子 | 兄弟 | 複雜組件關係 |
---|---|---|---|
通信方式 | props/綁定自定義事件、$emit | 狀態提升、事件總線 | 狀態機vuex |
vue項目如何做路由攔截?
全局路由守衛(router.beforeEach)、局部(頁面內部)路由守衛
vue的響應式原理 Object.defineProperty
vue組件中data裏面的數據,在初始渲染之前都會被Object.defineProperty轉化成響應式數據,然後這些數據的訪問和修改就能夠被監聽了,每當數據被訪問的時候就會觸發getter,接着會通知watcher,watcher這是會做一次依賴的收集或者更新,然後watcher會負責通知渲染界面(先轉化為虛擬DOM,在映射為真正的DOM)。每當數據被設置的時候會觸發setter,接着setter也會通知watcher,watcher在去通知渲染界面
作用:生成響應式的數據,即通過該方法設置過的屬性,它的設置和獲取都能夠被監聽
let o = { name = '張三' } let _name = o.name;//賦值 方便訪問o.name object.defieProperty(o,'name,{ get:function() { console.log('get函數執行了') return _name }, set:function(val) { console.log('set函數執行了',val) _name = val //在get和set裏面不能使用name 因為用了name就是會去get裏面訪問 然後又去訪問 死循環了 } }') o.name = '王二麻子' console.log(o.name) // 王二麻子
v-if和v-show的區別
v-if 操作節點 性能消耗高
v-show 操作樣式
v-if和v-for能一起用嗎
當 v-if
與 v-for
一起使用時,v-for
具有比 v-if
更高的優先級,這意味着 v-if
將分別重複運行於每個 v-for
循環中
理論上是可以的 但是性能消耗高 不推薦
keep-alive組件有什麼作用
緩存組件 注意它的兩個鉤子函數
this.$nextTick有什麼作用
類似updated,你可以稱作移動版的updated,如果你想獲取數據更新過後,DOM的最新狀態,則可以使用該方法(如果你直接獲取DOM狀態是拿不到的,因為在vue裏面數據更新雖然是同步的,但是DOM的更新是異步的),當然你也可以利用updated生命周期鉤子函數,但是不方便
this.$set有什麼作用
在組件data中預定義的數據,一定是響應式的,但是我們後續,通過常規的方式(比如someObject.propName = xxx)為data中某些對象添加新的屬性時,這些新的屬性並不是響應式的,這是可以使用該方法。 this.$set(target,prop,value) 這裡的prop屬性就是響應式的
vuex核心概念
state 數據源,載體 getters 用於改變state的值,派生出多個數據源 mutation 唯一可以提交可以改變state的狀態,也就是數據的屬性值 actions 提交的是mutation,用commit提交 而不是直接變更狀態,可以包含任意異步出操作
vue如何做路由懶加載
路由配置中component屬性的值修改為:()=>import(組件路徑)
你認為vue 框架和jquery有什麼區別?
開發思想不同,vue是數據驅動,並且可以組件化開發,jquery則是DOM驅動的,開發效率低
vue如何自定義指令
如何封裝一個vue插件
什麼是過濾器(filter)
vue中extends的用法
vue如何提取組件的公共邏輯
vuex/mixins/自定義指令/插件
react
shouldComponentUpdate有什麼作用?
它是react組件的一個 生命周期鉤子函數,每次數據更新時,首先會執行該鉤子函數,如果返回true,表示可以更新界面,然後後續的鉤子函數才會陸續執行,返回false,則表示不可以更新,後續的鉤子函數也不會執行,當然它默認返回true,
我們一般不會直接在組件中使用該鉤子函數,而是會選擇PureCompopnent來代替Component,在PureComponent裏面就利用來該鉤子函數來做優化
setState有什麼特性
它的作用是更新組件內部狀態,可以接受兩個參數,參數一個一般是個對象,在底層react會通過Object.assign把傳入的對象和原來的state進行合併,當然也可以傳入一個函數,這個函數會接受兩個形參(一個表示state,一個表示props),並返回個對象,要注意的是,這個函數在執行是會保證之前的state已經更新完畢,最後在把該函數返回的對象和原來的對象進行合併。當新的狀態值會基於老的狀態值時,我們會傾向於給setState的第一個參數傳遞一個函數進去。它的第二個參數則是一個回調函數,會在數據更新完畢,並且dom更新完畢時執行。
另外,當我們在react事件體系或者組件生命周期鉤子函數裏面直接調用setState的時候,它是異步的,其他情況是同步的,比如在setTimeout/setInterval裏面調用就是同步的
this.setState({name:'張三'}); this.setState((state,props)=>({})
react列表渲染時,key的作用
提升渲染性能
react組件之間如何通信
父子(props)、兄弟(狀態提升、事件總線)、複雜組件關係(狀態機)
解釋一下redux核心概念
store action reducer
react常用的生命周期鉤子函數有哪些?分別有什麼作用
鉤子函數名 | constructor | render | componentDidMount | componentDidUpdate | componentWillUnmount |
---|---|---|---|---|---|
執行時機和作用 | 組件初始化時負責數據的初始化 | 渲染界面 | DOM渲染完畢時執行,可以在這裡發送接口,獲取DOM等 | 數據更新完畢且界面更新完畢後執行 | 組件即將卸載的時候執行,可以在這裡清除定時器,延時器,解綁事件等等 |
react中refs有什麼作用?
1. 獲取DOM
-
獲取組件實例
redux中間件是什麼,有什麼作用,你常用的中間件有哪些?
redux三大原則是什麼?
-
單一數據源
-
store中的數據(state)是只讀的,唯一修改state的方法就是派發action
-
必須通過純函數reducer來執行修改
react中容器組件和展示組件有什麼區別?
函數組件和類組件有什麼區別(16.8以前)?
你對react新特性hooks有什麼了解嗎?
react如何提取組件之間的公共邏輯
什麼是高階組件?有什麼作用?你常用的高階組件有哪些
受控組件和不受控組件有什麼區別?
JSX的底層原理是什麼?
react組件的數據來源有哪些?他們之間有什麼區別?
react插槽是什麼?(或者react中如何實現組件複合?)
react中context是什麼?
react中廢棄了哪些和新增了哪些生命周期鉤子函數
小程序
小程序一個頁面有幾個文件構成?
小程序怎麼跟後台交互
(1)直接用微信官方提供的接口 wx.request接口,跟jquery的ajax差不多
小程序怎麼做掃碼功能(wx.scanCode),怎麼做支付功能(wx.requestPayment)
(1)調用微信提供的現成的接口(wx.開頭的),即可,具體參數怎麼傳參照文檔即可
微信裏面怎麼獲取用戶的手機號??
(1)簡單,直接用微信官方提供的現成組件button即可,具體用法是在button上加一個屬性opent-type,方它的值為getPhoneNumber,不知道怎麼用的去找微信官文檔看看、
小程序分包是什麼?有什麼作用?
提示:跟vue路由懶加載有類似的作用,提升用戶體驗度,減少首屏渲染速度
//developers.weixin.qq.com/miniprogram/dev/framework/subpackages/basic.html
//blog.csdn.net/acmdown/article/details/80037660
其他
性能優化
從用戶在瀏覽器中輸入url,到瀏覽器渲染出界面,中間發生了什麼?
DNS域名解析——》發起http或者https請求——》服務端處理請求——-》瀏覽器接受請求響應,並渲染界面
SPA(single page application)如何提高首屏(注意:不是首頁,一般你在url中輸入一個新的路勁,然後回車,即是一個首屏)的渲染速度
DNS域名解析部分優化
-
DNS prefetch(DNS預解析)
在html頭部使用link標籤進行DNS預解析
<link rel="dns-prefetch" href="//www.baidu.com">
發起請求部分
-
減少請求次數
-
採用css sprinte(也叫雪碧圖或者精靈圖),即:如果有多張比較小的背景圖,可以合成一個,然後通過background-position去設置背景,而不用每個都去發送請求
-
某些圖片編譯成可以是用base64格式(webpack中的url-loader會自動把大小小於某些值的圖片編譯成base64格式的,然後內嵌到js文件中,所以後續在訪問這些圖片時,不在需要單獨發送請求)
-
何時用base64格式的圖片??,可以參考以下幾個因素
-
這類圖片不能與其他圖片以CSS Sprite的形式存在,只能獨行
-
這類圖片從誕生之日起,基本上很少被更新
-
這類圖片的實際尺寸很小
-
這類圖片在網站中大規模使用
-
-
-
合併腳本和樣式表,但是要視情況而定,如果合併腳本或者樣式表後,包的體積變得非常大,反而會過度延長網絡請求時間,從而導致首先渲染更慢
-
利用http緩存(新鮮度限值和服務器在驗證)
-
-
減少請求或者服務端響應式時(當然主要是響應),網絡數據包的大小
-
壓縮css/js、圖片等
-
路由懶加載
-
-
縮短網絡的傳輸距離,優化網絡傳輸路徑
-
利用CDN(內容分髮網絡),一般我們會把靜態資源,即很少變化,體積有比較大的資源交給CDN服務商管理
-
服務端優化:不需要關注
使用單獨的圖片服務器、使用redis緩存、使用負載均衡等等
瀏覽器渲染
-
css放在body之前,script放在body之後
-
ssr(server side render—服務端渲染)
-
requestAnimationFrame
對於動畫來講:定時器為什麼不是一個好的方案
1. 開發人員並不知道,間隔多少時間出發一個動畫何時,間隔時間如果太短,則會損耗瀏覽器的性能,如果間隔時間太長,則用戶就會感覺卡頓。並且定時器自身機制的問題,它的回調函數觸發的時機可能並不是你設置的時間,因為他要等到執行棧裏面的任務清空之後再去執行
優化要達到的目的:間隔時間合適,同時用戶不會覺得卡
分析:
第一:間隔時間要合適,你自己手動設置肯定不行,因為延時器或定時器觸發的時機本就不精確。
第二:用戶不會覺得卡頓,首先我們要搞清楚是什麼原因導致的卡頓,所以接下來,我們要解釋一下瀏覽器幀的概念
幀:瀏覽器中的頁面是有一幀一幀繪製出來的,當每秒鐘繪製的幀數(FPS–Frame Per Second)大於或等於60的時候,用戶是感覺不到卡頓的,換言每一幀的時間控制在1s/60,也就是大約16.6毫秒之內時,用戶是感覺不到卡頓的。
在一幀中瀏覽器大致做了如下事情(有時不一定每一步都會執行):
1. 處理用戶的交互
2. js解析執行(例如用戶事件處理函數中的邏輯)
3. 調用window.requestAnimationFrame中註冊的函數(注意:這個函數其實是上一幀中註冊的函數,且如果在這一幀中發現有註冊的函數,則該函數一定會被執行)
4. Layout(布局,如果第二次觸發,我們就稱之為迴流)
5. Paint(繪製,如果第二次觸發我們就稱之為重繪)
6. 如果前五步驟執行完了之後,這一幀還有剩餘時間,則調用window.requestIdleCallback中註冊的函數
也就是說這前五個步驟(其他我們先暫時不用考慮)執行時間總和要在16.6毫秒內,才能保證用戶體驗。
結論:我們可以利用requestAnimationFrame實現動畫邏輯,並且不需要傳遞時間,在這裡觸發動畫,一般情況1秒鐘也能達到60幀(當然動畫里的邏輯也不能太複雜,在這一步,如果執行時間過長也會導致掉幀(1秒鐘沒有達到60次),從而讓用戶決定卡頓),具體用法如下(實現一個元素,在水平方向上左右移動的效果)
<div style="width:50px;height:50px;" id="myDiv"></div> let originStep = 10; let step = 10;//每次移動的距離 let direction = 1;//移動的方向1表示向右,-1表示向左 let left = 0;//元素的偏移量 const offsetWidth = document.body.offsetWidth;//body的寬度 const el = document.getElementById('myDiv'); const eleWidth = el.offsetWidth;//元素的寬度 const runAnimation = () => { if(direction === 1){ const remainOffset = offsetWidth - (left + eleWidth);//向右移動時,距離右邊距剩餘距離 if(remainOffset < step && remainOffset !== 0){ step = remainOffset;//保證向右的移動不會超出右邊接線 } }else{ step = originStep;//當向左移動的時候恢復移動速度 } if(left <=0){ direction = 1; }else if(offsetWidth <= left + eleWidth){ direction = -1; } const xOffset = left += step*direction; el.style.transform = `translate(${xOffset}px,0)`; requestAnimationFrame(runAnimation);//在註冊回調 } requestAnimationFrame(runAnimation)
-
requestAnimationFrame執行過後會返回一個id,跟定時器一樣,我們可以根據這個id取消對應的requestAnimationFrame
const cancelId = requestAnimationFrame(runAnimation);
cancelAnimationFrame(cancelId);
-
-
requestIdleCallback
SSR(Server Side Render)和CSR(Client Side Render)
SSR
瀏覽器中顯示的頁面,是由服務器拼接好模板,然後通過網絡傳送到瀏覽器,在有瀏覽器直接渲染的,由於在網絡傳輸路徑中攜帶了網頁的內容,所以ssr模式非常適合做SEO,同時服務器拼裝模板的速度會比瀏覽器快很多,所以SSR模式也會提升網站的首屏渲染速度。但是也會增加服務端的壓力。
ssr兩個優勢
利於seo
縮短首屏渲染速度
CSR
webpack
webpack有什麼作用?
什麼是webpack ? 模塊化的打包工具,原理是,我們必須向它提供一個入口js文件,然後webpack會根據這個入口文件生成一張依賴圖,然後在堆這張依賴圖裏面的文件進行轉義和打包,最後生成瀏覽器能夠識別的資源文件(css js 。。。)
作用:
1. 讓項目模塊化
-
編譯scss/less .vue jsx
-
性能優化:壓縮、代碼拆分、圖片轉base64格式。。。
-
工程化:自動編譯、打包
webpack常用配置項有哪些?(webpack.config.js)
-
entry:入口文件
-
output:出口文件
-
module
module:{ rules:[ { test:/\.css$/, use:['style-loader','css-loader'],//從後往前執行 } ] }
網絡相關
常用的http狀態碼有哪些,
1. 200
-
404
-
401
-
500
-
304
-
301 資源永久重定向
http和https的區別
安全:https協議在傳輸數據的時候,會對數據進行加密,http則是明文傳輸
性能:http協議的傳輸性能更高,因為對於傳輸同樣的數據量來講,由於https協議需要加密處理,所以最終在線路上它的數據量要大一點
費用:https需要購買證書,http則免費
默認端口不同:https–443 http—80
websokect和http的區別
websokect能夠實現客戶端和服務端的雙向通信,http則只能是單向通信,由客戶端去請求服務端,服務端不能主動的向客戶端推送數據
應用場景不同
websokect 實時通信 數據的實時更新
http 簡單的客戶端請求服務端
業務相關
如何處理權限問題
比如後台管理系統,不同的角色看到的側邊欄項是不同的,如何實現?
首先把側邊欄抽象成一個數組,數組裏面每一元素(對象)則表示每一個側邊欄,並且在每一個元素裏面,我們需要添加一個表示角色的字典,以此來區分,何種角色能夠看到當前側邊欄項,
接線來,就要根據當前登錄人的角色 去 過濾當前數組,並返回當前角色能看到的側邊欄數據
最後在根據得到的數據,進行遍歷循環,渲染側邊欄
前端如何實現身份驗證
前端現在一般用token實現身份驗證, 登錄過後後端會給到前端返回一個token,然後我們把這個token存到本地存儲,然後後續在進到主頁之後,基本所有的接口發送時,我們都要把這個token添加到header裏面,
這時,後端接受到請求之後,會先去解析token,如果能夠正常的解析,則表單當前登錄人沒有問題,可以正常返回數據,否則返回401
數據可視化如何實現(echart)
option setOption(option)
如何實現數據的實時更新 websokect
在項目中如何做到token的無感刷新
uni-app中要路徑跳轉,如何提高效率
使用uni.preloadPage頁面預加載,但是該方法有兼容性問題,只在app端和H5端有效
請說一下你項目中微信支付流程如何做的
說一下項目中微信授權登錄的流程。前後端是如何去交互的
參照://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
項目中權限如何如何渲染,如果後端的權限粒度要控制到每個功能如何實現
為什麼使用uni-app,你在項目開發的過程中遇到哪些兼容問題,以及如何處理的
-
頁面預加載,只有H5和APP端支持,小程序不支持
-
css中給元素設置背景圖,H5端支持,小程序不支持(在小程序端用行內樣式設置背景圖即可)
-
css中通配符*在H5端支持,但是小程序不支持
-
在非H5端不能使用ref的方式引用內置組件(比如view等)
-
如果想為不同的平台寫不同的代碼,可以使用條件編譯
-
項目中遇到的最大的問題是什麼
在頁面中如果要同時發送5個接口,當所有接口都成功相應之後,再去做其他操作,這個如何實現
項目是如何打包上線的,打包的時候需要配置些什麼內容
項目中如何實現上拉加載,下拉刷新的,如果要自己實現,說一下思路
前端登錄後,傳遞id給後端獲取數據,這種方式安全嗎?你是如何來避免的
1. 把get方式換成POST
-
如果我用抓包工具,把數據抓下來,在偽裝發送接口,怎麼辦?—–http–>https
項目如何打包為apk,如果是ios系統,如何打包呢
團隊中各個成員是如何配合的
微信小程序如何發佈上線
微信小程序上線發佈,通過有上角的上傳按鈕即可哈,上傳後,微信官方會做一個審核,審核通過之後,我們就能夠通過微信搜索到該小程序了
瀏覽器
什麼是跨域?如何解決
跨域是瀏覽器的同源策略導致的問題,當我們的協議、域名和端口號,任意一個不同的時候,就會導致跨域的出現
常見的一個場景,前端請求後端api的時候出現跨域,如何解決?
-
前端處理:代理服務器 webpack-dev-server (vue.config.js)
devServer:{
proxy:{
"/api":{
target:"//localhost:8000"
}
}
} -
後端處理
-
設置響應頭
-
瀏覽器渲染頁面的流程
GUI渲染線程負責界面的渲染過程
同時解析html/css
解析html —->DOMTree
解析css—>CSSTree
然後合併DOMTree和CSSTree形成RenderTree(渲染樹)
接下來開始layout (布局,迴流)
繪製(重繪)
根據這些過程我們可以知曉在寫html的時候需要注意的一些事項(性能優化)
1. css放在頭部
-
js放在尾部,因為js是有js引擎去編譯和執行的,而js引擎和GUI渲染引擎是互斥的
重繪和迴流有什麼區別
數據結構相關
你知道的數據結構有哪些?
棧、隊列、鏈表、二叉樹
空間複雜度和時間複雜度
這個兩個概念是用來衡量一個算法優劣的兩個維度,空間複雜度表示,算法所消耗的內存大小,而時間複雜度,表示一個算法所消耗的時間。一般情況下,我們更看重一個算法在時間上的消耗。如果時間太長,則認為這個算法是不太好的需要優化,所以才會有用空間換時間這個說法。
時間複雜度可以用大O表示法。