JS常見問題

Q: JS有幾種數據類型,其中基本數據類型有哪些!

7種!javascript

  • Boolean
  • Number
  • String
  • Null
  • Undefined
  • Object
  • Symbol (ECMAScript 6 新定義)

其中,除了Object是引用類型外,都是基本類型css

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------html

Q: null 和 undefined的區別

null是一個空指針,是一個特殊的object,會被前端

undefined是指一個被調用但未被賦值的變量html5

他們在if條件下都爲falsejava

null 轉爲數字是0,而undefined轉爲數字是NaNwebpack

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ios

Q:垃圾收集

一、標記清除nginx

二、引用計數git

對於性能問題:若是在運行期間,分配的內存不少,那麼垃圾收集的工做量也會至關大,所以,每一次垃圾收集的時間間隔如何肯定是一個很重要的問題。

從IE7開始,js改變了垃圾收集的工做方式:觸發垃圾收集的變量分配。相似於TCP擁塞窗口的控制。。。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Q: 給一個DOM添加捕獲和冒泡的兩種寫法的事件點擊,誰先執行?(如何阻止冒泡)

先捕獲,再冒泡

如上圖所示,你點擊了一個div裏的text,會先從window捕獲,直到text,而後從text冒泡,一直到冒泡到window

那麼什麼是捕獲,什麼是冒泡?

好比:

element.addEventListener('click', function(e){
console.log(e.target)
}, true|false);

其中,咱們經常使用的false就是冒泡,true就是捕獲。

return不只阻止事件冒泡,也阻止事件自己,stopPropagation()只阻止事件冒泡

 

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Q:相等運算符和嚴格相等運算符

1. 嚴格相等運算符‘===’

  • 先比較兩個值的類型,如不一樣,直接返回false
  • 同一類型的原始類型的值(Number、string、boolean),若是相同就返回true,不然返回false
  • 如果引用類型(好比,對象、數組),比較雙方所指向的地址是否相等 
{} === {} // false
[] === [] // false
(function () {} === function () {}) // false
上面代碼分別比較兩個空對象、兩個空數組、兩個空函數,結果都是不相等。
緣由是對於複合類型的值,嚴格相等運算比較的是,它們是否引用同一個內存地址,而運算符兩邊的空對象、空數組、空函數的值,都存放在不一樣的內存地址,結果固然是。
false

注意:NaN與任何值都不相等,包括自身。

NaN === NaN  // false

2.嚴格不相等運算符

a !== b 等價於
!(a === b)

3.相等運算符

  • 若兩個值類型相同,等價於嚴格相等
  • 若類型不一樣,對於原始類型值之間的比較會先轉換爲數值類型
1 == true // true
// 等同於 1 === Number(true)

0 == false // true
// 等同於 0 === Number(false)

2 == true // false
// 等同於 2 === Number(true)

2 == false // false
// 等同於 2 === Number(false)

'true' == true // false
// 等同於 Number('true') === Number(true)
// 等同於 NaN === 1

'' == 0 // true
// 等同於 Number('') === 0
// 等同於 0 === 0

'' == false  // true
// 等同於 Number('') === Number(false)
// 等同於 0 === 0

'1' == true  // true
// 等同於 Number('1') === Number(true)
// 等同於 1 === 1

'\n  123  \t' == 123 // true
// 由於字符串轉爲數字時,省略前置和後置的空格
  • 若類型不一樣,對於原始類型和引用類型之間,會把引用類型轉換爲原始類型
// 對象與數值比較時,對象轉爲數值
[1] == 1 // true
// 等同於 Number([1]) == 1

// 對象與字符串比較時,對象轉爲字符串
[1] == '1' // true
// 等同於 String([1]) == '1'
[1, 2] == '1,2' // true
// 等同於 String([1, 2]) == '1,2'

// 對象與布爾值比較時,兩邊都轉爲數值
[1] == true // true
// 等同於 Number([1]) == Number(true)
[2] == true // false
// 等同於 Number([2]) == Number(true)

 

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Q: 談談你對ajax 的理解,以及用原生 JS 實現有哪些要點須要注意;

