這篇文章主要講解了“web前端面試問答題有哪些”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“web前端面試問答題有哪些”吧!
10年積累的成都網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)經(jīng)驗(yàn),可以快速應(yīng)對(duì)客戶對(duì)網(wǎng)站的新想法和需求。提供各種問題對(duì)應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識(shí)你,你也不認(rèn)識(shí)我。但先網(wǎng)站制作后付款的網(wǎng)站建設(shè)流程,更有漳縣免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
這兩個(gè)方法都可以用來判斷變量類型
區(qū)別:前者是判斷這個(gè)變量是什么類型,后者是判斷這個(gè)變量是不是某種類型,返回的是布爾值
(1)typeof
缺陷:
1.不能判斷變量具體的數(shù)據(jù)類型比如數(shù)組、正則、日期、對(duì)象,因?yàn)槎紩?huì)返回object,不過可以判斷function,如果檢測(cè)對(duì)象是正則表達(dá)式的時(shí)候,在Safari和Chrome中使用typeof的時(shí)候會(huì)錯(cuò)誤的返回"function",其他的瀏覽器返回的是object.
2.判斷null的時(shí)候返回的是一個(gè)object,這是js的一個(gè)缺陷,判斷NaN的時(shí)候返回是number
(2)instanceof 可以用來檢測(cè)這個(gè)變量是否為某種類型,返回的是布爾值,并且可以判斷這個(gè)變量是否為某個(gè)函數(shù)的實(shí)例,它檢測(cè)的是對(duì)象的原型
let num = 1
num instanceof Number // false
num = new Number(1)
num instanceof Number // true
明明都是num,而且都是1,只是因?yàn)榈谝粋€(gè)不是對(duì)象,是基本類型,所以直接返回false,而第二個(gè)是封裝成對(duì)象,所以true。
這里要嚴(yán)格注意這個(gè)問題,有些說法是檢測(cè)目標(biāo)的__proto__與構(gòu)造函數(shù)的prototype相同即返回true,這是不嚴(yán)謹(jǐn)?shù)?,檢測(cè)的一定要是對(duì)象才行,如:
let num = 1
num.__proto__ === Number.prototype // true
num instanceof Number // false
num = new Number(1)
num.proto === Number.prototype // true
num instanceof Number // true
num.proto === (new Number(1)).proto // true
此外,instanceof還有另外一個(gè)缺點(diǎn):如果一個(gè)頁面上有多個(gè)框架,即有多個(gè)全局環(huán)境,那么我在a框架里定義一個(gè)Array,然后在b框架里去用instanceof去判斷,那么該array的原型鏈上不可能找到b框架里的array,則會(huì)判斷該array不是一個(gè)array。
解決方案:使用Object.prototype.toString.call(value) 方法去調(diào)用對(duì)象,得到對(duì)象的構(gòu)造函數(shù)名??梢越鉀Qinstanceof的跨框架問題,缺點(diǎn)是對(duì)用戶自定義的類型,它只會(huì)返回[object Object]
第三問:作用域安全的構(gòu)造函數(shù)--當(dāng)我們new一個(gè)構(gòu)造函數(shù)的時(shí)候可以獲得一個(gè)實(shí)例,要是我們忘記寫new了呢?// [1,2,3] instanceof Array ---- true
// L instanceof R
// 變量R的原型 存在于 變量L的原型鏈上
function instance_of(L,R){
// 驗(yàn)證如果為基本數(shù)據(jù)類型,就直接返回false
const baseType = ['string', 'number','boolean','undefined','symbol']
if(baseType.includes(typeof(L))) { return false }
let RP = R.prototype; //取 R 的顯示原型
L = L.__proto__; //取 L 的隱式原型
while(true){ // 無線循環(huán)的寫法(也可以使 for(;;) )
if(L === null){ //找到最頂層
return false;
}
if(L === RP){ //嚴(yán)格相等
return true;
}
L = L.__proto__; //沒找到繼續(xù)向上一層原型鏈查找
}
}
例如
function Person(){
this.name = "小紅"
}
p = Person();
這會(huì)發(fā)生什么問題?,怎么解決
這樣直接使用,this會(huì)映射到全局對(duì)象window上。解決方法可以是:首先確認(rèn)this對(duì)象是正確類型的實(shí)例。如果不是,那么會(huì)創(chuàng)建新的實(shí)例并返回。請(qǐng)看下面的例子
function Person(){
if(this instanceof Person){
this.name = "小紅"
}else{
return new Person()
}
}
p = Person();
在JavaScript代碼中,由于瀏覽器之間行為的差異,多數(shù)JavaScript代碼包含了大量的if語句,以檢查瀏覽器特性,解決不同瀏覽器的兼容問題。例如添加事件的函數(shù):
function addEvent (element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
}
每次調(diào)用addEvent()的時(shí)候,都要對(duì)瀏覽器所支持的能力仔細(xì)檢查。首先檢查是否支持addEventListener方法,如果不支持再檢查是否支持attachEvent方法,如果還不支持,就用DOM 0級(jí)的方法添加事件。在調(diào)用addEvent()過程中,每次這個(gè)過程都要走一遍。其實(shí),瀏覽器支持其中的一種方法就會(huì)一直支持他,就沒有必要再進(jìn)行其他分支的檢測(cè)了,也就是說if語句不必每次都執(zhí)行,代碼可以運(yùn)行的更快一些。解決的方案稱之為惰性載入。 所謂惰性載入,就是說函數(shù)的if分支只會(huì)執(zhí)行一次,之后調(diào)用函數(shù)時(shí),直接進(jìn)入所支持的分支代碼。有兩種實(shí)現(xiàn)惰性載入的方式,第一種事函數(shù)在第一次調(diào)用時(shí),對(duì)函數(shù)本身進(jìn)行二次處理,該函數(shù)會(huì)被覆蓋為符合分支條件的函數(shù),這樣對(duì)原函數(shù)的調(diào)用就不用再經(jīng)過執(zhí)行的分支了,我們可以用下面的方式使用惰性載入重寫addEvent()。
function addEvent (type, element, handler) {
if (element.addEventListener) {
addEvent = function (type, element, handler) {
element.addEventListener(type, handler, false);
}
}
else if(element.attachEvent){
addEvent = function (type, element, handler) {
element.attachEvent('on' + type, handler);
}
}
else{
addEvent = function (type, element, handler) {
element['on' + type] = handler;
}
}
return addEvent(type, element, handler);
}
在這個(gè)惰性載入的addEvent()中,if語句的每個(gè)分支都會(huì)為addEvent變量賦值,有效覆蓋了原函數(shù)。最后一步便是調(diào)用了新賦函數(shù)。下一次調(diào)用addEvent()的時(shí)候,便會(huì)直接調(diào)用新賦值的函數(shù),這樣就不用再執(zhí)行if語句了。
第二種實(shí)現(xiàn)惰性載入的方式是在聲明函數(shù)時(shí)就指定適當(dāng)?shù)暮瘮?shù)。這樣在第一次調(diào)用函數(shù)時(shí)就不會(huì)損失性能了,只在代碼加載時(shí)會(huì)損失一點(diǎn)性能。一下就是按照這一思路重寫的addEvent()。
var addEvent = (function () {
if (document.addEventListener) {
return function (type, element, fun) {
element.addEventListener(type, fun, false);
}
}
else if (document.attachEvent) {
return function (type, element, fun) {
element.attachEvent('on' + type, fun);
}
}
else {
return function (type, element, fun) {
element['on' + type] = fun;
}
}
})();
這個(gè)例子中使用的技巧是創(chuàng)建一個(gè)匿名的自執(zhí)行函數(shù),通過不同的分支以確定應(yīng)該使用那個(gè)函數(shù)實(shí)現(xiàn),實(shí)際的邏輯都一樣,不一樣的地方就是使用了函數(shù)表達(dá)式(使用了var定義函數(shù))和新增了一個(gè)匿名函數(shù),另外每個(gè)分支都返回一個(gè)正確的函數(shù),并立即將其賦值給變量addEvent。
惰性載入函數(shù)的優(yōu)點(diǎn)只執(zhí)行一次if分支,避免了函數(shù)每次執(zhí)行時(shí)候都要執(zhí)行if分支和不必要的代碼,因此提升了代碼性能,至于那種方式更合適,就要看您的需求而定了。
概念:限制一個(gè)函數(shù)在一定時(shí)間內(nèi)只能執(zhí)行一次。
主要實(shí)現(xiàn)思路就是通過 setTimeout 定時(shí)器,通過設(shè)置延時(shí)時(shí)間,在第一次調(diào)用時(shí),創(chuàng)建定時(shí)器,先設(shè)定一個(gè)變量true,寫入需要執(zhí)行的函數(shù)。第二次執(zhí)行這個(gè)函數(shù)時(shí),會(huì)判斷變量是否true,是則返回。當(dāng)?shù)谝淮蔚亩〞r(shí)器執(zhí)行完函數(shù)最后會(huì)設(shè)定變量為false。那么下次判斷變量時(shí)則為false,函數(shù)會(huì)依次運(yùn)行。目的在于在一定的時(shí)間內(nèi),保證多次函數(shù)的請(qǐng)求只執(zhí)行最后一次調(diào)用。
函數(shù)節(jié)流的代碼實(shí)現(xiàn)
function throttle(fn,wait){
var timer = null;
return function(){
var context = this;
var args = arguments;
if(!timer){
timer = setTimeout(function(){
fn.apply(context,args);
timer = null;
},wait)
}
}
}
function handle(){
console.log(Math.random());
}
window.addEventListener("mousemove",throttle(handle,1000));
函數(shù)節(jié)流的應(yīng)用場(chǎng)景(throttle)
DOM 元素的拖拽功能實(shí)現(xiàn)(mousemove)
高頻點(diǎn)擊提交,表單重復(fù)提交
搜索聯(lián)想(keyup)
計(jì)算鼠標(biāo)移動(dòng)的距離(mousemove)
監(jiān)聽滾動(dòng)事件,比如是否滑到底部自動(dòng)加載更多,用throttle來判斷
射擊游戲的 mousedown/keydown 事件(單位時(shí)間只能發(fā)射一顆子彈)
監(jiān)聽滾動(dòng)事件判斷是否到頁面底部自動(dòng)加載更多:給 scroll 加了 debounce 后,只有用戶停止?jié)L動(dòng)后,- - 才會(huì)判斷是否到了頁面底部;如果是 throttle 的話,只要頁面滾動(dòng)就會(huì)間隔一段時(shí)間判斷一次.
概念:函數(shù)防抖(debounce),就是指觸發(fā)事件后,在 n 秒內(nèi)函數(shù)只能執(zhí)行一次,如果觸發(fā)事件后在 n 秒內(nèi)又觸發(fā)了事件,則會(huì)重新計(jì)算函數(shù)延執(zhí)行時(shí)間。
函數(shù)防抖的要點(diǎn),是需要一個(gè) setTimeout 來輔助實(shí)現(xiàn),延遲運(yùn)行需要執(zhí)行的代碼。如果方法多次觸發(fā),則把上次記錄的延遲執(zhí)行代碼用 clearTimeout 清掉,重新開始計(jì)時(shí)。若計(jì)時(shí)期間事件沒有被重新觸發(fā),等延遲時(shí)間計(jì)時(shí)完畢,則執(zhí)行目標(biāo)代碼。
函數(shù)防抖的代碼實(shí)現(xiàn)
function debounce(fn,wait){
var timer = null;
return function(){
if(timer !== null){
clearTimeout(timer);
}
timer = setTimeout(fn,wait);
}
}
function handle(){
console.log(Math.random());
}
window.addEventListener("resize",debounce(handle,1000));
函數(shù)防抖的使用場(chǎng)景函數(shù)防抖一般用在什么情況之下呢?一般用在,連續(xù)的事件只需觸發(fā)一次回調(diào)的場(chǎng)合。具體有:
搜索框搜索輸入。只需用戶最后一次輸入完,再發(fā)送請(qǐng)求;
用戶名、手機(jī)號(hào)、郵箱輸入驗(yàn)證;
瀏覽器窗口大小改變后,只需窗口調(diào)整完后,再執(zhí)行 resize 事件中的代碼,防止重復(fù)渲染。
目前遇到過的用處就是這些,理解了原理與實(shí)現(xiàn)思路,小伙伴可以把它運(yùn)用在任何需要的場(chǎng)合,提高代碼質(zhì)量。
動(dòng)畫原理: 眼前所看到圖像正在以每秒60次的頻率刷新,由于刷新頻率很高,因此你感覺不到它在刷新。而動(dòng)畫本質(zhì)就是要讓人眼看到圖像被刷新而引起變化的視覺效果,這個(gè)變化要以連貫的、平滑的方式進(jìn)行過渡。 那怎么樣才能做到這種效果呢?
刷新頻率為60Hz的屏幕每16.7ms刷新一次,我們?cè)谄聊幻看嗡⑿虑?,將圖像的位置向左移動(dòng)一個(gè)像素,即1px。這樣一來,屏幕每次刷出來的圖像位置都比前一個(gè)要差1px,因此你會(huì)看到圖像在移動(dòng);由于我們?nèi)搜鄣囊曈X停留效應(yīng),當(dāng)前位置的圖像停留在大腦的印象還沒消失,緊接著圖像又被移到了下一個(gè)位置,因此你才會(huì)看到圖像在流暢的移動(dòng),這就是視覺效果上形成的動(dòng)畫。
與setTimeout相比較:
理解了上面的概念以后,我們不難發(fā)現(xiàn),setTimeout 其實(shí)就是通過設(shè)置一個(gè)間隔時(shí)間來不斷的改變圖像的位置,從而達(dá)到動(dòng)畫效果的。但我們會(huì)發(fā)現(xiàn),利用seTimeout實(shí)現(xiàn)的動(dòng)畫在某些低端機(jī)上會(huì)出現(xiàn)卡頓、抖動(dòng)的現(xiàn)象。 這種現(xiàn)象的產(chǎn)生有兩個(gè)原因:
setTimeout的執(zhí)行時(shí)間并不是確定的。在Javascript中, setTimeout 任務(wù)被放進(jìn)了異步隊(duì)列中,只有當(dāng)主線程上的任務(wù)執(zhí)行完以后,才會(huì)去檢查該隊(duì)列里的任務(wù)是否需要開始執(zhí)行,因此 setTimeout 的實(shí)際執(zhí)行時(shí)間一般要比其設(shè)定的時(shí)間晚一些。
刷新頻率受屏幕分辨率和屏幕尺寸的影響,因此不同設(shè)備的屏幕刷新頻率可能會(huì)不同,而 setTimeout只能設(shè)置一個(gè)固定的時(shí)間間隔,這個(gè)時(shí)間不一定和屏幕的刷新時(shí)間相同。
以上兩種情況都會(huì)導(dǎo)致setTimeout的執(zhí)行步調(diào)和屏幕的刷新步調(diào)不一致,從而引起丟幀現(xiàn)象
requestAnimationFrame:與setTimeout相比,requestAnimationFrame最大的優(yōu)勢(shì)是由系統(tǒng)來決定回調(diào)函數(shù)的執(zhí)行時(shí)機(jī)。具體一點(diǎn)講,如果屏幕刷新率是60Hz,那么回調(diào)函數(shù)就每16.7ms被執(zhí)行一次,如果刷新率是75Hz,那么這個(gè)時(shí)間間隔就變成了1000/75=13.3ms,換句話說就是,requestAnimationFrame的步伐跟著系統(tǒng)的刷新步伐走。它能保證回調(diào)函數(shù)在屏幕每一次的刷新間隔中只被執(zhí)行一次,這樣就不會(huì)引起丟幀現(xiàn)象,也不會(huì)導(dǎo)致動(dòng)畫出現(xiàn)卡頓的問題。
除此之外,requestAnimationFrame還有以下兩個(gè)優(yōu)勢(shì):
CPU節(jié)能:使用setTimeout實(shí)現(xiàn)的動(dòng)畫,當(dāng)頁面被隱藏或最小化時(shí),setTimeout 仍然在后臺(tái)執(zhí)行動(dòng)畫任務(wù),由于此時(shí)頁面處于不可見或不可用狀態(tài),刷新動(dòng)畫是沒有意義的,完全是浪費(fèi)CPU資源。而requestAnimationFrame則完全不同,當(dāng)頁面處理未激活的狀態(tài)下,該頁面的屏幕刷新任務(wù)也會(huì)被系統(tǒng)暫停,因此跟著系統(tǒng)步伐走的requestAnimationFrame也會(huì)停止渲染,當(dāng)頁面被激活時(shí),動(dòng)畫就從上次停留的地方繼續(xù)執(zhí)行,有效節(jié)省了CPU開銷。
函數(shù)節(jié)流:在高頻率事件(resize,scroll等)中,為了防止在一個(gè)刷新間隔內(nèi)發(fā)生多次函數(shù)執(zhí)行,使用requestAnimationFrame可保證每個(gè)刷新間隔內(nèi),函數(shù)只被執(zhí)行一次,這樣既能保證流暢性,也能更好的節(jié)省函數(shù)執(zhí)行的開銷。一個(gè)刷新間隔內(nèi)函數(shù)執(zhí)行多次時(shí)沒有意義的,因?yàn)轱@示器每16.7ms刷新一次,多次繪制并不會(huì)在屏幕上體現(xiàn)出來。
白屏?xí)r間: 白屏?xí)r間指的是瀏覽器開始顯示內(nèi)容的時(shí)間。因此我們只需要知道是瀏覽器開始顯示內(nèi)容的時(shí)間點(diǎn),即頁面白屏結(jié)束時(shí)間點(diǎn)即可獲取到頁面的白屏?xí)r間。
計(jì)算白屏?xí)r間 因此,我們通常認(rèn)為瀏覽器開始渲染 標(biāo)簽或者解析完 標(biāo)簽的時(shí)刻就是頁面白屏結(jié)束的時(shí)間點(diǎn)。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>白屏</title>
<script type="text/javascript">
// 不兼容performance.timing 的瀏覽器,如IE8
window.pageStartTime = Date.now();
</script>
<!-- 頁面 CSS 資源 -->
<link rel="stylesheet" href="common.css">
<link rel="stylesheet" href="page.css">
<script type="text/javascript">
// 白屏?xí)r間結(jié)束點(diǎn)
window.firstPaint = Date.now();
</script>
</head>
<body>
<!-- 頁面內(nèi)容 -->
</body>
</html>
因此白屏?xí)r間則可以這樣計(jì)算出:
可使用 Performance API 時(shí)
:
白屏?xí)r間 = firstPaint - performance.timing.navigationStart;
不可使用 Performance API 時(shí)
:
白屏?xí)r間 = firstPaint - pageStartTime; //雖然我們知道這并不準(zhǔn)確,畢竟DNS解析,tcp三次握手等都沒計(jì)算入內(nèi)。
首屏?xí)r間: 首屏?xí)r間是指用戶打開網(wǎng)站開始,到瀏覽器首屏內(nèi)容渲染完成的時(shí)間。對(duì)于用戶體驗(yàn)來說,首屏?xí)r間是用戶對(duì)一個(gè)網(wǎng)站的重要體驗(yàn)因素。通常一個(gè)網(wǎng)站,如果首屏?xí)r間在5秒以內(nèi)是比較優(yōu)秀的,10秒以內(nèi)是可以接受的,10秒以上就不可容忍了。超過10秒的首屏?xí)r間用戶會(huì)選擇刷新頁面或立刻離開。
通常計(jì)算首屏的方法有
首屏模塊標(biāo)簽標(biāo)記法
統(tǒng)計(jì)首屏內(nèi)加載最慢的圖片的時(shí)間
自定義首屏內(nèi)容計(jì)算法
1、首屏模塊標(biāo)簽標(biāo)記法
首屏模塊標(biāo)簽標(biāo)記法,通常適用于首屏內(nèi)容不需要通過拉取數(shù)據(jù)才能生存以及頁面不考慮圖片等資源加載的情況。我們會(huì)在 HTML 文檔中對(duì)應(yīng)首屏內(nèi)容的標(biāo)簽結(jié)束位置,使用內(nèi)聯(lián)的 JavaScript 代碼記錄當(dāng)前時(shí)間戳。如下所示:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>首屏</title>
<script type="text/javascript">
window.pageStartTime = Date.now();
</script>
<link rel="stylesheet" href="common.css">
<link rel="stylesheet" href="page.css">
</head>
<body>
<!-- 首屏可見模塊1 -->
<div></div>
<!-- 首屏可見模塊2 -->
<div></div>
<script type="text/javascript">
window.firstScreen = Date.now();
</script>
<!-- 首屏不可見模塊3 -->
<div></div>
<!-- 首屏不可見模塊4 -->
<div></div>
</body>
</html>
此時(shí)首屏?xí)r間等于 firstScreen - performance.timing.navigationStart;
事實(shí)上首屏模塊標(biāo)簽標(biāo)記法 在業(yè)務(wù)中的情況比較少,大多數(shù)頁面都需要通過接口拉取數(shù)據(jù)才能完整展示,因此我們會(huì)使用 JavaScript 腳本來判斷首屏頁面內(nèi)容加載情況。
2、統(tǒng)計(jì)首屏內(nèi)圖片完成加載的時(shí)間
通常我們首屏內(nèi)容加載最慢的就是圖片資源,因此我們會(huì)把首屏內(nèi)加載最慢的圖片的時(shí)間當(dāng)做首屏的時(shí)間。
由于瀏覽器對(duì)每個(gè)頁面的 TCP 連接數(shù)有限制,使得并不是所有圖片都能立刻開始下載和顯示。因此我們?cè)?DOM樹 構(gòu)建完成后將會(huì)去遍歷首屏內(nèi)的所有圖片標(biāo)簽,并且監(jiān)聽所有圖片標(biāo)簽 onload 事件,最終遍歷圖片標(biāo)簽的加載時(shí)間的最大值,并用這個(gè)最大值減去 navigationStart 即可獲得近似的首屏?xí)r間。
此時(shí)首屏?xí)r間等于 加載最慢的圖片的時(shí)間點(diǎn) - performance.timing.navigationStart; //首屏?xí)r間嘗試: //1,獲取首屏基線高度 //2,計(jì)算出基線dom元素之上的所有圖片元素 //3,所有圖片onload之后為首屏顯示時(shí)間 //
function getOffsetTop(ele) {
var offsetTop = ele.offsetTop;
if (ele.offsetParent !== null) {
offsetTop += getOffsetTop(ele.offsetParent);
}
return offsetTop;
}
var firstScreenHeight = win.screen.height;
var firstScreenImgs = [];
var isFindLastImg = false;
var allImgLoaded = false;
var t = setInterval(function() {
var i, img;
if (isFindLastImg) {
if (firstScreenImgs.length) {
for (i = 0; i < firstScreenImgs.length; i++) {
img = firstScreenImgs[i];
if (!img.complete) {
allImgLoaded = false;
break;
} else {
allImgLoaded = true;
}
}
} else {
allImgLoaded = true;
}
if (allImgLoaded) {
collect.add({
firstScreenLoaded: startTime - Date.now()
});
clearInterval(t);
}
} else {
var imgs = body.querySelector('img');
for (i = 0; i<imgs.length; i++) {
img = imgs[i];
var imgOffsetTop = getOffsetTop(img);
if (imgOffsetTop > firstScreenHeight) {
isFindLastImg = true;
break;
} else if (imgOffsetTop <= firstScreenHeight && !img.hasPushed) {
img.hasPushed = 1;
firstScreenImgs.push(img);
}
}
}
}, 0);
doc.addEventListener('DOMContentLoaded', function() {
var imgs = body.querySelector('img');
if (!imgs.length) {
isFindLastImg = true;
}
});
win.addEventListener('load', function() {
allImgLoaded = true;
isFindLastImg = true;
if (t) {
clearInterval(t);
}
collect.log(collect.global);
});
解釋一下思路,大概就是判斷首屏有沒有圖片,如果沒圖片就用domready時(shí)間,如果有圖,分2種情況,圖在首屏,圖不在首屏,如果在則收集,并判斷加載狀態(tài),加載完畢之后則首屏完成加載,如果首屏沒圖,找到首屏下面的圖,立刻觸發(fā)首屏完畢。可以想象這么做前端收集是不準(zhǔn)的,但是可以確保最晚不會(huì)超過win load,所以應(yīng)該還算有些意義。。沒辦法,移動(dòng)端很多瀏覽器不支持performance api,所以土辦法前端收集,想出這么個(gè)黑魔法,在基線插入節(jié)點(diǎn)收集也是個(gè)辦法,但是不友好,而且現(xiàn)在手機(jī)屏幕這么多。。
3、自定義模塊內(nèi)容計(jì)算法
由于統(tǒng)計(jì)首屏內(nèi)圖片完成加載的時(shí)間比較復(fù)雜。因此我們?cè)跇I(yè)務(wù)中通常會(huì)通過自定義模塊內(nèi)容,來簡(jiǎn)化計(jì)算首屏?xí)r間。如下面的做法:
忽略圖片等資源加載情況,只考慮頁面主要 DOM
只考慮首屏的主要模塊,而不是嚴(yán)格意義首屏線以上的所有內(nèi)容
實(shí)際上用performance.timing來計(jì)算首屏加載時(shí)間與白屏?xí)r間非常簡(jiǎn)單與精確。不過目前只支持IE10和chrome貼下其API的使用
var navigationStart = performance.timing.navigationStart;
//1488984540668
console.log(navigationStart);
//Wed Mar 08 2017 22:49:44 GMT+0800 (中國(guó)標(biāo)準(zhǔn)時(shí)間)
console.log(new Date(new Date(navigationStart)));
復(fù)制代碼
redirectStart:到當(dāng)前頁面的重定向開始的時(shí)間。但只有在重定向的頁面來自同一個(gè)域時(shí)這個(gè)屬性才會(huì)有值;否則,值為0
redirectEnd:到當(dāng)前頁面的重定向結(jié)束的時(shí)間。但只有在重定向的頁面來自同一個(gè)域時(shí)這個(gè)屬性才會(huì)有值;否則,值為0
console.log(performance.timing.redirectStart);//0
console.log(performance.timing.redirectEnd);//0
fetchStart:開始通過HTTP GET取得頁面的時(shí)間
console.log(performance.timing.fetchStart);//1488984540668
domainLookupStart:開始査詢當(dāng)前頁面DNS的時(shí)間,如果使用了本地緩存或持久連接,則與fetchStart值相等
domainLookupEnd:査詢當(dāng)前頁面DNS結(jié)束的時(shí)間,如果使用了本地緩存或持久連接,則與fetchStart值相等
console.log(performance.timing.domainLookupStart);//1488984540670
console.log(performance.timing.domainLookupEnd);//1488984540671
connectStart:瀏覽器嘗試連接服務(wù)器的時(shí)間
secureConnectionStart:瀏覽器嘗試以SSL方式連接服務(wù)器的時(shí)間。不使用SSL方式連接時(shí),這個(gè)屬性的值為0
connectEnd:瀏覽器成功連接到服務(wù)器的時(shí)間
console.log(performance.timing.connectStart);//1488984540671
console.log(performance.timing.secureConnectionStart);//0
console.log(performance.timing.connectEnd);//1488984540719
requestStart:瀏覽器開始請(qǐng)求頁面的時(shí)間
responseStart:瀏覽器接收到頁面第一字節(jié)的時(shí)間
responseEnd:瀏覽器接收到頁面所有內(nèi)容的時(shí)間
console.log(performance.timing.requestStart);//1488984540720
console.log(performance.timing.responseStart);//1488984540901
console.log(performance.timing.responseEnd);//1488984540902
unloadEventStart:前一個(gè)頁面的unload事件開始的時(shí)間。但只有在前一個(gè)頁面與當(dāng)前頁面來自同一個(gè)域時(shí)這個(gè)屬性才會(huì)有值;否則,值為0
unloadEventEnd:前一個(gè)頁面的unload事件結(jié)束的時(shí)間。但只有在前一個(gè)頁面與當(dāng)前頁面來自同一個(gè)域時(shí)這個(gè)屬性才會(huì)有值;否則,值為0
console.log(performance.timing.unloadEventStart);//1488984540902
console.log(performance.timing.unloadEventEnd);//1488984540903
domLoading:document.readyState變?yōu)?quot;loading"的時(shí)間,即開始解析DOM樹的時(shí)間
domInteractive:document.readyState變?yōu)?quot;interactive"的時(shí)間,即完成完成解析DOM樹的時(shí)間
domContentLoadedEventStart:發(fā)生DOMContentloaded事件的時(shí)間,即開始加載網(wǎng)頁內(nèi)資源的時(shí)間
domContentLoadedEventEnd:DOMContentLoaded事件已經(jīng)發(fā)生且執(zhí)行完所有事件處理程序的時(shí)間,網(wǎng)頁內(nèi)資源加載完成的時(shí)間
domComplete:document.readyState變?yōu)?quot;complete"的時(shí)間,即DOM樹解析完成、網(wǎng)頁內(nèi)資源準(zhǔn)備就緒的時(shí)間
console.log(performance.timing.domLoading);//1488984540905
console.log(performance.timing.domInteractive);//1488984540932
console.log(performance.timing.domContentLoadedEventStart);//1488984540932
console.log(performance.timing.domContentLoadedEventEnd);//1488984540932
console.log(performance.timing.domComplete);//1488984540932
loadEventStart:發(fā)生load事件的時(shí)間,也就是load回調(diào)函數(shù)開始執(zhí)行的時(shí)間
loadEventEnd:load事件已經(jīng)發(fā)生且執(zhí)行完所有事件處理程序的時(shí)間
console.log(performance.timing.loadEventStart);//1488984540933
console.log(performance.timing.loadEventEnd);//1488984540933
多線程技術(shù)在服務(wù)端技術(shù)中已經(jīng)發(fā)展的很成熟了,而在Web端的應(yīng)用中卻一直是雞肋 在新的標(biāo)準(zhǔn)中,提供的新的WebWork API,讓前端的異步工作變得異常簡(jiǎn)單。 使用:創(chuàng)建一個(gè)Worker對(duì)象,指向一個(gè)js文件,然后通過Worker對(duì)象往js文件發(fā)送消息,js文件內(nèi)部的處理邏輯,處理完畢后,再發(fā)送消息回到當(dāng)前頁面,純異步方式,不影響當(dāng)前主頁面渲染。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
<script type="text/javascript">
//創(chuàng)建線程 work對(duì)象
var work = new Worker("work.js"); //work文件中不要存在跟ui代碼
//發(fā)送消息
work.postMessage("100");
// 監(jiān)聽消息
work.onmessage = function(event) {
alert(event.data);
};
</script>
</head>
<body>
</body>
</html>
onmessage = function (event) {
//從1加到num
var num = event.data;
var result = 0;
for (var i = 1; i <= num; i++) {
result += i;
}
postMessage(result);
}
感謝各位的閱讀,以上就是“web前端面試問答題有哪些”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)web前端面試問答題有哪些這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
文章名稱:web前端面試問答題有哪些
鏈接地址:http://www.rwnh.cn/article2/jsceoc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制網(wǎng)站、網(wǎng)頁設(shè)計(jì)公司、網(wǎng)站內(nèi)鏈、網(wǎng)站維護(hù)、網(wǎng)站策劃、網(wǎng)站改版
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)