前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >WePY 在小程序性能调优上做出的探究

WePY 在小程序性能调优上做出的探究

原创
作者头像
Gcaufy
修改于 2017-06-19 10:59:21
修改于 2017-06-19 10:59:21
4.9K00
代码可运行
举报
文章被收录于专栏:Gcaufy的专栏Gcaufy的专栏
运行总次数:0
代码可运行

导语

性能调优是一个亘古不变的话题,无论是在传统H5上还是小程序中。因为实现机制不同,可能导致传统H5中的某些优化方式在小程序上并不适用。因此必须另开辟蹊径找出适合小程序的调估方式。

预先加载

这一节的内容主要是基于 anniexliu 的文章进行的研究:《小程序性能优化——提高页面加载速度》

原理

传统H5中也可以通过预加载来提升用户体验,但在小程序中做到这一点实际上是可以更简单方便却又更容易被忽视的。

传统H5在启动时,page1.html 只会加载 page1.html 的页面与逻辑代码,当page1.html 跳转至 page2.html 时,page1 所有的 Javascript 数据将会从内存中消失。page1 与 page2 之间的数据通信只能通过 URL 参数传递或者浏览器的 cookie,localStorge 存储处理。

小程序在启动时,会直接加载所有页面逻辑代码进内存,即便 page2 可能都不会被使用。在 page1 跳转至 page2 时,page1 的逻辑代码 Javascript 数据也不会从内存中消失。page2 甚至可以直接访问 page1 中的数据。

最简单的验证方式就是在 page1 中加入一个setInterval(function () {console.log('exist')}, 1000)。传统H5中跳转后定时器会自动消失,小程序中跳转后定时器仍然工作。

小程序的这种机制差异正好可以更好的实现预加载。通常情况下,我们习惯将数据拉取写在 onLoad 事件中。但是小程序的 page1 跳转到 page2,到 page2 的 onLoad 是存在一个 300ms ~ 400ms 的延时的。如下图:

因为小程序的特性,完全可以在 page1 中预先拿取数据,然后在 page2 中直接使用数据,这样就可以避开 redirecting 的 300ms ~ 400ms了。如下图:

试验

在官方demo中加入两个页面:page1,page2

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// page1.js 点击事件中记录开始时间
bindTap: function () {
  wx.startTime = +new Date();
  wx.navigateTo({
    url: '../page2/page2'
  });
}


// page2.js 中假设从服务器拉取数据需要500ms
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');
  });
}

重试10次,得到的结果如下:

优化

对于上述问题,WePY 中封装了两种概念去解决:

  • 预加载数据

用于 page1 主动传递数据给 page2,比如 page2 需要加载一份耗时很长的数据。我可以在 page1 闲时先加载好,进入 page2 时直接就可以使用。

  • 预查询数据

用于避免于 redirecting 延时,在跳转时调用 page2 预查询。

扩展了生命周期,添加了onPrefetch事件,会在 redirect 之时被主动调用。同时给onLoad事件添加了一个参数,用于接收预加载或者是预查询的数据:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// params
// data.from: 来源页面,page1
// data.prefetch: 预查询数据
// data.preload: 预加载数据
onLoad (params, data) {}

预加载数据示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// page1.wpy 预先加载 page2 需要的数据。

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

// page2.wpy 直接从参数中拿到 page1 中预先加载的数据
onLoad (params, data) {
  data.preload.list.then((list) => render(list));
}

预查询数据示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// page1.wpy 使用封装的 redirect 方法跳转时,会调用 page2 的 onPrefetch 方法
methods: {
  tap () {
    this.$redirect('./page2');
  }
}

// page2.wpy 直接从参数中拿到 onPrefetch 中返回的数据
onPrefetch () {
  return api.getBigList();
}
onLoad (params, data) {
  data.prefetch.then((list) => render(list));
}
c

数据绑定

原理

在针对数据绑定做优化时,需要先了解小程序的运行机制。因为视图层与逻辑层的完全分离,所以二者之间的通信全都依赖于 WeixinJSBridge 实现。如:

  • 开发者工具中是基于window.postMessage
  • IOS中基于 window.webkit.messageHandlers.invokeHandler.postMessage
  • Android中基于WeixinJSCore.invokeHandler

