Maison  >  Article  >  Applet WeChat  >  Enregistrez une pratique et voyez comment optimiser l'animation du panier du mini programme

Enregistrez une pratique et voyez comment optimiser l'animation du panier du mini programme

青灯夜游
青灯夜游avant
2021-12-28 10:21:492329parcourir

Cet article partagera avec vous une pratique d'optimisation de l'animation du mini-programme et verra comment optimiser l'animation du panier du mini-programme. J'espère qu'il sera utile à tout le monde !

Enregistrez une pratique et voyez comment optimiser l'animation du panier du mini programme

Optimisation de l'animation du panier d'achat du mini programme

Lorsque le mini programme de l'entreprise clique pour ajouter un achat, une animation parabolique sera dessinée. Cette animation parabolique correspond aux coordonnées calculées de chaque point de la courbe de Bézier, qui est. puis traversé par les coordonnées du point js, puis définissez dynamiquement le style du point pour réaliser l'animation. Mais cela entraînera le problème des images bloquées et perdues

this.goodBoxTimer = setInterval(() => {
  index--
  this.setData({
    'movingBallInfo.posX': linePos[index][0],
    'movingBallInfo.posY': linePos[index][1],
  })
  if (index < 1) {
    this.resetGoodBoxStatus()
  }
}, 30)

Connaissances préalables : boucle d'événement, tâche, micro-tâche, rendu de l'interface utilisateur

Javascript est un langage à thread unique, ce qui signifie que toutes les tâches doivent être en file d'attente. Il existe deux types de tâches : l'une est une tâche synchrone (synchrone) et l'autre est une tâche asynchrone (asynchrone). Les tâches synchrones font référence aux tâches mises en file d'attente pour exécution sur le thread principal. La tâche suivante ne peut être exécutée qu'après l'exécution de la tâche précédente. Les tâches asynchrones font référence aux tâches qui n'entrent pas dans le thread principal mais entrent dans la « file d'attente des tâches ». ce n'est que lorsque la « file d'attente des tâches » informe le thread principal qu'une tâche asynchrone peut être exécutée que la tâche entrera dans le thread principal pour être exécutée.

Les tâches asynchrones sont divisées en macro-tâches (Task) et micro-tâches (micro-tâches). De même, les files d'attente de tâches sont également divisées en files d'attente de macro-tâches et de micro-tâches.

Étapes grossières de la boucle d'événement :

  • Toutes les tâches de synchronisation sont exécutées sur le thread principal, formant une pile de contexte d'exécution.

  • Tant que la tâche asynchrone a un résultat en cours d'exécution, un événement est placé dans la file d'attente des tâches.

  • Une fois les macro-tâches de la pile d'exécution exécutées, le moteur lira d'abord les micro-tâches et les poussera dans la pile d'exécution. Une fois l'exécution terminée, continuez à lire la microtâche suivante. Si une nouvelle microtâche est générée lors de l'exécution, cette microtâche sera poussée dans la file d'attente des microtâches. Si le thread principal termine d'exécuter toutes les tâches de la file d'attente des microtâches, il lira la file d'attente des macrotâches et la poussera dans la pile d'exécution.

  • Le fil principal ne cesse de répéter la troisième étape ci-dessus.

Tâches de macro courantes :

  • setTimeout
  • setInterval
  • postMessage
  • ...

Micro-tâches courantes 

  • Promise
  • MutationObserver

La relation entre Event Loop et le rendu de l'interface utilisateur Tissu en laine ? En fait, une fois que toutes les microtâches de la file d'attente des microtâches sont exécutées, le navigateur décide s'il doit effectuer des mises à jour de rendu.

