比較的従来型の注文アプリであるプロジェクトについて簡単に紹介します。
インターフェイスは次のとおりです:
左側はカテゴリ メニュー、右側は長いリストです。製品には複数のカテゴリがあります。 1つのカテゴリをスクロールした後もスクロールを続けることができ、次のカテゴリに切り替えると、左側のカテゴリメニューの選択状態が現在の商品リストに表示されているカテゴリに切り替わります。
ユーザー エクスペリエンスの向上を考慮し、Meituan や他の注文アプレットを参考に、この製品リストのデータを一度に返します。 現在発生している問題は、商品の数が多い場合、最初のレンダリング時間が非常に長くなり、ページがフリーズしてしまうことです。
Xiaosheng bb: 実際、元のコードは (歴史的な理由により) 書かれすぎていました...OTL
最初に写真を載せてください
Xiaosheng bb: もうミニプログラムにも耐えられないので、警告しなければなりません
WeChat開発者ツールは警告を出しました。プロンプトには特定のコードの場所も含まれているため、キーはこの setData
です! ! !
まず、ミニ プログラムのパフォーマンスと setData
最適化に関する公式の提案をいくつか見てみましょう。 (developers.weixin.qq.com/miniprogram…)
具体的な実践:
setData
一度に大量のデータを送信することはできません。長すぎる場合は、個別にレンダリングできます (2 次元配列に変換し、ループ内で毎回 1 つの配列をレンダリングするなど)。 v1: 簡易ラフ版
// 每次渲染一个分类// 假设goodsList是一个二维数组goodsList.forEach((item, index) => { this.setData({ [`goodsList[${index}]`]: item }) })复制代码
上記のように書くと問題があり、ページの最初の画面表示は速いのですが、ページをクリックしたときの動作(購入ボタン等)を押すとページがフリーズしますので、しばらくお待ちください、操作フィードバックが大幅に遅れます。
実際、これは、このサイクルによって単一の setData
の数が減りますが、複数の setData
のサイクルに変わるためです。わかりましたが、実際には、他のカテゴリ (他の配列) はまだレンダリング中であり、スレッドはまだビジー状態です。JS スレッドはレンダリングをコンパイルして実行しています。クリック イベントは時間内にロジック層に渡すことができず、ロジック層は操作処理結果を時間内にビュー層に渡すことができません。
v2: タイマー ハック バージョン
js スレッドはレンダリングでビジー状態であるため、最初にそれを強制的に停止できます。つまり、v2 のタイマーハックバージョンがあります。
// 每次渲染一个分类let len = data.goodsList ? data.goodsList.length : 0;let idx = 0let timer = setInterval(() => { if (idx < len) { that.setData({ [`goodsList[${idx}]`]: data.goodsList[idx] }); idx++ } else { clearInterval(timer) } }, 15);复制代码
これで、最初の画面の描画速度の問題は解決され、ボタンをクリックしたときの応答の遅れの問題も解決されました。ただ、コードが少しハック的で、そのせいで私は強迫性障害に悩まされています。
v3: Big Killer - Virtual List
仮想リストの単純な原理は、現在のリストをレンダリングするだけです。表示画面領域と前の n 画面と後ろの n 画面 別のフィールドを使用して、表示する必要がある現在の配列 (つまり、現在の画面の n 画面前と現在の画面の n 画面後) を保存します。リストがスクロールするたびに、を選択すると、表示する必要のあるデータが再計算されます。このフィールドが更新されると、それに応じてページも更新されます。これにより、ページ上の要素ノードの数が多すぎず、大量のデータに対する長いリスト要件をサポートできるようになります。
より詳細な原則と実装については、学生が自分で検索できるため、ここでは詳しく説明しません。
ミニ プログラムには、公式のオープン ソース仮想リスト コンポーネントもあります:recycle-view
setData
は、詳細な更新をサポートし、特定の属性を指定できます。 たとえば、追加購入などの操作で商品の右上隅にある小さな数字を更新する必要がある場合は、次のように記述できます:
this.setData({ [`goodsList[${categoryIndex}][${goodsIndex}].num`]: goodsItem.num })复制代码
data
に保存します。setData
はページのレンダリングをトリガーするため、setData
で更新しないでください。 例:
Page({ data: { ... }, // 跟页面渲染无关的数据 state: { hasLogin: false, }, ... })// 更新的时候直接赋值就行this.state.hasLogin = true复制代码
PS: または、page
オブジェクトにマウントする必要さえなく、通常の変数を使用して直接保存するだけです。
長いリスト内の画像サイズが制限されていない場合、多数の大きな画像が大量のメモリを占有し、iOS クライアントのメモリ使用量が増加する可能性があります。増加するため、システムのリサイクル ミニ プログラム ページがトリガーされます。メモリの問題に加えて、画像が大きいとページ切り替えの遅延が発生する可能性もあります。
解決策は、現在表示されている写真領域のサイズに基づいて、適切なサイズ (写真の 2 倍から 3 倍) で写真を撮影することです。
画像には CDN を使用することをお勧めします。一般に、画像サービスを提供する CDN サービス プロバイダーは画像をトリミングするためのインターフェイスを提供し、そのインターフェイスは元の画像リンクのみを返し、フロント エンドはパラメーターを渡します。必要に応じて画像をトリミングします。具体的なフロントエンドのアプローチとしては、公開画像処理メソッドを作成することも、画像コンポーネントを自分でカプセル化することもできます。
一般的に使用される画像 CDN サービス プロバイダーの画像トリミング API ドキュメントを添付します:
比如在该点餐页面进入时需要获取定位,然后根据定位获取最近的门店,前面两个接口都需要请求(具体可以根据业务需求),而最后如果获取到的距离最近的门店跟上次一样,则不需要重新获取店铺详情和商品数据。
还是该点餐页面流程,像上文说过的,进入页面时需要获取定位接口,等定位接口返回结果了再拿定位取值去获取距离最近的店铺,最后才是请求店铺和商品数据。
这三个接口是串行的。此时如果我们每个接口都弹出一个loading提示,就会出现loading显示一会儿,消失,又显示一会儿,又消失……这样的现象,这样的体验是不太好的。
建议可以通过封装请求,并且在请求里统一处理loading,来合并短时间内多次发起请求的多个loading。
eg:
let showLoadingTimer = null;let showRequestLoading = false; // 标记是否正在显示loading/** * 封装request * @param {*} {showLoading:是否需要显示loading, options:request参数,如url,data等} */function request({showLoading = true, ...options}) { // 显示request loading handleShowLoading(showLoading) wx.request({ ... complete() { // 关闭request loading handleShowLoading(false) } }) }/** * 封装request loading * 短时间内如果调用多次showLoading,会合并在一起显示,而不是每个都闪现一下 * @param showLoading */function handleShowLoading(showLoading) { if (showLoading) { // 显示loading clearTimeout(showLoadingTimer); if (!showRequestLoading) { showRequestLoading = true; wx.showNavigationBarLoading(); wx.showLoading({ title: "加载中", mask: true }) } } else { // 200ms后关闭loading showLoadingTimer = setTimeout(() => { showRequestLoading = false; wx.hideNavigationBarLoading(); wx.hideLoading() }, 200) } }复制代码
比如这个点餐页每次 onShow
都会调用定位接口和获取最近门店接口,但是不显示loading,用户就没有感知,体验比较好。
需要关注接口的粒度控制。 因为有时候合并接口,前端可以减少一次请求,体验更好;但有时候如果接口的数据太多,响应太慢,就可以考虑是否某部分数据可以后置获取,让主要的页面内容先渲染出来,根据这个设计来拆分接口。
比如项目中的点餐页面,原来购物车数据和商品规格弹窗显示的详情数据都是在获取店铺商品接口一次性返回的,而这个接口本来由于设计需要一次返回所有商品,就会造成数据量太大,而且后端需要查询的表也更多。于是把获取购物车,和商品详情接口都拆分为单独的接口,获取店铺商品接口的响应时间就减少了,页面也能更快显示出来。
其实上面提到的逻辑优化和接口优化很多都是细节,并不是太高深的技术,我们平时迭代的时候就可以注意。而体验方面的优化则需要前端同学在前端技术以外更多关注用户体验和设计方面的知识啦,而且这也是一个有追求的前端应该具备的技能……←_←
所以嘛……技术路漫漫,大家共勉吧
相关免费学习推荐:微信小程序开发教程
以上が小規模プログラムのパフォーマンス最適化の実践概要の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。