ajax全稱是異步 javascript 和 XML,用來和服務端進行數據交互的,讓無刷新替換頁面數據成了可能。

https://www.html5rocks.com/zh/tutorials/file/xhr2/#toc-examples

https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest

這個東西,細節不少,短期內想要基本熟悉很難。

let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
    if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
        console.log(xhr.responseText);
    }
}
xhr.open();
xhr.send();

 

 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Q: JS 實現一個閉包函數,每次調用都自增1

let add = (function () {
    let i = 0;
    return function () {
        return ++i;
    }
})()

能夠這樣理解這個閉包,add函數return的是一個匿名函數,所以,訪問不到函數內的全局變量i,所以i被隱藏起來了。

 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Q: JS 實現函數運行一秒後打印輸出0-9

for(var i=0;i<10;i++) {
            setTimeout((function (x) {
                return function () {
                    console.log(x)
                }
            })(i), 1000)
        }

  -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Q:函數聲明和函數表達式

其中,function meili () {}是函數聲明,會有函數聲明提高,全局可用。

function mogu () {}是函數表達式,必須先聲明,後使用。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

加法運算 +號會優先嚐試字符鏈接;
減法運算 會嘗試轉化成數值型進行計算
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

宏任務:script(總體代碼), setTimeout, setInterval, setImmediate的回調是宏任務, I/O, UI rendering。
微任務:Promises的回調是微任務(promise自己的函數是馬上執行), Object.observe, MutationObserver
代碼執行順序是先宏任務,再微任務,若是還有則須要開始新一輪循環宏任務、微任務。
 
因此原代碼執行順序是:
1.宏任務 script,先彈出D,new建立promise對象時的EF,而後彈出H
2.微任務 promise,Promise對象執行完resolve()後.then的G
3.宏任務 setTimeout的C
即DEFHGC
 
2019/4/25補充:
1.準確的說是先執行宏任務,若是有回調就丟到宏任務隊列。
2.再執行微任務,若是有回調就丟到微任務隊列。
3.檢查微任務隊列,非空就執行。
4.檢查宏任務隊列,非空就執行。
5.渲染dom。
6.再來一次。
例題:

1  -  2 - 3 - be - also - 4 - test。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 Q:js中的this的理解

https://blog.csdn.net/cjgeng88/article/details/79846670

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Q: 怎麼解決跨域問題,有哪些方法

我通常用這三種,cors,nginx反向代理,jsonp

  • jsonp : 單純的 get 一些數據,侷限性很大...就是利用script標籤的src屬性來實現跨域。
  • nginx 反向代理: 主要就是用了nginx.conf內的proxy_pass http://xxx.xxx.xxx,會把全部請求代理到那個域名,有利也有弊吧..
  • cors的話,可控性較強,須要先後端都設置,兼容性 IE10+

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

CSRF工具的防護手段

1. 儘可能使用POST,限制GET

GET接口太容易被拿來作CSRF攻擊,看第一個示例就知道,只要構造一個img標籤,而img標籤又是不能過濾的數據。接口最好限制爲POST使用,GET則無效,下降攻擊風險。

固然POST並非萬無一失,攻擊者只要構造一個form就能夠,但須要在第三方頁面作,這樣就增長暴露的可能性。

2. 瀏覽器Cookie策略

IE六、七、八、Safari會默認攔截第三方本地Cookie(Third-party Cookie)的發送。可是Firefox二、三、Opera、Chrome、Android等不會攔截,因此經過瀏覽器Cookie策略來防護CSRF攻擊不靠譜,只能說是下降了風險。

PS:Cookie分爲兩種,Session Cookie(在瀏覽器關閉後,就會失效,保存到內存裏),Third-party Cookie(即只有到了Exprie時間後纔會失效的Cookie,這種Cookie會保存到本地)。

PS:另外若是網站返回HTTP頭包含P3P Header,那麼將容許瀏覽器發送第三方Cookie。