// demo1
// 渲染发生在微任务之后
const con = document.getElementById(&#39;con&#39;);
con.onclick = function () {
  Promise.resolve().then(function Promise1 () {
    con.textContext = 0;
  })
};

Enregistrez une pratique et voyez comment optimiser lanimation du panier du mini programme

// demo2
// 两次EventLoop中间没有渲染
const con = document.getElementById(&#39;con&#39;);
con.onclick = function () {
  setTimeout(function setTimeout1() {
      con.textContent = 0;
      Promise.resolve().then(function Promise1 () {
          console.log(&#39;Promise1&#39;)
    })
  }, 0)
  setTimeout(function setTimeout2() {
    con.textContent = 1;
    Promise.resolve().then(function Promise2 () {
        console.log(&#39;Promise2&#39;)
    })
  }, 0)
};

Enregistrez une pratique et voyez comment optimiser lanimation du panier du mini programme

Nous savons que la fréquence d'images du navigateur dans des circonstances normales est de 60 ips, c'est-à-dire que la durée d'une image est d'environ 16,66 ms. Si le Dom est modifié deux fois dans une image, le navigateur n'utilisera que la dernière valeur modifiée pour le rendu.

// demo3
// 两次eventloop中有渲染
const con = document.getElementById(&#39;con&#39;);
con.onclick = function () {
  setTimeout(function  setTimeout1() {
    con.textContent = 0;
  }, 0);
  setTimeout(function  setTimeout2() {
    con.textContent = 1;
  }, 16.7);
};

Enregistrez une pratique et voyez comment optimiser lanimation du panier du mini programme

Essayez de ne pas utiliser setInterval

Comme le montre ce qui précède, setInterval est une tâche macro, setInterval poussera une fonction de rappel dans la file d'attente des tâches macro à chaque intervalle de temps défini, puis la. le thread principal lira la macro. La fonction de rappel setInterval dans la file d'attente des tâches est exécutée. Cependant, si le thread principal a une longue tâche en cours d'exécution, la lecture sera bloquée et la lecture ne se poursuivra pas jusqu'à ce que la tâche dans le thread principal soit exécutée. Cependant, l'opération setInterval consistant à ajouter une fonction de rappel à la file d'attente des tâches de macro ne sera pas exécutée. stop Dans ce cas, cela provoquera : l'intervalle de temps entre l'exécution de la fonction est beaucoup plus grand que l'intervalle de temps que nous avons défini.

Ce qui suit est un exemple. Chaque rappel setInterval nécessite beaucoup de calculs, ce qui bloque le thread principal

// demo4
const btn = document.getElementById(&#39;btn&#39;)
btn.addEventListener(&#39;click&#39;, 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(&#39;setInterval&#39;, gap, countIdx)
    if (countIdx > 5) clearInterval(timer)
    // 10000000
    // 100000
    for (let i = 0; i < 100000; i++) {
      sum+= i
    }
  }, 100)
  last = new Date().getTime()
}

Enregistrez une pratique et voyez comment optimiser lanimation du panier du mini programme

Inconvénients de setInterval :

  • Lorsque le thread principal exécute du code, la file d'attente des tâches macro suivra toujours une certaine fonction de rappel d'événement push à intervalle de temps. La fonction de rappel ne sera exécutée que lorsque le thread principal est inactif, mais la plupart de ces fonctions de rappel sont obsolètes.
  • Si l'intervalle de rappel de setInterval est plus court que le temps nécessaire au navigateur pour restituer une image, alors la fonction de rappel est exécutée plusieurs fois, mais seul le dernier résultat sera utilisé, ce qui entraînera également du gaspillage et peut même bloquer le fil conducteur.

Alors essayez d'utiliser setTimeout au lieu de setInterval

Utilisez requestAnimationFrame

Si vous utilisez js pour dessiner des animations, utilisez le requestAnimationFrame officiellement recommandé au lieu de setTimeout.

window.requestAnimationFrame() Dites au navigateur que vous souhaitez effectuer une animation et demandez au navigateur d'appeler la fonction de rappel spécifiée pour mettre à jour l'animation avant le prochain redessin

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

// demo5
const con = document.getElementById(&#39;con&#39;);
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();
};

Enregistrez une pratique et voyez comment optimiser lanimation du panier du mini programme

可以看到渲染了5次(五条竖直虚线)

小程序上的动画优化

小程序是双线程架构

Enregistrez une pratique et voyez comment optimiser lanimation du panier du mini programme

好处是:ui渲染和js主线程是分开的,我们知道在浏览器中这两者是互斥的,所以当主线程有阻塞时,页面交互就会失去响应,而小程序中不会出现这样的情况。

坏处是:逻辑层、渲染层有通信延时,大量的通信也会造成性能瓶颈。

小程序提供了wxs用来处理渲染层的逻辑。

购物车抛物线动画优化

所以我们不应该用setInterval去执行动画,我们修改成,当点击加购时,把点击坐标与目标坐标传入wxs,然后计算运行轨迹点的坐标计算,接着用requestAnimationFrame执行动画帧

// wxs
function executeCartAnimation () {
  curCoordIdx = coordArr.length - 1
  ins.requestAnimationFrame(setStyleByFrame)
}

function setStyleByFrame() {
  if (curCoordIdx >= 0) {
    ins.selectComponent(&#39;.cart-animation&#39;).setStyle({
      display: &#39;block&#39;,
      left: coordArr[curCoordIdx].x + &#39;px&#39;, 
      top: coordArr[curCoordIdx].y + &#39;px&#39;
    })
    curCoordIdx -= 1
    ins.requestAnimationFrame(setStyleByFrame)
  } else {
    ins.selectComponent(&#39;.cart-animation&#39;).setStyle({
      display: &#39;none&#39;
    })
  }
}

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

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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer