對(duì)于 jQuery 的動(dòng)畫的設(shè)計(jì)我們要分 2 個(gè)層面理解:
- 每一個(gè)動(dòng)畫效果可以看作一個(gè)獨(dú)立的動(dòng)畫對(duì)象,每個(gè)對(duì)象都實(shí)現(xiàn)了針對(duì)自己這個(gè)動(dòng)畫的生命周期的控制
- 動(dòng)畫對(duì)象與動(dòng)畫對(duì)象之間其實(shí)是沒有直接關(guān)系,但是為了做到連續(xù)調(diào)用就需要引入一套隊(duì)列機(jī)制也就是 Queue 來(lái)控制對(duì)象之間的轉(zhuǎn)換的控制
動(dòng)畫的源碼:
animate: function(prop, speed, easing, callback) {
doAnimation = function() {
var anim = Animation(this, args, optall);
};
this.queue(optall.queue, doAnimation);
}
這個(gè)代碼縮減了,但是我們上面提到的最重要的 2 點(diǎn)這里都涉及到了:通過 queue 調(diào)度動(dòng)畫的之間的銜接,Animation 方法執(zhí)行單個(gè)動(dòng)畫的封裝。
jQuery 在 queue 的調(diào)度上涉及了一個(gè)關(guān)鍵的處理:同步與異步代碼同時(shí)執(zhí)行,同步收集動(dòng)畫序列,異步調(diào)用序列,看看整個(gè)調(diào)用的流程是這樣的:
- 通過多個(gè) animate 方法形成動(dòng)畫鏈,那么這個(gè)動(dòng)畫鏈其實(shí)都是會(huì)加入到 queue 隊(duì)列里面
- 在每一次 queue 方法中會(huì)把動(dòng)畫數(shù)據(jù)寫到隊(duì)列中,然后取出隊(duì)列中的第一個(gè)序列通過 dequeue 方法執(zhí)行
- 開始執(zhí)行之前寫一個(gè)進(jìn)程鎖“inprogress”到 queue 里面,代表這個(gè)動(dòng)畫還在執(zhí)行中,防止同個(gè)序列的多個(gè)動(dòng)畫重復(fù)執(zhí)行,這個(gè)就是異步執(zhí)行同步收集的處理方案
- 此時(shí)動(dòng)畫開始了,這里注意動(dòng)畫是在異步執(zhí)行的同步的代碼,繼續(xù)調(diào)用下一個(gè) animate
- 執(zhí)行同樣的 animate 方法邏輯但是此時(shí)問題來(lái)了,動(dòng)畫可能還在執(zhí)行可是后續(xù)的 animate 還在繼續(xù)調(diào)用,所以這個(gè)時(shí)候后面的動(dòng)畫代碼就需要等待了(進(jìn)程鎖)
- 隊(duì)列頭是有一把“inprogress”進(jìn)程鎖的,那么這時(shí)候動(dòng)畫只需要加入隊(duì)列,但是可以通過 inprogress 是否存在來(lái)判斷是否執(zhí)行
- 所有的 animate 方法在加入隊(duì)列都是按照以上的邏輯依次執(zhí)行,動(dòng)畫執(zhí)行完畢了就會(huì)有一個(gè)結(jié)束通知,然后從 queue 取出第一個(gè)隊(duì)列繼續(xù)執(zhí)行了,如此循環(huán)
以上是整個(gè)動(dòng)畫的調(diào)度一個(gè)流程,其實(shí)都是利用隊(duì)列異步的空閑然后執(zhí)行同步的代碼,這樣在處理上是沒有浪費(fèi)資源的,而且精確度也是最高的。