因此数据绑定方法this.setData也如此,频繁的数据绑定就增加了通信的成本。再来看看this.setData究竟做了哪些事情。基于开发者工具的代码,单步调试大致还原出完整的流程,以下是还原后的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*
setData 主流程精简还原,并非完整主流程,内有注释
*/
function setData (obj) {
    if (typeof(obj) !== 'Object') {
        console.log('类型错误'); // 并没有预期中的return;
    }
    let type = 'appDataChange';

    // u.default.emit(e, this.__wxWebviewId__) 代码还原
    let e = [type, {
                data: {data: list}, 
                options: {timestamp: +new Date()}
            },
            [0] // this.__wxWebviewId__
    }];

    // WeixinJSBridge.publish.apply(WeixinJSBridge, e); 代码还原
    var datalength = JSON.stringify(e.data).length;  // 第一次 JSON.stringify
    if (datalength > AppserviceMaxDataSize) { // AppserviceMaxDataSize === 1048576
        console.error('已经超过最大长度');
        return;
    }

    if (type === 'appDataChange' || type === 'pageInitData' || type === '__updateAppData') {

        // sendMsgToNW({appData: __wxAppData, sdkName: "send_app_data"}) 代码还原
        __wxAppData = {
            'pages/page1/page1': alldata
        }
        e = { appData: __wxAppData, sdkName: "send_app_data" }

        var postdata = JSON.parse(JSON.stringify(e)); // 第二次 JSON.stringify 第一次 JSON.parse
        window.postMessage({
            postdata
        }, "*");
    }


    // sendMsgToNW({appData: __wxAppData, sdkName: "send_app_data"}) 代码还原
    e = {
        eventName: type,
        data: e[1],
        webviewIds: [0],
        sdkName: 'publish'
    };

    var postdata = JSON.parse(JSON.stringify(e));  // 第三次 JSON.stringify 第二次 JSON.parse
    window.postMessage({
        postdata
    }, "*");
}

setData 运行的流程如下:

从上面代码以及流程图中可以看出,在一次setData({a: 1})作时,会进行三次 JSON.stringify,二次JSON.parse以及两次window.postMessage操作。并且在第一次window.postMessage时,并不是单单只处理传递的{a:1},而是处理当前页面的所有 data 数据。因此可想而知每次setData操作的开销是非常大的,只能通过减少数据量,以及减少setData操作来规避。

setData 相近的是 React 的 setState 方法,同样是使用 setState 去更新视图的,可以通过源码 React:L199 看到 setState 的关键代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function enqueueUpdate(component) {
  ensureInjected();
  if (!batchingStrategy.isBatchingUpdates) {
    batchingStrategy.batchedUpdates(enqueueUpdate, component);
    return;
  }
  dirtyComponents.push(component);
}

setState的工作流程如下:

可以看出,setState 加入了一个缓冲列队,在同一执行流程中进行多次 setState 之后也不会重复渲染视图,这就是一种很好的优化方式。

实验

为了证实setData的性能问题,可以写简单的测试例子去测试:

动态绑定1000条数据的列表进行性能测试,这里测试了三种情况:

  • 最优绑定: 在内存中添加完毕后最后执行setData操作。
  • 最差绑定: 在添加一条记录执行一次setData操作。
  • 最智能绑定:不管中间进行了什么操作,在运行结束时执行一次脏检查,对需要设置的数据进行setData操作。

参考代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// page1.wxml
<view bindtap="worse">
  <text class="user-motto">worse数据绑定测试</text>
</view>
<view bindtap="best">
  <text class="user-motto">best数据绑定测试</text>
</view>
<view bindtap="digest">
  <text class="user-motto">digest数据绑定测试</text>
</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 (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);
}

在经过十次刷新运行测试后得出以下结果:

实现同样的逻辑,性能数据却相差40倍左右。由此可以看出,在开发过程中,一定要避免同一流程内多次 setData 操作。

优化

在开发时,避免在同一流程内多次使用setData当然是最佳实践。采取人工维护肯定是能够实现的,就好比能用原生 js 能写出比众多框架更高效的性能一样。但当页面逻辑负责起来之后,花很大的精力去维护都不一定能保证每个流程只存在一次setData,而且可维护性也不高。因此,WePY选择使用脏检查去做数据绑定优化。用户不用再担心在我的流程里,数据被修改了多少次,只会在流程最后做一次脏检查,并且按需执行setData。

脏检测机制借鉴自AngularJS,多数人一听到脏检查都会觉得是低效率的一种作法,认为使用 Vue.js 中的 getter,setter更高效。其实不然,两种机制都是对同一件事的不同实现方式。各有优劣,取决于使用的人在使用过程中是否正好放大了机制中的劣势面。

WePY 中的 setData 就好比是一个 setter,在每次调用时都会去渲染视图。因此如果再封装一层 getter、setter 就完全没有意义,没有任何优化可言。这也就是为什么一个类 Vue.js 的小程序框架却选择了与之相反的另外一种数据绑定方式。

