序文
最近、ustbhuangyi先生のVueソースコードを調べて、コースを総合的に分析しています。以下の内容はクラスノートと見なすことができます。
JS操作メカニズム
nextTickの理解を容易にするために、最初にJSの操作メカニズムを理解する必要があります。
参照リンク:
JSの実行はシングルスレッドであり、イベントループに基づいています。イベントループは、大きく次の手順に分けられます。
(1)すべての同期タスクはメインスレッドで実行され、実行コンテキストスタックを形成します。
(2)メインスレッドに加えて、「タスクキュー」もあります。非同期タスクの実行結果がある限り、イベントは「タスクキュー」に配置されます。
(3)「実行スタック」内のすべての同期タスクが実行されると、システムは「タスクキュー」を読み取り、その中にあるイベントを確認します。次に、これらの対応する非同期タスクは待機状態を終了し、実行スタックに入り、実行を開始します。
(4)メインスレッドは上記の3番目のステップを繰り返し続けます。
私の理解
簡単なテスト
<script>
console.log(1)
console.log(2)
console.log(3)
console.log(4)
test()
console.log(5)
console.log(6)
console.log(7)
console.log(8)
function test(){
console.log("a")
setTimeout(function(){console.log("b")},1000)
}
</script>
プリント注文
ソースコードの実装
nextTickソースコード実装の本質は、実装する関数を収集し、それらをコールバック配列に収集してから、次のティックで配列をトラバースしてコールバックを実行することです。
src / core / util / next-tick.js
constコールバック= []
……。
エクスポート関数nextTick(cb?:関数、ctx?:オブジェクト){
_resolveしましょう
callbacks.push(()=> {
if(cb){
{を試してください
cb.call(ctx)
} catch(e){
handleError(e、ctx、 'nextTick')
}
} else if(_resolve){
_resolve(ctx)
}
})
if(!pending){
保留中= true
timerFunc()
}
// $ flow-disable-line
if(!cb && typeof Promise!== 'undefined'){
新しいPromise(resolve => {を返す
_resolve =解決
})
}
}
テスト
<テンプレート>
<div class = "hello">
<h1 ref = "msg"> { {msg}} </ h1>
<div>
<button @ click = "changeText1"> change1 </ button>
<button @ click = "changeText2"> change2 </ button>
</ div>
</ div>
</ template>
<スクリプト>
デフォルトのエクスポート{
名前: 'NextTick'、
データ(){
戻り値{
msg: 'Hello World'
}
}、
メソッド:{
changeText1(){
this.msg = 'こんにちはvue'
// domの結果を同期的に出力します
console.log( 'sync:msg =' + this。$ refs.msg.innerText)//再輸出の世界
// domの結果を非同期に出力します
//次の2つの方法を書くことができます
//this。$nextTick(()=> {
// console.log( "nextTick:msg =" + this。$ refs.msg.innerText)
//})
this。$ nextTick()。then(()=> {
console.log( 'nextTick:msg =' + this。$ refs.msg.innerText)//輸出出こんにちはvue
})
}、
changeText2(){
//実行順序は書き込み順序に関連しています
this。$ nextTick(()=> {
console.log( 'nextTick:msg =' + this。$ refs.msg.innerText)//再輸出の世界
})
this.msg = 'こんにちはvue'
// domの結果を同期的に出力します
console.log( 'sync:msg =' + this。$ refs.msg.innerText)//再輸出の世界
// domの結果を非同期に出力します
//結論:domの再レンダリングへのデータの変更は非同期プロセスです
this。$ nextTick()。then(()=> {
console.log( 'nextTick:msg =' + this。$ refs.msg.innerText)//輸出出こんにちはvue
})
}
}
}
</ script>
総括する
DOMの再レンダリングへのデータ変更は非同期プロセスであり、次のティックで発生します。
これは、サーバーインターフェイスからデータを取得するときなど、開発プロセスで通常行うことです。データの変更後にDOMの変更に依存するメソッドがある場合は、nextTickの後に実行する必要があります。
たとえば、次の擬似コード:
getData(res).then(()=> {
this.xxx = res.data
this。$ nextTick(()=> {
//ここで変更されたDOMを取得できます
})
})
レンダリングウォッチャーの更新はデータが変更された後にトリガーされますが、ウォッチャーのフラッシュはnextTickの後であるため、再レンダリングは非同期です。