3. 加驗證碼

驗證碼,強制用戶必須與應用進行交互,才能完成最終請求。在一般狀況下,驗證碼能很好遏制CSRF攻擊。可是出於用戶體驗考慮,網站不能給全部的操做都加上驗證碼。所以驗證碼只能做爲一種輔助手段,不能做爲主要解決方案。

4. Referer Check

Referer Check在Web最多見的應用就是「防止圖片盜鏈」。同理,Referer Check也能夠被用於檢查請求是否來自合法的「源」(Referer值是不是指定頁面,或者網站的域),若是都不是,那麼就很可能是CSRF攻擊。

可是由於服務器並非何時都能取到Referer,因此也沒法做爲CSRF防護的主要手段。可是用Referer Check來監控CSRF攻擊的發生,卻是一種可行的方法。

5. Anti CSRF Token

如今業界對CSRF的防護,一致的作法是使用一個Token(Anti CSRF Token)。

例子:

1. 用戶訪問某個表單頁面。

2. 服務端生成一個Token,放在用戶的Session中,或者瀏覽器的Cookie中。

3. 在頁面表單附帶上Token參數。

4. 用戶提交請求後, 服務端驗證表單中的Token是否與用戶Session(或Cookies)中的Token一致,一致爲合法請求,不是則非法請求。

這個Token的值必須是隨機的,不可預測的。因爲Token的存在,攻擊者沒法再構造一個帶有合法Token的請求實施CSRF攻擊。另外使用Token時應注意Token的保密性,儘可能把敏感操做由GET改成POST,以form或AJAX形式提交,避免Token泄露。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Q: 描述下cookie,sessionStorage,localStorage的差別..

  • cookie : 大小4KB 左右,跟隨請求(請求頭),會佔用帶寬資源,可是如果用來判斷用戶是否在線這些挺方便
  • sessionStoragelocalStorage大同小異,大小看瀏覽器支持,通常爲5MB,數據只保留在本地,不參與服務端交互.
    • sessionStorage的生存週期只限於會話中,關閉了儲存的數據就沒了.
    • localStorage則保留在本地,沒有人爲清除會一直保留

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Q:promise

https://www.cnblogs.com/lvdabao/p/es6-promise-1.html

let p = new Promise(function(resolve, reject) {
    setTimeout(function () {
        console.log('執行完成');
        resolve('hello');
    }, 2000);
});

我new了一個Promise對象,先無論這裏面的每句話是什麼意思,這裏注意,在new的同時,裏面的函數已經被執行了,所以咱們能夠利用函數,讓Promise延遲執行。

function dosomethingAsync () {
    let p = new Promise(function(resolve, reject) {
        setTimeout(function () {
            console.log('執行完成');
            resolve('hello');
        }, 2000);
    });
    return p;
}

dosomethingAsync();

這裏說一個概念,promise的狀態,promise的狀態分爲三種,pending(等待),fulfilled(成功),rejected(失敗)。一個promise只能從pending到另外兩種狀態之一轉變,且這種轉變是單向的,一次性的。也就是說,只能轉變一次,且不可更改結果。

那麼要怎麼轉變呢?就經過resolve(),和reject()。

好比咱們定義,咱們從數據庫取年齡爲100歲的人的信息,若是取到了,就是成功,若是沒取到就是失敗,咱們寫一下僞代碼

 1 function getSomeoneInfo () {
 2     let p = new Promise(function (resolve, reject) {
 3         axios.get('http://獲取年齡的api/&age=100', function (response) {
 4             // 接收響應的回調函數
 5             if (response.data 不爲空) {
 6                 // 成功了
 7                 resolve(response.data);
 8             } else {
 9                 //  失敗了
10                 reject('error');
11             }
12         })
13     })
14     return p;
15 }
16 
17 getSomeoneInfo ();

能夠看到,Promise在尚未執行的時候狀態爲pending,在經過resolve和reject函數後分別轉爲兩種對應的狀態。