再回来看脏检查的问题在哪里,从上面实验的代码可以看出,脏检查的性能问题在于每次进行脏检查时,需要遍历所以数据并且作值的深比较,性能取决于遍历以及比较数据的大小。WePY 中深比较是使用的 underscore 的 isEqual 方法。为了验证效率问题,使用不同的比较方法对一个 16.7 KB 的复杂 JSON 数据进行深比较,测试用例请看这里:deep-compare-test-case

得到的结果如下:

从结果来看,对于一个 16.7 KB 的数据深比较是完全不足以产生性能问题的。那 AngularJS 1.x 脏检查的性能问题是怎么出现的呢?

AngularJS 1.x 中没有组件的概念,页面数据就位于 controller 的 \$scope 当中。每一次脏检查都是从 \$rootScope 开始,随后遍历至所有子 \$scope。参考这里 angular.js:L1081。对于一个大型的单页应用来说,所有 \$scope 中的数据可能达到了上百甚至上千个都有可能。那时,脏检查的每次遍历就可能真的会成为了性能的瓶颈了。

反观 WePY,使用类似于 Vue.js 的组件化开发,在抛开父子组件双向绑定通信的情况下,组件的脏检查仅针对组件本身的数据进行,一个组件的数据通常不会太多,数据太多时可以细化组件划分的粒度。因此在这种情况下,脏检查并不会导致性能问题。

其实,在很多情况下,框架封装的解决方案都不是性能优化的最优解决方案,使用原生肯定能优化出更快的代码。但它们之所以存在并且有价值,那都是因为它们是在性能、开发效率、可维护性上寻找到一个平衡点,这也是为什么 WePY 选择使用脏检查作为数据绑定的优化。

其它优化

除了以上两点是基于性能上做出的优化以外,WePY 也作出了一系列开发效率上的优化。因为在我之前的文章里都有详细说明,所以在这里就简单列举一下,不做深入探讨。详情可以参看 WePY 文档。

组件化开发

支持组件循环、嵌套,支持组件 Props 传值,组件事件通信等等。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
parent.wpy
<child :item.sync="myitem" />

<repeat for="{{list}}" item="item" index="index">
   <item :item="item" />
</repeat>

支持丰富的编译器

js 可以选择用 Babel 或者 TypeScript 编译。

wxml 可以选择使用 Pug(原Jade)。

wxss 可以选择使用 Less、Sass、Styus。

支持丰富的插件处理

可以通过配置插件对生成的js进行压缩混淆,压缩图片,压缩 wxml 和 json 已节省空间等等。

支持 ESLint 语法检查

添加一行配置就可以支持 ESLint 语法检查,可以避免低级语法错误以及统一项目代码的风格。

生命周期优化

添加了 onRoute 的生命周期。用于页面跳转后触发。 因为并不存在一个页面跳转事件(onShow 事件可以用作页面跳转事件,但同时也存在负作用,比如按 HOME 键后切回来,或者拉起支付后取消,拉起分享后取消都会触发 onShow 事件)。

支持 Mixin 混合

可以灵活的进行不同组件之间的相同功能的复用。参考 Vue.js 官方文档: 混合

优化事件,支持自定义事件

bindtap="tap"简写为 @tap="tap",catchtap="tap"简写为@tap.stop="tap"。

对于组件还提供组件自定义事件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<child @myevent.user="someevent" />

优化事件传参

官方版本如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<view data-alpha-beta="1" data-alphaBeta="2" bindtap="bindViewTap"> DataSet Test </view>
Page({
  bindViewTap:function(event){
    event.target.dataset.alphaBeta === 1 // - 会转为驼峰写法
    event.target.dataset.alphabeta === 2 // 大写会转为小写
  }
})

优化后:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<view @tap="bindViewTap("1", "2")"> DataSet Test </view>

methods: {
  bindViewTap(p1, p2, event) {
    p1 === "1";
    p2 === "2";
  }
}

结束语

