Heim  >  Artikel  >  WeChat-Applet  >  Zeichnen Sie eine Übung auf und sehen Sie, wie Sie die Warenkorbanimation des Miniprogramms optimieren können

Zeichnen Sie eine Übung auf und sehen Sie, wie Sie die Warenkorbanimation des Miniprogramms optimieren können

青灯夜游
青灯夜游nach vorne
2021-12-28 10:21:492312Durchsuche

In diesem Artikel erfahren Sie, wie Sie die Miniprogramm-Animation optimieren und erfahren, wie Sie die Miniprogramm-Warenkorbanimation optimieren können.

Zeichnen Sie eine Übung auf und sehen Sie, wie Sie die Warenkorbanimation des Miniprogramms optimieren können

Einkaufswagen-Animationsoptimierung des Miniprogramms

Wenn das Miniprogramm des Unternehmens klickt, um einen Kauf hinzuzufügen, wird eine parabolische Animation gezeichnet, die die berechneten Koordinaten jedes Punktes auf der Bezier-Kurve darstellt wird dann von js durchquert Punktkoordinaten, und legen Sie dann den Punktstil dynamisch fest, um eine Animation zu erreichen. Dies führt jedoch zum Problem hängender und ausgelassener Frames

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

Vorausgesetzte Kenntnisse: Ereignisschleife, Aufgabe, Mikroaufgabe, UI-Rendering

Javascript ist eine Single-Threaded-Sprache, was bedeutet, dass alle Aufgaben ausgeführt werden müssen in der Warteschlange. Es gibt zwei Arten von Aufgaben: eine ist eine synchrone Aufgabe (synchron) und die andere ist eine asynchrone Aufgabe (asynchron). Synchrone Aufgaben beziehen sich auf Aufgaben, die zur Ausführung im Hauptthread eingereiht werden. Die nächste Aufgabe kann erst ausgeführt werden, nachdem die vorherige Aufgabe ausgeführt wurde. Erst wenn die „Aufgabenwarteschlange“ dem Hauptthread mitteilt, dass eine asynchrone Aufgabe ausgeführt werden kann, gelangt die Aufgabe zur Ausführung in den Hauptthread.

Asynchrone Aufgaben werden in Makroaufgaben (Task) und Mikroaufgaben (Micro Task) unterteilt. Ebenso werden Aufgabenwarteschlangen in Makroaufgabenwarteschlangen und Mikroaufgabenwarteschlangen unterteilt.

Grobe Schritte der Ereignisschleife:

  • Alle Synchronisierungsaufgaben werden im Hauptthread ausgeführt und bilden einen Ausführungskontextstapel.

  • Solange die asynchrone Aufgabe ein laufendes Ergebnis hat, wird ein Ereignis in die Aufgabenwarteschlange gestellt.

  • Nachdem die Makroaufgaben im Ausführungsstapel ausgeführt wurden, liest die Engine zunächst die Mikroaufgaben und schiebt sie in den Ausführungsstapel. Nachdem die Ausführung abgeschlossen ist, lesen Sie weiter mit der nächsten Mikroaufgabe. Wenn während der Ausführung eine neue Mikrotask generiert wird, wird diese Mikrotask in die Mikrotask-Warteschlange verschoben. Wenn der Hauptthread die Ausführung aller Aufgaben in der Mikrotask-Warteschlange abgeschlossen hat, liest er die Makrotask-Warteschlange und schiebt sie in den Ausführungsstapel.

  • Der Hauptthread wiederholt immer wieder den dritten Schritt oben.

Allgemeine Makroaufgaben:

  • setTimeout
  • setInterval
  • postMessage
  • ...

Allgemeine Mikroaufgaben:

  • Promise
  • MutationObserver

Die Beziehung zwischen der Ereignisschleife und dem UI-Rendering von Wollstoff ? Tatsächlich entscheidet der Browser, ob Rendering-Updates durchgeführt werden, nachdem alle Mikrotasks in der Mikrotask-Warteschlange ausgeführt wurden.

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