那麼知道狀態改變了之後,要怎麼作呢?經過then

function getSomeoneInfo () {
    let p = new Promise(function (resolve, reject) {
        axios.get('http://獲取年齡的api/&age=100', function (response) {
            // 接收響應的回調函數
            if (response.data 不爲空) {
                // 成功了
                resolve(response.data);
            } else {
                //  失敗了
                reject('error');
            }
        })
    })
    return p;
}

getSomeoneInfo().then(function (data) {
    console.log(data);
}, function (data) {
    console.log(data);
});

能夠看到then函數的參數是兩個匿名函數,能夠這麼理解,用then來監聽promise的狀態變化,若是轉向成功,就執行第一個函數,且參數data 和 response.data一致,不然轉向第二個函數,data等於'error'。

promise.all()


同時執行多個異步函數,所有都執行完了,進到then裏

Promise
.all([runAsync1(), runAsync2(), runAsync3()])
.then(function(results){
    console.log(results);
});

result是三個函數執行結果組成的數組。

promise.race()

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Q:async / await

https://segmentfault.com/a/1190000013292562?utm_source=channel-newest

放在一個函數前的async有兩個做用:

  1. 使函數老是返回一個promise
  2. 許在這其中使用await

promise前面的await關鍵字可以使JavaScript等待,直到promise處理結束。而後:
若是它是一個錯誤,異常就產生了,就像在那個地方調用了throw error同樣。

  1. 不然,它會返回一個結果,咱們能夠將它分配給一個值
  2. 他們一塊兒提供了一個很好的框架來編寫易於讀寫的異步代碼。

有了async/await,咱們不多須要寫promise.then/catch,可是咱們仍然不該該忘記它們是基於promise的,由於有些時候(例如在最外面的範圍內)咱們不得不使用這些方法。Promise.all也是一個很是棒的東西,它可以同時等待不少任務。

舉例


一個獲取頭像的需求,若是用promise只能以鏈式這麼寫,若是不以promise寫,甚至會形成回調地獄

loadJson('/article/promise-chaining/user.json')
  .then(user => loadGithubUser(user.name))
  .then(showAvatar)
  .then(githubUser => alert(`Finished showing ${githubUser.name}`));

若是用async / await

async function showAvatar() {
    // read our JSON
    let response = await fetch('/article/promise-chaining/user.json')
    let user = await response.json()
    
    // read github user
    let githubResponse = await fetch(`https://api.github.com/users/${user.name}`)
    let githubUser = await githubResponse.json()
    
    // 展現頭像
    let img = document.createElement('img')
    img.src = githubUser.avatar_url
    img.className = 'promise-avatar-example'
    documenmt.body.append(img)
    
    // 等待3s
    await new Promise((resolve, reject) => {
        setTimeout(resolve, 3000)
    })
    
    img.remove()
    
    return githubUser
}
showAvatar()

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

11. js的new操做符作了哪些事情

new 操做符新建了一個空對象,這個對象原型指向構造函數的prototype,執行構造函數後返回這個對象。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

13. js的各類位置,好比clientHeight,scrollHeight,offsetHeight ,以及scrollTop, offsetTop,clientTop的區別?

  • clientHeight:表示的是可視區域的高度,不包含border和滾動條

  • offsetHeight:表示可視區域的高度,包含了border和滾動條

  • scrollHeight:表示了全部區域的高度,包含了由於滾動被隱藏的部分。

  • clientTop:表示邊框border的厚度,在未指定的狀況下通常爲0

  • scrollTop:滾動後被隱藏的高度,獲取對象相對於由offsetParent屬性指定的父座標(css定位的元素或body元素)距離頂端的高度。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

17. js的節流和防抖

http://www.cnblogs.com/coco1s/p/5499469.html

針對高頻度觸發的事件(例如頁面 scroll ,屏幕 resize,監聽用戶輸入等)應該減小操做,下面介紹兩種經常使用的解決方法,防抖和節流。

