Home > Article > WeChat Applet > Record a practice and see how to optimize the shopping cart animation of the mini program
This article will share with you a mini program animation optimization practice and see how to optimize the mini program shopping cart animation. I hope it will be helpful to everyone!
When the company’s mini-program clicks to add a purchase, a parabolic animation will be drawn. This parabolic animation is calculated The coordinates of each point on the Bezier curve are traversed by js, and then the point style is dynamically set to achieve animation. But this will bring about the problem of stuck and dropped frames
this.goodBoxTimer = setInterval(() => { index-- this.setData({ 'movingBallInfo.posX': linePos[index][0], 'movingBallInfo.posY': linePos[index][1], }) if (index < 1) { this.resetGoodBoxStatus() } }, 30)
Prerequisite knowledge: Event Loop, Task, micro Task, UI Rendering
Javascript is a single-threaded language, which means that all tasks must be queued. There are two types of tasks: one is synchronous task (synchronous) and the other is asynchronous task (asynchronous). Synchronous tasks refer to tasks queued for execution on the main thread. The next task can only be executed after the previous task has been executed. Asynchronous tasks refer to tasks that do not enter the main thread but enter the "task queue". Task, only when the "task queue" notifies the main thread that an asynchronous task can be executed, will the task enter the main thread for execution.
Asynchronous tasks are divided into macro tasks (Task) and micro tasks (micro Task). Similarly, task queues are also divided into macro task queues and micro task queues.
Event Loop Rough steps:
All synchronization tasks are executed on the main thread, forming an execution context stack.
As long as the asynchronous task has a running result, an event is placed in the task queue.
After the macro tasks in the execution stack are executed, the engine will first read the micro tasks and push them into the execution stack. After the execution is completed, continue reading the next microtask. If a new microtask is generated during execution, this microtask will be pushed into the microtask queue. If the main thread finishes executing all the tasks in the microtask queue, it will read the macrotask queue and push it into the execution stack.
The main thread keeps repeating the third step above.
Common macro tasks:
Common microtasks:
And what is the relationship between Event Loop and UI rendering? In fact, after all microtasks in the microtask queue are executed, the browser decides whether to perform rendering updates.
// demo1 // 渲染发生在微任务之后 const con = document.getElementById('con'); con.onclick = function () { Promise.resolve().then(function Promise1 () { con.textContext = 0; }) };
// 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) };
We know that the frame rate of the browser under normal circumstances is 60fps, that is, the time of one frame is approximately 16.66ms. If the Dom is modified twice in one frame, the browser will only use the last modified value to render.
// 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); };
Try not to use setInterval
It can be seen from the above that setInterval is a macro task, setInterval every The defined time interval will push the callback function to the macro task queue, and then the main thread will read the setInterval callback function in the macro task queue and execute it. However, if the main thread has a long task executing, the reading will be blocked and the reading will not continue until the task in the main thread is executed. However, the setInterval operation of adding a callback function to the macro task queue will not stop. In this case, it will cause: the time interval between function execution is much larger than the time interval we defined.
The following is an example. Each setInterval callback requires a large amount of calculations, which blocks the main thread.
// 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 > 5) clearInterval(timer) // 10000000 // 100000 for (let i = 0; i < 100000; i++) { sum+= i } }, 100) last = new Date().getTime() }
Disadvantages of setInterval:
So try to use setTimeout instead of setInterval
Use requestAnimationFrame
If you use js to draw animation, Still use the officially recommended requestAnimationFrame instead of setTimeout.
window.requestAnimationFrame()
Tell the browser that you want to perform an animation and ask the browser to call the specified callback function to update the animation before the next redraw
由上面的例子可知,两个宏任务之间不一定会触发浏览器渲染,这个由浏览器自己决定,并且浏览器的帧率并会一直是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 < 5) {rAF(); i++;} }); }); } con.onclick = function () { rAF(); };
可以看到渲染了5次(五条竖直虚线)
小程序上的动画优化
小程序是双线程架构
好处是:ui渲染和js主线程是分开的,我们知道在浏览器中这两者是互斥的,所以当主线程有阻塞时,页面交互就会失去响应,而小程序中不会出现这样的情况。
坏处是:逻辑层、渲染层有通信延时,大量的通信也会造成性能瓶颈。
小程序提供了wxs用来处理渲染层的逻辑。
购物车抛物线动画优化
所以我们不应该用setInterval去执行动画,我们修改成,当点击加购时,把点击坐标与目标坐标传入wxs
,然后计算运行轨迹点的坐标计算,接着用requestAnimationFrame
执行动画帧
// wxs function executeCartAnimation () { curCoordIdx = coordArr.length - 1 ins.requestAnimationFrame(setStyleByFrame) } function setStyleByFrame() { if (curCoordIdx >= 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' }) } }
在真机上效果非常明显,低端安卓机上的动画也非常丝滑。但是录屏效果不好,这里就不放了。
【相关学习推荐:小程序开发教程】
The above is the detailed content of Record a practice and see how to optimize the shopping cart animation of the mini program. For more information, please follow other related articles on the PHP Chinese website!