How to Supercharge WePY Mini‑Program Performance with Preloading and Smart Data Binding

This article explains common performance bottlenecks in WeChat mini‑programs, demonstrates how WePY's preloading and prefetch mechanisms can eliminate redirect delays, and shows how reducing redundant setData calls with dirty‑checking dramatically improves rendering speed.

Tencent TDS Service
Tencent TDS Service
Tencent TDS Service
How to Supercharge WePY Mini‑Program Performance with Preloading and Smart Data Binding

Introduction

Performance tuning is a timeless topic, both for traditional H5 and mini‑programs. Because of different execution mechanisms, some H5 optimizations do not apply to mini‑programs, so new methods are needed.

This article introduces two performance issues encountered in mini‑program development and the corresponding WePY optimization solutions.

Preloading

Principle

In traditional H5, preloading can improve user experience, but in mini‑programs it can be implemented more simply and is often overlooked.

When a traditional H5 page loads, only its own JavaScript is kept; after navigation to another page the previous page’s data disappears. Mini‑programs load all page logic into memory at startup, so data can be accessed across pages.

A simple verification is to add a setInterval(function () {console.log('exist')}, 1000) in page1; the timer persists after navigation in a mini‑program but not in H5.

Because of this mechanism, we can preload data in page1 and use it directly in page2, avoiding the 300‑400 ms redirect delay.

Experiment: two pages page1 and page2 added to the official demo.

bindTap: function () {
  wx.startTime = +new Date();
  wx.navigateTo({url: '../page2/page2'});
},
fetchData: function (cb) {
  setTimeout(function () {cb({a:1});}, 500);
},
onLoad: function () {
  wx.endTime = +new Date();
  this.fetchData(function () {
    wx.endFetch = +new Date();
    console.log('page1 redirect start -> page2 onload invoke -> fetch data complete: ' + (wx.endTime - wx.startTime) + 'ms - ' + (wx.endFetch - wx.endTime) + 'ms');
  });
}

After 10 retries the results are shown:

Optimization

WePY provides two concepts to solve the above problem:

Preload data – page1 proactively loads data needed by page2.

Prefetch data – page2’s onPrefetch event is called during redirect, and onLoad receives the prefetched data. onLoad (params, data) {} Preload example:

methods: {
  tap () {
    this.$redirect('./page2');
  }
},
onLoad () {
  setTimeout(() => {
    this.$preload('list', api.getBigList())
  }, 3000)
}
// page2.wpy
onLoad (params, data) {
  data.preload.list.then((list) => render(list));
}

Prefetch example:

methods: {
  tap () {
    this.$redirect('./page2');
  }
},
// page2.wpy
onPrefetch () {
  return api.getBigList();
}
onLoad (params, data) {
  data.prefetch.then((list) => render(list));
}

Data Binding

Principle

Understanding the mini‑program runtime is essential for data‑binding optimization. The view layer communicates with the logic layer via WeixinJSBridge, using different bridge calls on web, iOS, and Android.

The this.setData method triggers communication cost; each call involves multiple JSON serializations and postMessage operations.

function setData(obj) {
  if (typeof(obj) !== 'Object') { console.log('类型错误'); }
  let type = 'appDataChange';
  let e = [type, {data: {data: list}, options: {timestamp: +new Date()}}, [0]];
  var datalength = JSON.stringify(e.data).length;
  if (datalength > AppserviceMaxDataSize) { console.error('已经超过最大长度'); return; }
  if (type === 'appDataChange' || type === 'pageInitData' || type === '__updateAppData') {
    __wxAppData = {'pages/page1/page1': alldata};
    e = {appData: __wxAppData, sdkName: "send_app_data"};
    var postdata = JSON.parse(JSON.stringify(e));
    window.postMessage({postdata}, "*");
  }
  e = {eventName: type, data: e[1], webviewIds: [0], sdkName: 'publish'};
  var postdata = JSON.parse(JSON.stringify(e));
  window.postMessage({postdata}, "*");
}

The flow shows that a single setData({a:1}) results in three JSON.stringify, two JSON.parse, and two window.postMessage calls, processing the whole page data each time. Therefore, reducing the number of setData calls is crucial.

Experiment

Three binding strategies were tested with a list of 1000 items:

Optimal binding – add all items in memory then call setData once.

Poor binding – call setData after each item insertion.

Smart binding – perform a dirty‑check at the end and call setData once.

// page1.wxml
<view bindtap="worse">worse数据绑定测试</view>
<view bindtap="best">best数据绑定测试</view>
<view bindtap="digest">digest数据绑定测试</view>
<view class="list">
  <view wx:for="{{list}}" wx:for-index="index" wx:for-item="item">
    <text>{{item.id}}</text>---<text>{{item.name}}</text>
  </view>
</view>
// page1.js
worse: function () {
  var start = +new Date();
  for (var i = 0; i < 1000; i++) {
    this.data.list.push({id: i, name: Math.random()});
    this.setData({list: this.data.list});
  }
  var end = +new Date();
  console.log(end - start);
},
best: function () {
  var start = +new Date();
  for (var i = 0; i < 1000; i++) {
    this.data.list.push({id: i, name: Math.random()});
  }
  this.setData({list: this.data.list});
  var end = +new Date();
  console.log(end - start);
},
digest: function () {
  var start = +new Date();
  for (var i = 0; i < 1000; i++) {
    this.data.list.push({id: i, name: Math.random()});
  }
  var data = this.data;
  var $data = this.$data;
  var readyToSet = {};
  for (var k in data) {
    if (!util.$isEqual(data[k], $data[k])) {
      readyToSet[k] = data[k];
      $data[k] = util.$copy(data[k], true);
    }
  }
  if (Object.keys(readyToSet).length) {
    this.setData(readyToSet);
  }
  var end = +new Date();
  console.log(end - start);
},
onLoad: function () {
  this.$data = util.$copy(this.data, true);
}

After ten runs the performance difference reached about 40×, confirming that multiple setData calls dramatically degrade speed.

Optimization

Avoid multiple setData calls within the same flow. WePY adopts a dirty‑checking mechanism that runs once at the end of a flow, applying only the necessary changes.

The dirty‑check is similar to AngularJS’s approach but operates on a component’s own data, so it does not become a bottleneck.

Although native code can be faster, WePY balances performance, development efficiency, and maintainability by using dirty‑checking.

Other Optimizations

WePY also offers many development‑efficiency improvements, such as componentized development, rich compiler support (Babel, TypeScript, Pug, Less, Sass, Stylus), plugin handling, ESLint integration, lifecycle enhancements, mixins, and event optimizations.

Conclusion

Mini‑programs still have many optimization opportunities; readers are encouraged to discuss and share their experiences.

frontendPerformance optimizationmini-programpreloadingData Bindingwepy
Tencent TDS Service
Written by

Tencent TDS Service

TDS Service offers client and web front‑end developers and operators an intelligent low‑code platform, cross‑platform development framework, universal release platform, runtime container engine, monitoring and analysis platform, and a security‑privacy compliance suite.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.