函數節流是指必定時間內js方法只跑一次。好比人的眨眼睛,就是必定時間內眨一次。這是函數節流最形象的解釋。
函數防抖是指頻繁觸發的狀況下,只在最終中止的時候,才執行代碼一次。好比生活中的坐公交,就是必定時間內,若是有人陸續刷卡上車,司機就不會開車。只有別人沒刷卡了,司機纔開車。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

20.如何理解前端模塊化

前端模塊化就是複雜的文件編程一個一個獨立的模塊,好比js文件等等,分紅獨立的模塊有利於重用(複用性)和維護(版本迭代),這樣會引來模塊之間相互依賴的問題,因此有了commonJS規範,AMD,CMD規範等等,以及用於js打包(編譯等處理)的工具webpack。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

21.Commonjs、 AMD和CMD

一個模塊是能實現特定功能的文件,有了模塊就能夠方便的使用別人的代碼,想要什麼功能就能加載什麼模塊。

  • Commonjs:開始於服務器端的模塊化,同步定義的模塊化,每一個模塊都是一個單獨的做用域,模塊輸出,modules.exports,模塊加載require()引入模塊。
  • AMD:中文名異步模塊定義的意思。

requireJS實現了AMD規範,主要用於解決下述兩個問題。

1.多個文件有依賴關係,被依賴的文件須要早於依賴它的文件加載到瀏覽器

2.加載的時候瀏覽器會中止頁面渲染,加載文件越多,頁面失去響應的時間越長。

語法:requireJS定義了一個函數define,它是全局變量,用來定義模塊。

requireJS的例子:

//定義模塊
define(['dependency'], function(){
        var name = 'Byron';
        function printName(){
            console.log(name);
        }
        return {
            printName: printName
        };
   });