Zeichnen Sie eine Übung auf und sehen Sie, wie Sie die Warenkorbanimation des Miniprogramms optimieren können

// 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)
};

Zeichnen Sie eine Übung auf und sehen Sie, wie Sie die Warenkorbanimation des Miniprogramms optimieren können

Wir wissen, dass die Bildrate des Browsers unter normalen Umständen 60 fps beträgt, d. h. die Zeit eines Frames beträgt ungefähr 16,66 ms. Wenn der Dom in einem Frame zweimal geändert wird, verwendet der Browser zum Rendern nur den zuletzt geänderten Wert.

// 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);
};

Zeichnen Sie eine Übung auf und sehen Sie, wie Sie die Warenkorbanimation des Miniprogramms optimieren können

Versuchen Sie, setInterval nicht zu verwenden

Wie oben zu sehen ist, ist setInterval eine Makroaufgabe, die in jedem definierten Zeitintervall eine Rückruffunktion an die Makroaufgabenwarteschlange sendet Der Hauptthread liest das Makro. Die Rückruffunktion setInterval wird in der Aufgabenwarteschlange ausgeführt. Wenn im Hauptthread jedoch eine lange Aufgabe ausgeführt wird, blockiert er das Lesen und setzt den Lesevorgang erst fort, wenn die Aufgabe im Hauptthread ausgeführt wird. Der setInterval-Vorgang zum Hinzufügen einer Rückruffunktion zur Makroaufgabenwarteschlange wird jedoch nicht gestoppt. In diesem Fall führt dies dazu, dass das Zeitintervall zwischen der Funktionsausführung viel größer ist als das von uns definierte Zeitintervall.

Das Folgende ist ein Beispiel. Jeder Rückruf von setInterval erfordert viele Berechnungen, wodurch der Hauptthread blockiert wird eine bestimmte Zeitintervall-Push-Ereignis-Rückruffunktion. Die Rückruffunktion wird nur ausgeführt, wenn der Hauptthread inaktiv ist, die meisten dieser Rückruffunktionen sind jedoch veraltet.

Wenn das Rückrufintervall von setInterval kürzer ist als die Zeit, die der Browser zum Rendern eines Frames benötigt, wird die Rückruffunktion mehrmals ausgeführt, es wird jedoch nur das letzte Ergebnis verwendet, was ebenfalls zu Verschwendung führt und möglicherweise sogar blockiert der Hauptthread. Zeichnen Sie eine Übung auf und sehen Sie, wie Sie die Warenkorbanimation des Miniprogramms optimieren können

Versuchen Sie also, setTimeout anstelle von setInterval zu verwenden.

  • Verwenden Sie requestAnimationFrame.

Wenn Sie js zum Zeichnen von Animationen verwenden, verwenden Sie den offiziell empfohlenen requestAnimationFrame anstelle von setTimeout.

Teilen Sie dem Browser mit, dass Sie eine Animation ausführen möchten, und bitten Sie den Browser, die angegebene Rückruffunktion aufzurufen, um die Animation vor dem nächsten Neuzeichnen zu aktualisieren

由上面的例子可知,两个宏任务之间不一定会触发浏览器渲染,这个由浏览器自己决定,并且浏览器的帧率并会一直是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();
};

Zeichnen Sie eine Übung auf und sehen Sie, wie Sie die Warenkorbanimation des Miniprogramms optimieren können

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

小程序上的动画优化

小程序是双线程架构

Zeichnen Sie eine Übung auf und sehen Sie, wie Sie die Warenkorbanimation des Miniprogramms optimieren können

好处是: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;
    })
  }
}

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

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

Das obige ist der detaillierte Inhalt vonZeichnen Sie eine Übung auf und sehen Sie, wie Sie die Warenkorbanimation des Miniprogramms optimieren können. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:juejin.cn. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen