当前位置: 代码网 > 移动>腾讯>微信 > 记录一次实践,看看小程序购物车动画怎么优化

记录一次实践,看看小程序购物车动画怎么优化

2025年03月31日 微信 我要评论
本篇文章给大家分享一次小程序动画优化实践,看看小程序购物车动画怎么优化,希望对大家有所帮助!小程序购物车动画优化公司小程序点击加购时,会绘制一个抛物线动画,这个抛物线动画是计算出来的贝塞尔曲线上每个点

本篇文章给大家分享一次小程序动画优化实践,看看小程序购物车动画怎么优化,希望对大家有所帮助!

记录一次实践,看看小程序购物车动画怎么优化

小程序购物车动画优化

公司小程序点击加购时,会绘制一个抛物线动画,这个抛物线动画是计算出来的贝塞尔曲线上每个点的坐标,再由js遍历点坐标,然后动态设置点的样式,从而实现动画。但这会带来卡顿掉帧问题
this.goodboxtimer = setinterval(() => {
  index--
  this.setdata({
    'movingballinfo.posx': linepos[index][0],
    'movingballinfo.posy': linepos[index][1],
  })
  if (index <p><span style="font-size: 16px;"><strong>前置知识:event loop, task, micro task, ui rendering</strong></span></p><p>javascript是单线程语言,这就意味着所有任务都要进行排队。任务分为两种:一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。</p><p>而异步任务又分为宏任务(task)和微任务(micro task),同理任务队列也分为宏任务队列和微任务队列。</p><p>事件循环(event loop) 大致步骤:</p>
登录后复制
  • 所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。

  • 只要异步任务有了运行结果,就在任务队列之中放置一个事件。

  • 执行栈中的宏任务执行完毕,引擎会先读取微任务,推入执行栈。执行完成之后,继续读取下一个微任务。如果执行过中产生新的微任务,就会把这个微任务推入微任务队列。如果主线程执行完所有微任务队列中的任务中时,就会去读取宏任务队列,推入执行栈。

  • 主线程不断重复上面的第三步。

常见的宏任务:

  • settimeout
  • setinterval
  • postmessage
  • ...

常见的微任务:

  • promise
  • mutationobserver

而event loop和ui渲染的关系呢?其实是在执行完微任务队列里所有微任务的之后,由浏览器决定是否进行渲染更新。

// demo1
// 渲染发生在微任务之后
const con = document.getelementbyid('con');
con.onclick = function () {
  promise.resolve().then(function promise1 () {
    con.textcontext = 0;
  })
};
登录后复制

1.png

// demo2
// 两次eventloop中间没有渲染
const con = document.getelementbyid('con');
con.onclick = function () {
  settimeout(function settimeout1() {
      con.textcontent = 0;
      promise.resolve().then(function promise1 () {
          console.log('promise1')
    })
  }, 0)
  settimeout(function settimeout2() {
    con.textcontent = 1;
    promise.resolve().then(function promise2 () {
        console.log('promise2')
    })
  }, 0)
};
登录后复制

2.png

我们知道浏览器正常情况下的帧率是60fps,即一帧的时间大约为16.66ms。如果在一帧里对dom进行了两次修改,那么浏览器只会取最后一次的修改值去渲染。

// demo3
// 两次eventloop中有渲染
const con = document.getelementbyid('con');
con.onclick = function () {
  settimeout(function  settimeout1() {
    con.textcontent = 0;
  }, 0);
  settimeout(function  settimeout2() {
    con.textcontent = 1;
  }, 16.7);
};
登录后复制

3.png

尽量不要使用setinterval

由上文可知setinterval是宏任务,setinterval每隔定义的时间间隔就会往宏任务队列推入回调函数,然后主线程会读取宏任务队列里的setinterval回调函数并执行。但是如果主线程有长任务(long task)执行时,会阻塞读取,直到主线程里的任务执行完才会继续读取,但setinterval往宏任务队列添加回调函数的操作是不会停止的,这种情况下就会造成:函数执行的时间间隔远大于我们定义的时间间隔。

下面是一个例子,每次setinterval回调都需要进行大量的计算,这样阻塞主线程

// demo4
const btn = document.getelementbyid('btn')
btn.addeventlistener('click', setintervalfn)
let sum = 0
function setintervalfn() {
  let last
  let countidx = 0
  const timer = setinterval(function timefn() {
    countidx++
    const newtime = new date().gettime()
    const gap = newtime - last
    last = newtime
    console.log('setinterval', gap, countidx)
    if (countidx &gt; 5) clearinterval(timer)
    // 10000000
    // 100000
    for (let i = 0; i <p><img src="https://img.php.cn/upload/image/176/431/251/1640657815926480.png" title="1640657815926480.png" alt="4.png"></p><p>setinterval的缺点:</p>
登录后复制
  • 当主线程有代码执行时,宏任务队列会一直按照一定的时间间隔推入事件回调函数。只有当主线程空闲时,才会把回调函数执行,但是这些回调函数大多都是过时的。
  • 如果setinterval的回调间隔比浏览器渲染一帧的时间要短,那么回调函数执行了多次,但只会用到最后一次的结果,这样也会造成浪费,甚至有可能会阻塞主线程。

所以尽量要用settimeout去代替setinterval

使用requestanimationframe

如果用js去绘制动画,还是用官方推荐的requestanimationframe,而不是settimeout。

window.requestanimationframe() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画

由上面的例子可知,两个宏任务之间不一定会触发浏览器渲染,这个由浏览器自己决定,并且浏览器的帧率并会一直是60fps,有时可能会下降到30fps,而settimeout的回调时间是写死的,就有可能导致修改了多次dom,而只触发了一次ui更新,造成掉帧。

// demo5
const con = document.getelementbyid('con');
let i = 0;
function raf(){
  requestanimationframe(function aaaa() {
    con.textcontent = i;
    promise.resolve().then(function bbbb(){
      if(i <p><img src="https://img.php.cn/upload/image/412/705/313/1640657854778507.png" title="1640657854778507.png" alt="5.png"></p><p>可以看到渲染了5次(五条竖直虚线)</p><p><span   style="max-width:90%"><strong>小程序上的动画优化</strong></span></p><p>小程序是双线程架构</p><p><img src="https://img.php.cn/upload/image/416/262/830/1640657858530582.png" title="1640657858530582.png" alt="6.png"></p><p>好处是:ui渲染和js主线程是分开的,我们知道在浏览器中这两者是互斥的,所以当主线程有阻塞时,页面交互就会失去响应,而小程序中不会出现这样的情况。</p><p>坏处是:逻辑层、渲染层有通信延时,大量的通信也会造成性能瓶颈。</p><p>小程序提供了wxs用来处理渲染层的逻辑。</p><p><span   style="max-width:90%"><strong>购物车抛物线动画优化</strong></span></p><p>所以我们不应该用setinterval去执行动画,我们修改成,当点击加购时,把点击坐标与目标坐标传入wxs,然后计算运行轨迹点的坐标计算,接着用requestanimationframe执行动画帧</p><pre class="brush:js;toolbar:false;">// wxs
function executecartanimation () {
  curcoordidx = coordarr.length - 1
  ins.requestanimationframe(setstylebyframe)
}

function setstylebyframe() {
  if (curcoordidx &gt;= 0) {
    ins.selectcomponent('.cart-animation').setstyle({
      display: 'block',
      left: coordarr[curcoordidx].x + 'px', 
      top: coordarr[curcoordidx].y + 'px'
    })
    curcoordidx -= 1
    ins.requestanimationframe(setstylebyframe)
  } else {
    ins.selectcomponent('.cart-animation').setstyle({
      display: 'none'
    })
  }
}
登录后复制

在真机上效果非常明显,低端安卓机上的动画也非常丝滑。但是录屏效果不好,这里就不放了。

【相关学习推荐:小程序开发教程】

以上就是记录一次实践,看看小程序购物车动画怎么优化的详细内容,更多请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com