分類:
版權聲明:本文為博主原創文章,未經博主允許不得轉載。
ready、queue放在一塊寫,沒有特殊的意思,只是相對來說它倆可能源碼是最簡單的了。ready是在dom加載完成後,以最快速度觸發,很實用。queue是隊列,比如動畫的順序觸發就是通過默認隊列』fx'處理的。
(本文採用 1.12.0 版本進行講解,用 #number 來標註行號)
ready
很多時候,我們需要盡快的加載一個函數,如果裡面含有操作dom的邏輯,那麼最好在dom剛剛加載完成時調用。window的load事件會在頁面中的一切都加載完畢時(圖像、js文件、css文件、iframe等外部資源)觸發,可能會因外部資源過多而過遲觸發。
DOMContentLoaded
:IE9+、Firefox、Chrome、Safari3.1+、Opera9+HTML5規範指定的標準事件,在document上,在形成完整的dom樹後就會觸發(不理會圖像、js文件、css文件等是否下載完畢)。
readystatechange
:IE、Firfox4+、Opera這個事件的目的是提供與文檔或元素的加載狀態相關的信息,但這個事件的行為有時候很難預料。支持該事件的每個對象都有一個readyState屬性,可能包含下列5個值中的一個。
uninitialized(未初始化):對象存在但尚未初始化
loading(正在加載):對象加載數據完成
interactive(交互):可以操作對象了,但還沒有完全加載
complete(完成):對象已經加載完成
對document而言,值為」interactive」的readyState會在與
DOMContentLoaded
大致相同時刻觸發readystatechange
(行為難料,該階段既可能早於也可能晚於complete階段,jq上報告了一個interactive的bug,所以源碼中用的complete)。而且在包含較少或較小的外部資源的頁面中,readystatechange
有可能晚於load事件,因此優先使用DOMContentLoaded
。
jQuery思路
jq可以通過
$(xx).ready(fn)
指定dom加載完後需要盡快調用的事件。我們知道事件一旦錯過了監聽,就不會再觸發,$().ready()增加了遞延支持,這裡自然要使用'once memory'
的觀察者模型,Callback、Deferred對象均可,源碼中是一個Deferred對象,同時掛載在變量readyList上。- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
有了promise對象,需要dom加載完後,盡快的resolve這個promise。判斷加載完的方式,就是首先判斷是否已經是加載完成狀態,如果不是優先使用DOMContentLoaded事件,IE6-8用readystatechange,都要用load事件保底,保證一定觸發。由於readystatechange為complete時機詭異有時甚至慢於load,IE低版本可以用定時器反覆
document.documentElement.doScroll('left')
判斷,只有dom加載完成調用該方法才不報錯,從而實現盡快的觸發。
jQuery是富有極客精神的,綁定的觸發函數調用一次後就不再有用,因此觸發函數中不僅能resolve那個promise,還會自動解綁觸發函數(方法
觸發函數->
detach()
),這樣比如readystatechange、load多事件不會重複觸發,同時節省內存。當然doScroll方法是setTimeout完成的,如果被readystatechange搶先觸發,需要有變量能告知他取消操作,源碼中是jQuery.isReady
。觸發函數->
completed()
= 解綁觸發函數->detach()
+ resolve那個promise->jQuery.ready()
jq中增加了
holdReady(true)
功能,能夠延緩promise的觸發,holdReady()
不帶參數(即jQuery.ready(true))則消減延遲次數,readyWait
初始為1,減至0觸發。由於doScroll靠jQuery.isReady防止重複觸發,因此即使暫緩jQuery.ready()也要能正常的設置jQuery.isReady = true
。jQuery.ready()不僅能觸發promise,之後還會觸發』ready'自定義事件。
思路整理
- 1
- 2
- 3
- 1
- 2
- 3
[源碼]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
queue
jQuery提供了一個多用途隊列,animate添加的動畫就是使用默認的』fx'隊列完成的。動畫的特點,是在元素上一經添加,即刻觸發,並且該元素一個動畫執行完,才會執行下一個被添加的動畫。動畫的執行是含有異步過程的,從這點上看,queue的價值是允許一系列函數被異步地調用而不會阻塞程序。jq隊列的實現,並不是為了僅僅給動畫使用,由核心功能
jQuery.queue/dequeue
和外觀jQuery.fn.queue/dequeue/clearQueue/promise
組成。
queue模型
下面是一個簡單的隊列模型。如何實現異步調用呢?在棧出的函數fn中傳入next參數即可實現,只要函數內調用next(),即可實現異步調用下一個。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
jquery實現
jquery的實現更精密,還考慮了隊列棧出為空後調用鉤子函數銷毀,type參數省略自動調整。功能自然是兩套:
jQuery.xx/jQuery.fn.xx
,使得$()
包裹元素可以迭代調用,並且$()調用時type為』fx'時,還將能夠添加時即刻執行。儲存位置都在私有緩存jQuery._data( elem, type )
中。
API具體功能見下面:
內部使用:(type不存在,則為』fx',後參數不會前挪)
jQuery.queue( elem, type[, fn] )
:向隊列添加fn,若fn為數組,則重定義隊列,type默認』fx'。這裡不會添加_queueHooksjQuery.dequeue( elem, type)
:type默認』fx',棧出隊列開頭並執行。若是為』fx'隊列,一旦被dequeue過,總是給隊列開頭增加有一個」inprogress」,之所以這麼做是為了滿足』fx'動畫隊列首個添加的函數要立即執行,需要一個標記。還會增加jQuery._queueHooks
鉤子,dequeue在隊列無函數時調用,會調用鉤子來刪除隊列對象和鉤子本身(極客精神-_-||)
外部使用:(type不為字符串,則為』fx',且後參數會前挪)
jQuery.fn.queue( type, fn )
:type默認』fx',對於』fx'隊列,添加第一個fn時默認直接執行(動畫添加即執行的原因,第一個添加的開頭沒有」inprogress」),其他則無此步驟。此方式添加fn都會給元素們的緩存加上用於自毀的鉤子jQuery._queueHooks( this, type )
jQuery.fn.dequeue( type )
:對每個元素遍歷使用jQuery.dequeue( this, type )jQuery.fn.clearQueue( type )
:重置隊列為空數組,type默認』fx',不對已綁定的_queuehook產生影響jQuery.fn.promise( type, obj )
: 返回一個deferred對象的promise對象,帶有jQuery._queueHooks
鉤子的所有元素鉤子均被觸發時,觸發resolve(比如幾個元素動畫全都執行完後執行某操作)
在隊列中函數執行時,會向函數注入elem、next、hooks,通過next可以讓函數內部調用jQuery.dequeue,hooks可以讓函數內部調用empty方法直接終止、銷毀隊列,或者綁定銷毀時要執行的邏輯。
[源碼]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158