//加載模塊
require(['myModule'], function (my){
 my.printName();
}

requirejs定義了一個函數define,它是全局變量,用來定義模塊:

define(id?dependencies?,factory)

在頁面上使用模塊加載函數:

require([dependencies],factory);

總結AMD規範:require()函數在加載依賴函數的時候是異步加載的,這樣瀏覽器不會失去響應,它指定的回調函數,只有前面的模塊加載成功,纔會去執行。
由於網頁在加載js的時候會中止渲染,所以咱們能夠經過異步的方式去加載js,而若是須要依賴某些,也是異步去依賴,依賴後再執行某些方法。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

22.對象深度克隆的簡單實現

function deepClone(obj){
  var newObj= obj instanceof Array ? []:{};
  for(var item in obj){
    var temple= typeof obj[item] == 'object' ? deepClone(obj[item]):obj[item];
    newObj[item] = temple;
  }
  return newObj;
}

ES5的經常使用的對象克隆的一種方式。注意數組是對象,可是跟對象又有必定區別,因此咱們一開始判斷了一些類型,決定newObj是對象仍是數組~

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

24.將原生的ajax封裝成promise

var  myNewAjax=function(url){
  return new Promise(function(resolve,reject){
      var xhr = new XMLHttpRequest();
      xhr.open('get',url);
      xhr.send(data);
      xhr.onreadystatechange=function(){
           if(xhr.status==200&&readyState==4){
                var json=JSON.parse(xhr.responseText);
                resolve(json)
           }else if(xhr.readyState==4&&xhr.status!=200){
                reject('error');
           }
      }
  })
}

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

補:defineProperty

http://www.javashuo.com/article/p-qasukviu-dp.html

value:對應的值,默認爲undefined。

writable:是否能夠被重寫。默認爲false。用內部方法也不可被修改

enumeable:此屬性是否能夠被枚舉到(注意這個說法,「被枚舉到」,當你用for in或object.keys()的時候能不能被枚舉出來)。設置爲true能夠被枚舉;設置爲false,不能被枚舉。默認爲false。

configurable:是否能夠刪除目標屬性或是否能夠再次修改屬性的特性(writable, configurable, enumerable)。設置爲true能夠被刪除或能夠從新設置特性;設置爲false,不能被能夠被刪除或不能夠從新設置特性。默認爲false。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

25.js監聽對象屬性的改變

咱們假設這裏有一個user對象,

(1)在ES5中能夠經過Object.defineProperty來實現已有屬性的監聽

Object.defineProperty(user,'name',{
    set:function(key,value){
       
    }
})

缺點:若是id不在user對象中,則不能監聽id的變化

(2)在ES6中能夠經過Proxy來實現

var  user = new Proxy({},{
 set:function(target,key,value,receiver){

  }
})

這樣即便有屬性在user中不存在,經過user.id來定義也一樣能夠這樣監聽這個屬性的變化哦~

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

26.如何實現一個私有變量,用getName方法能夠訪問,不能直接訪

(1)經過defineProperty來實現(這個我測了,是不行的!!!反而能夠用上面的proxy實現)

obj={
  name:yuxiaoliang,
  getName:function(){
    return this.name
  }
}
object.defineProperty(obj,"name",{
   //不可枚舉不可配置
});

(2)經過函數的建立形式 

function product(){
    var name='yuxiaoliang';
    this.getName=function(){
      return name;
    }
}
var obj=new product();

27. ==和===、以及Object.is的區別

  1. ==:等同,比較運算符,兩邊值類型不一樣的時候,先進行類型轉換,再比較;
  2. ===:恆等,嚴格比較運算符,不作類型轉換,類型不一樣就是不等;
  3. Object.is()ES6新增的用來比較兩個值是否嚴格相等的方法,與===的行爲基本一致。
    1. 先說= = =,這個比較簡單,只須要利用下面的規則來判斷兩個值是否恆等就好了:

      1. 若是類型不一樣,就不相等
      2. 若是兩個都是數值,而且是同一個值,那麼相等; 
        1. 值得注意的是,若是兩個值中至少一個是NaN,那麼不相等(判斷一個值是不是NaN,能夠用isNaN()Object.is()來判斷)。
      3. 若是兩個都是字符串,每一個位置的字符都同樣,那麼相等;不然不相等
      4. 若是兩個值都是一樣的Boolean值,那麼相等
      5. 若是兩個值都引用同一個對象或函數,那麼相等,即兩個對象的物理地址也必須保持一致;不然不相等
      6. 若是兩個值都是null,或者都是undefined,那麼相等

再說Object.is(),其行爲與===基本一致,不過有兩處不一樣:

  1. +0不等於-0
  2. NaN等於自身。

舉個栗子☺:

+0 === -0 //true
NaN === NaN // false

Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
 

28.setTimeout、setInterval和requestAnimationFrame之間的區別

這裏有一篇文章講的是requestAnimationFrame:http://www.cnblogs.com/xiaohuochai/p/5777186.html
與setTimeout和setInterval不一樣,requestAnimationFrame不須要設置時間間隔,
大多數電腦顯示器的刷新頻率是60Hz,大概至關於每秒鐘重繪60次。大多數瀏覽器都會對重繪操做加以限制,不超過顯示器的重繪頻率,由於即便超過那個頻率用戶體驗也不會有提高。所以,最平滑動畫的最佳循環間隔是1000ms/60,約等於16.6ms。

RAF採用的是系統時間間隔,不會由於前面的任務,不會影響RAF,可是若是前面的任務多的話,
會響應setTimeout和setInterval真正運行時的時間間隔。

特色:
(1)requestAnimationFrame會把每一幀中的全部DOM操做集中起來,在一次重繪或迴流中就完成,而且重繪或迴流的時間間隔牢牢跟隨瀏覽器的刷新頻率。

(2)在隱藏或不可見的元素中,requestAnimationFrame將不會進行重繪或迴流,這固然就意味着更少的CPU、GPU和內存使用量

(3)requestAnimationFrame是由瀏覽器專門爲動畫提供的API,在運行時瀏覽器會自動優化方法的調用,而且若是頁面不是激活狀態下的話,動畫會自動暫停,有效節省了CPU開銷。

相關文章
相關標籤/搜索