小程序还存在很多值得开发者去探索优化的地方,欢迎大家与我探讨交流开发心得。若本文存在不准确的地方,欢迎批评指正。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
Skywalking微服务监控分析
微服务框架落地后,分布式部署架构带来的问题就会迅速凸显出来。服务之间的相互调用过程中,如果业务出现错误或者异常,如何快速定位问题?如何跟踪业务调用链路?如何分析解决业务瓶颈?...本文我们来看看如何解决以上问题。
yuanyi928
2019/03/07
3K1
实现全链路监控平台很难吗?Pinpoint、SkyWalking、Zipkin 选型对比
随着微服务架构的流行,服务按照不同的维度进行拆分,一次请求往往需要涉及到多个服务。互联网应用构建在不同的软件模块集上,这些软件模块,有可能是由不同的团队开发、可能使用不同的编程语言来实现、有可能布在了几千台服务器,横跨多个不同的数据中心。因此,就需要一些可以帮助理解系统行为、用于分析性能问题的工具,以便发生故障的时候,能够快速定位和解决问题。
java进阶架构师
2021/05/08
1.6K0
实现全链路监控平台很难吗?Pinpoint、SkyWalking、Zipkin 选型对比
一文读懂微服务监控之分布式追踪
现在越来越多的应用迁移到基于微服务的云原生的架构之上,微服务架构很强大,但是同时也带来了很多的挑战,尤其是如何对应用进行调试,如何监控多个服务间的调用关系和状态。如何有效的对微服务架构进行有效的监控成为微服务架构运维成功的关键。用软件架构的语言来说就是要增强微服务架构的可观测性(Observability)。
yuanyi928
2019/08/08
1.1K0
一文读懂微服务监控之分布式追踪
几款符合 OpenTracing 规范的分布式链路追踪组件介绍与选型
Tracing 是在上世纪 90 年代就已出现的技术,但真正让该领域流行起来的还是源于 Google 的一篇 Dapper 论文。分布式追踪系统发展很快,种类繁多,但无论哪种组件,其核心步骤一般有 3 步:代码埋点、数据存储和查询展示,如下图所示为链路追踪组件的组成。
aoho求索
2021/01/28
9.3K1
几款符合 OpenTracing 规范的分布式链路追踪组件介绍与选型
得物云原生全链路追踪Trace2.0-采集篇
2020年3月,得物技术团队在三个月的时间内完成了整个交易体系的重构,交付了五彩石项目,业务系统也进入了微服务时代。系统服务拆分之后,虽然每个服务都会有不同的团队各司其职,但服务之间的依赖也变得复杂,对服务治理等相关的基础建设要求也更高。
得物技术
2022/12/08
1.3K0
得物云原生全链路追踪Trace2.0-采集篇
架构师——复盘落地全链路监控项目
记一次完整的落地全链路监控项目的完整过程,我们来一起复盘下,我是如何进行技术选型的。
35岁程序员那些事
2022/09/23
1.4K0
架构师——复盘落地全链路监控项目
拥抱 Agent,“0” 代码玩转 Trace 之 OpenTelemetry 系列第二弹!
自2006年以来,曾就职于SonyEricsson、SAP等多家公司,历任软件开发工程师,数据开发工程师,解决方案架构师
腾讯云中间件团队
2021/03/24
1.6K0
拥抱 Agent,“0” 代码玩转 Trace 之 OpenTelemetry 系列第二弹!
快速学习-Skywalking原理
上文中我们知道,要使用Skywalking去监控服务,需要在其 VM 参数中添加 “- javaagent:/usr/local/skywalking/apache-skywalking-apm-bin/agent/skywalking-agent.jar"。这里就 使用到了java agent技术。
cwl_java
2020/08/10
2.8K0
快速学习-Skywalking原理
分布式链路追踪要怎么玩?
最近公司服务出现了一个bug,问题一直没有查出来在哪里,主要是某个接口调用两个应用的日志输出都没有问题,并且在整个请求链路较长,仅仅定位这个问题就定位了很久,效率奇低,于是'在moon的强烈要求下',准备在各服务接入分布式链路追踪框架了。
moon聊技术
2021/07/28
5630
分布式链路追踪要怎么玩?
全链路追踪在腾讯云的落地思考与实践
随着微服务以及容器技术的发展,系统软件的构建方式也随之发生了改变,微服务调用关系错综复杂,传统的监控方案很难满足当下应用场景的需求,指标、链路追踪以及日志目前已经成为了云原生应用的“必备品”,当把它们集成在一起时,需要拥有一个更加成熟的现代化可观测体系来支撑,以便了解应用系统内发生的事情。通过可观测性体系的建立,我们可以更好的去洞察监控数据,从而能够更快速的做问题定界以及根因定位,降低 MTTR。
腾讯云可观测平台
2024/01/03
8191
全链路追踪在腾讯云的落地思考与实践
冷门instrument包,功能d炸天
5版本以后,jdk有一个包叫做instrument,能够实现一些非常酷的功能。市面上一些APM工具,就是通过它来进行的增强。
xjjdog
2019/07/10
8210
冷门instrument包,功能d炸天
锅总浅析链路追踪技术
链路追踪是什么?常用的链路追踪工具有哪些?它们的异同、架构、工作流程及关键指标有哪些?希望读完本文能帮您解答这些疑惑!
锅总
2024/07/31
1470
锅总浅析链路追踪技术
Skywalking 链路追踪
APM(Application Performance Monitoring)即应用性能管理系统,是对企业系统即时监控以实现对应用程序性能管理和故障管理的系统化的解决方案。应用性能管理,主要指对企业的关键业务应用进行检测、优化、提高企业应用的可靠性和质量,保证用户得到良好的服务,降低 IT拥有的成本。APM系统是可以帮助理解系统行为、用于分析性能问题的工具,以便发生故障的时候,能够快速定位和解决问题**。**
Java架构师必看
2021/04/25
2.4K0
Skywalking 链路追踪
【云原生安全】从分布式追踪看云原生应用安全
在基于微服务的云原生架构中,客户端的一次服务调用,会产生包括服务和中间件在内的众多调用关系。对这些大量复杂的调用过程进行追踪,对于微服务的安全性分析、故障定位、以及性能提升等,有着重要的作用。
绿盟科技研究通讯
2020/12/30
1K0
【云原生安全】从分布式追踪看云原生应用安全
分布式系统架构6:链路追踪
在复杂的分布式系统中,系统通常由多个独立的服务组成,几乎每一个前端请求都会形成一个复杂的分布式服务调用链路。
卷福同学
2025/01/01
1280
分布式系统架构6:链路追踪
有赞全链路追踪实践
在企业级业务系统日趋复杂的背景下,微服务架构逐渐成为了许多中大型企业的标配,它将庞大的单体应用拆分成多个子系统和公共的组件单元。这一理念带来了许多好处:复杂系统的拆分简化与隔离、公共模块的重用性提升与更合理的资源分配、大大提升了系统变更迭代的速度、更灵活的可扩展性以及在云计算中的适用性,等等。
有赞coder
2020/08/24
1.2K0
有赞全链路追踪实践
监控系统-OpenTracing
在all in拥抱云原生的大环境中,分布式系统已经成为标配,传统的服务器逐渐弹性化,上层接触到的跟多的是虚拟资源模式。然而,随着系统规模和复杂度的增加,分布式系统中的问题变得越来越难以排查和修复。在这种情况下,分布式追踪技术成为了必不可少的工具,以帮助开发者理解系统行为和性能,并快速识别和解决问题。
五分钟学SRE
2023/12/05
3930
监控系统-OpenTracing
054. SkyWalking
1. APM系统 ---- 1.1. APM系统概述 APM (Application Performance Management) 即应用性能管理系统,是对企业系统即时监控以实现对应用程序性能管理和故障管理的系统化的解决方案。应用性能管理,主要指对企业的关键业务应用进行监测、优化,提高企业应用的可靠性和质量,保证用户得到良好的服务,降低 IT 总拥有成本。 APM系统是可以帮助理解系统行为、用于分析性能问题的工具,以便发生故障的时候,能够快速定位和解决问题。 1.2. 分布式链路追踪 随着分布式系统和微
山海散人
2021/03/03
1.9K0
054. SkyWalking
[业界方案]用Jaeger来学习分布式追踪系统Opentracing
笔者之前有过zipkin的经验,希望扩展到Opentracing,于是在学习Jaeger基础上总结出此文,与大家分享。
罗西的思考
2020/09/16
2.2K0
Skywalking Tracing 的接入和使用 —— Trace 之 OpenTelemetry 系列第三弹
导读 然后我们就进入标准的实操阶段,市面上有3个非常受欢迎的包含tracing的项目,skywalking,zipkin和jaeger。这篇文章希望通过解释skywalking的接入流程,让读者了解产品的设计,交互体验和提出一些自己的想法。如果有什么想法和建议,欢迎在评论区告诉我们。 作者介绍 徐为 腾讯云微服务团队高级解决方案构架师 毕业于欧盟 Erasmus Mundus IMMIT,获得经济和IT管理硕士学位 自2006年以来,曾就职于SonyEricsson、SAP等多家公司,历任软件
腾讯云中间件团队
2021/04/21
5.1K0
相关推荐
Skywalking微服务监控分析
更多 >
LV.0
苏州特瑞特软件开发工程师
目录
  • 导语
  • 预先加载
    • 原理
    • 试验
    • 优化
  • 数据绑定
    • 原理
    • 优化
  • 其它优化
    • 组件化开发
    • 支持丰富的编译器
    • 支持丰富的插件处理
    • 支持 ESLint 语法检查
    • 生命周期优化
    • 支持 Mixin 混合
    • 优化事件,支持自定义事件
    • 优化事件传参
  • 结束语
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档