記事ディレクトリ
I.はじめに
前回のモバイル端末のメモリ不足によるiOSページの白画面問題に続き、(ブログ記事「高度なクロスプラットフォームアプリ開発 (50) uni-app ios web-view nested H5 project 白画面問題の分析と解決策」を参照)です。システムの実行中に、APP にiOS
黒い画面、黒いブロック、白い画面が頻繁に表示されることがわかりました。
2. 問題分析
上記の問題はページ レンダリングの問題が原因で発生します。ページ スタックのオーバーフローやアプリケーションのメモリ リークが原因である可能性があります。
ページ スタック情報を出力した後getCurrentPages()
、下部のナビゲーションが切り替えられると、ページ スタック情報がクリアされていることが判明したため、ページ スタック オーバーフローの問題はありません。
引き続き APP キャッシュ クリーニング メカニズムを試し、次のようにクリーニング戦略を策定します。
現在のタブ項目をクリックし、現在のページをスクロールまたは更新してネイティブ メソッドを呼び出し、plus.cache.clear
アプリケーション キャッシュをクリアします。別のタブアイテムをクリックすると、間違いなくページ切り替えがトリガーされます。
// 点击 tab 时触发
onTabItemTap (e) {
// #ifdef APP-PLUS
plus.cache.clear( function () {
console.log( "Clear application cache successful!" );
});
// #endif
},
クリーン キャッシュ ポリシーの実装後、問題は解決されました。
uni.setStorage(OBJECT)
このことから、 (macrotask)、uni.setStorageSync(KEY,DATA)
(microtask)などの API を呼び出すように派生しuni.downloadFile
、uni.saveFile
デバイスのメモリに格納されますか?
3.拡張読書
3.1 ページジャンプ
-
uni.navigateTo(OBJECT)
ページ スタックは保持され、navigateBack
呼び出しによって返すことができます。ただし、ページスタックオーバーフローの問題があるため、一般的なジャンプ方法としては使えません。 -
uni.redirectTo(OBJECT)
ページ スタックは保持されず、前のページは返されず、デフォルトのpages.json
最初のページが返されます。 -
uni.reLaunch(OBJECT)
ページ スタックを破棄し、指定されたページにジャンプします。通常、ログアウトしてホームページに戻るために使用されます。 -
uni.switchTab(OBJECT)
タブの切り替えに使用します。 -
uni.navigateBack(OBJECT)
協力しnavigateTo
て使用するページに戻ります。これにより、ページ スタックのオーバーフローを効果的に回避できます。getCurrentPages()
現在のページ スタックを取得し、返す必要があるレイヤーの数を決定できます。
プロジェクト コードを解析した結果、ルーティング ジャンプでページ スタック オーバーフロー例外が発生しないことがわかりました。下部のナビゲーション バーが切り替えられると、ページ スタックがクリアされます。ページ スタックには、同じナビゲーション バーの下にあるページ ジャンプのみが含まれます。
2 トラブルシューティングのアイデア
- 特定のビジネス シナリオに従って、ページ スタックがオーバーフローしないように、ページ ジャンプとページ リターンを論理的に制御します。
getCurrentPages()
ページスタックの高さを判断し、webview
オブジェクトの数を確認することで、現在のジャンプ方法が適切かどうかを判断できます。 - コードのロジックを確認し、バックグラウンド リクエストが長時間返されないという問題がある場合は、この状況を回避するために
uni.request
追加できます。timeout
setInterval
作成された ( ) がクリアされていない ( )タイマーがあるかどうか、メモリ オーバーフローをチェックしますclearInterval
。uniapp
問題自体は、クロスプラットフォームをjs
呼び出す必要があるためnative
、パフォーマンスは確実に失われます. それが許容できない場合は、ネイティブ言語で開発する必要があります.- キャッシュを削除する場合、データが消去された場合に使用する必要があります
uni.clearStorageSync
。
次に、実行中にアプリケーションが占有するメモリをチェックして、メモリ リークがあるかどうかを確認する必要があります。
3.2 $nextTick 原則の詳細な分析
Vue
応答性を達成するには、データが変更された直後に変更するのではなくDOM
、特定の戦略に従って更新する必要がありますDOM
。$nextTick
次のDOM
更新、データを変更した後に使用すると$nextTick
、コールバックで更新されたものを取得できDOM
、次のDOM
更新。
簡単に理解すると、データが で更新およびdom
レンダリングされると、関数が自動的に実行されます。Vue
上記のデータはupdate のdata
直後には更新されませんDOM
。つまり、data
データを変更してすぐにDOM
上記の値を取得すると、取得されるのは古い値であり、その中にDOM
上記の値を取得する操作を入れます。 $nextTick
、更新されたデータを取得できます。
正しい使い方: vue が data 内のデータを変更した後、vue.$nextTick()
メソッドを使用して js オブジェクトをラップし、後続のコードを実行します。
3.2.1 $nextTick() を使用する場合
Vue
ライフサイクルのcreated()
フック関数で行うDOM操作はVue.nextTick()
コールバック関数に配置する必要がある. 理由は,created()
フック関数が実行されるとき, DOMは実際には何の描画も行わず, ここでDOM操作を行っても意味がないからである. time. 無駄とは違うので、ここでは DOM 操作の js コードをVue.nextTick()
コールバック関数に入れる必要があります。
プロジェクトで関数のデータが変更されdata
、新しい dom に基づいて何かを実行したい場合は、新しい一連の js 操作をコールバック関数にDOM
入れる必要があります。Vue.nextTick()
3.2.2 $nextTick() の実行原理
Vue
DOM
更新は非同期で実行されます。データの変更が検出される限り、Vue
タスクキューが開かれ、同じタイム ループで発生するすべてのデータ変更がバッファリングされます。同じものwatcher
が、キューにプッシュされるのは 1 回だけです。(バッファリング中のこの重複排除は、不要な計算やDOM
操作)
そして、次のイベントループ「tick
」で、Vue
キューをフラッシュし、タスクキュー (重複排除) の作業を実行します。
Vue
Promise.then
内部的には、非同期キューにネイティブ (マイクロタスク) を使用しようとしますMutationObserver
。実行環境がサポートしていない場合は、代わりに (マクロタスク)setImmediate
を使用します。setTimeout(fn, 0)
3.3 JS の動作メカニズム
JS
実行はシングル スレッドであり、イベント ループ ベースです。イベント ループは、次の手順に大別されます。
- すべての同期タスクはメイン スレッドで実行され、実行スタックが形成されます。
- メインスレッドに加えて、「タスクキュー」 (
task queue
) もあります。 - 非同期タスクに実行結果がある限り、イベントは「タスク キュー」に配置されます。
- 「実行スタック」内のすべての同期タスクが実行されると、システムは「タスク キュー」を読み取り、そこにあるイベントを確認します。それらの対応する非同期タスクは待機状態を終了し、実行スタックに入り、実行を開始します。メインスレッドは、上記の 3 番目のステップを繰り返し続けます。
メイン スレッドの実行プロセスはティックであり、すべての非同期結果は「タスク キュー」を通じてスケジュールされます。「タスクキュー」には、タスクが1つずつ格納されます。仕様では、タスクをマクロ タスクとマイクロ タスクの2 つのカテゴリに分類することが規定されています。
3.3.1 マイクロタスク
とも呼ばれjob
、通常、現在実行中のスクリプトの直後に発生する処理に使用されます。たとえば、一連の動作に反応する場合や、新しいタスクを作成せずに非同期タスクを実行する場合などです。javascript
各タスクの最後に、実行スタックで他に何も実行されていない限り、マイクロタスク キューはコールバック後に処理されます。マイクロタスク中にキューに入れられた他のマイクロタスクは、このキューの最後に追加されます。
一般的なマイクロタスクはMutationObsever
、、、ですPromise.then
。$nextTiock
3.3.2 マクロタスク
javascript / dom
マクロ タスクの役割は、ブラウザが内部からコンテンツを取得できるようにし、実行スタックが順次処理できるようにすることです。HTML の解析、マウス クリック イベントのコールバックの取得など、スケジューリングはいたるところにあります。
一般的なマクロ タスクはsetTimeout
次MessageChannel
のとおりですpostMessage
。setImmediate
vue
DOM 更新の場合、非同期キュー制御のために内部的にも呼び出されますnextTick
。自分で呼び出すとnextTick
、DOM を更新するマイクロタスクの後に独自のコールバック関数が追加され、DOM が更新された後にコードが実行されるようになります。
setTimeout
マクロタスクであり、遅延実行のみであり、遅延実行方式ではDOM
更新される場合とされない場合があります。
3. ソリューション
注意⚠️:
-
uni-app
アプリ側の組み込みHTML5+
エンジンにより js は豊富なネイティブ機能を直接呼び出すことができます。条件付きコンパイルの呼び出し
HTML5+
: アプレットや H5 などのプラットフォーム用のHTML5+
拡張ため、 の拡張仕様を呼び出すuni-app
場合は、条件付きコンパイルの使用に注意する必要があります。HTML5+
そうしないと、h5 やアプレットなどのプラットフォームで実行したときにplus is not defined
エラー。// #ifdef APP-PLUS var appid = plus.runtime.appid; console.log('应用的 appid 为:' + appid); // #endif
-
uni-app
ロジック レイヤーはjscore
、ローカル マシンに依存しない独立した環境で実行されるwebview
ため、一方ではブラウザーの互換性の問題がなく、その上でコードAndroid4.4
を実行es6
できますが、他方では、window、document、navigator、localstorage
他のブラウザー固有の jsを実行することはできません。 API。jscore
標準のjsエンジンで、if、for、各種文字列、日付処理など、標準のjsが正常に動作します。js とブラウザの違いを区別する必要があります。 -
uni-app
jsは実行されず、独立しているwebkit remote debug
ため、アプリ側にアプリなどはありません。uni-app
webview
jscore
-
ブラウザGUI レンダリング スレッドとJS エンジン スレッドは相互に排他的であるため、JS エンジンが実行されると、JS エンジンの実行が終了するまで GUI スレッドは中断されます。ページに長いタスクが多数ある場合、ページ UI がブロックされ、インターフェイスが動かなくなり、フレームがドロップされます。
GUI レンダリング スレッドhtml、css
: ページの描画とレンダリング、リソースの解析、DOM ツリーの生成、およびページの描画を担当する、よく知られているすべてのスレッドがこのスレッドを担当します。
JS エンジン スレッド: すべての非同期および同期タスクの js 解析と実行、実行スタックの維持、最初に同期コードを 1 つずつ処理する責任を負います。非同期タスクに遭遇すると、イベントを使用してスレッドをトリガーします。
ブラウザのプロセスとスレッドの情報は次のとおりです。
そのうち、フロントエンドは主にブラウザ カーネルのレンダリング プロセスに焦点を当てています。ブラウザ カーネルは主にhtml、css、js
リソースの解析とレンダリングを担当し、イベント ループと非同期リクエストも担当します。 .
データストレージ: uni-app のキャッシュと H5 キャッシュはメモリに保存されますか?
-
ネイティブ
plus Storage
モジュールは、アプリケーション データの保存と読み取りに使用される、アプリケーションのローカル データ ストレージ領域を管理します。アプリケーション ローカル データ と との違いは、データが異なるドメインで有効であるlocalStorage
ことです. 前者はアプリケーション内のドメイン間で操作できます. データの保存期間は永続的で、容量制限はありません. アプリケーション ローカル データ管理オブジェクトは、から取得できます。sessionStorage
plus.storage
-
uni-app
アプリケーションuni.setStorage(OBJECT)
(マクロタスク) およびuni.setStorageSync(KEY,DATA)
(マイクロタスク) がデータを保存する場合、本質的にはネイティブを使用しplus.storage
、サイズの制限はなく、キャッシュではなく、sqlite
永続化のためにデータベース ファイルにデータを保存することです。 -
H5 アプリケーション
localStorage
とsessionStorage
データ ストレージの場合、ブラウザーはサイズを 5M に制限します。これはキャッシュの概念であり、クリーンアップされる可能性があります。 -
アプリケーションは
Vuex
状態管理を実装します。 -
ネイティブ
plus.cache
管理アプリケーションのキャッシュ データにはwebview
、プログラムで生成されたデータのみが含まれ、拡張機能api
(uni.setStorage(OBJECT)
(マクロタスク)、uni.setStorageSync(KEY,DATA)
(マイクロタスク) およびその他の API など) を使用してビジネス ロジックに保存されたデータは含まれません。 -
各アプレットには独自の が付属しており
storage api
、データ ストレージのライフ サイクルはアプレット自体と一致しています。つまり、ユーザーが積極的に削除したり、一定期間後に自動的にクリーンアップされたりしない限り、データは常に利用可能です。 -
uni-app
フレームワーク コンポーネント自体で解決できない問題については、フレームワーク コンポーネントを破棄し、ネイティブ コンポーネントを使用して最適化することができます。
最後に、下部のタブを切り替えるときにキャッシュ クリーニングを行うことを選択します (ここでのキャッシュ クリーニングは、plus.cache.clear
アプリケーションのキャッシュ データをクリアするために使用されることに注意してください)。アプリケーション キャッシュ データのクリアには、プログラムでの使用によって生成されたデータのみが含まれ、ビジネス ロジックの拡張機能によって保存されたデータはwebview
含まれません。api
コードは以下のように表示されます:
// 点击 tab 时触发
onTabItemTap (e) {
console.log('-----------点击 tab 时触发-----------', e);
// #ifdef APP-PLUS
plus.cache.clear( function () {
console.log( "component Clear application cache successful!" );
});
// #endif
},