前端星2020_4_11課程筆記

前端工程化

  • 規範化

    • 流程控制 git git flow

    • 編寫規範

  • 模塊化

    核心需求 避免變量污染前端

    • CSS模塊化
    • JS模塊化
  • 組件化

    對於UI和邏輯的封裝webpack

  • 自動化

    將重複費時的操做交給工具git

    • 初始化 cli
    • 構建 webpack
    • 測試 jest
    • 部署 jenkins

JS動畫

  • js的原生接口Animation
  • 月影介紹的各類原生實現 固然會更靈活 由於本質就是代碼實現數學公式QAQ 原本不想抄下來 可是聽說要回收課程資格5555 抄一份當手冊好了

通用的抽象接口 線性++:web

function update({target}, count) {
  target.style.transform = `rotate(${count++}deg)`;
}

class Ticker {
  tick(update, context) {
    let count = 0;
    requestAnimationFrame(function next() {
      if(update(context, ++count) !== false) {
        requestAnimationFrame(next);
      }
    });
  }
}

const ticker = new Ticker();
ticker.tick(update, {target: block});

通用的抽象接口 角度 時間:chrome

function update({target}, {time}) {
  target.style.transform = `rotate(${360 * time / 2000}deg)`;
}

class Ticker {
  tick(update, context) {
    let count = 0;
    let startTime = Date.now();
    requestAnimationFrame(function next() {
      count++;
      const time = Date.now() - startTime;
      if(update(context, {count, time}) !== false) {
        requestAnimationFrame(next);
      }
    });
  }
}

const ticker = new Ticker();
ticker.tick(update, {target: block})

通用的接口 canvas:canvas

function update({context}, {time}) {
  context.clearRect(0, 0, 512, 512);
  context.save();
  context.translate(100, 100);
  context.rotate(time * 0.005);
  context.fillStyle = '#00f';
  context.fillRect(-50, -50, 100, 100);
  context.restore();
}

class Ticker {
  tick(update, context) {
    let count = 0;
    let startTime = Date.now();
    requestAnimationFrame(function next() {
      count++;
      const time = Date.now() - startTime;
      if(update(context, {count, time}) !== false) {
        requestAnimationFrame(next);
      }
    });
  }
}

Timing 的實現:前端工程化

class Timing {
  constructor({duration, easing} = {}) {
    this.startTime = Date.now();
    this.duration = duration;
    this.easing = easing || function(p){return p};
  }
  get time() {
    return Date.now() - this.startTime;
  }
  get p() {
    return this.easing(Math.min(this.time / this.duration, 1.0));
  }
}

class Ticker {
  tick(update, context, timing) {
    let count = 0;
    timing = new Timing(timing);
    requestAnimationFrame(function next() {
      count++;
      if(update(context, {count, timing}) !== false) {
        requestAnimationFrame(next);
      }
    });
  }
}

後面的具體例子就是數學公式結合前面的通用接口,找幾個例子來記一下promise

貝塞爾軌跡:瀏覽器

avatra

function bezierPath(x1, y1, x2, y2, p) {
  const x = 3 * x1 * p * (1 - p) ** 2 + 3 * x2 * p ** 2 * (1 - p) + p ** 3;
  const y = 3 * y1 * p * (1 - p) ** 2 + 3 * y2 * p ** 2 * (1 - p) + p ** 3;
  return [x, y];
} //軌跡的數學公式

function update({target}, {timing}) {
  const [px, py] = bezierPath(0.2, 0.6, 0.8, 0.2, timing.p);
  target.style.transform = `translate(${100 * px}px, ${100 * py}px)`;
}

const ticker = new Ticker();
ticker.tick(update, {target: block}, {
  duration: 2000,
  easing: p => p * (2 - p),
});

週期運動:實際上週期運動的timing發生了變化性能優化

class Timing {
  constructor({duration, easing, iterations = 1} = {}) {
    this.startTime = Date.now();
    this.duration = duration;
    this.easing = easing || function(p){return p};
    this.iterations = iterations;
  }
  get time() {
    return Date.now() - this.startTime;
  }
  get finished() {
    return this.time / this.duration >= 1.0 * this.iterations;
  }
  get op() {
    let op = Math.min(this.time / this.duration, 1.0 * this.iterations);
    if(op < 1.0) return op;
    op -= Math.floor(op);
    return op > 0 ? op : 1.0;
  }
  get p() {
    return this.easing(this.op);
  }
}

用promise來寫連續運動Ticker 其實目標就是使用promise作流程控制

class Ticker {
  tick(update, context, timing) {
    let count = 0;
    timing = new Timing(timing);
    return new Promise((resolve) => {
      requestAnimationFrame(function next() {
        count++;
        if(update(context, {count, timing}) !== false && !timing.finished) {
          requestAnimationFrame(next);
        } else {
          resolve(timing);
        }
      });      
    });
  }
}

下面就是上面promise trick的應用 小球彈跳

const down = lerp(setValue, {top: 100}, {top: 300});
const up = lerp(setValue, {top: 300}, {top: 100});

(async function() {
  const ticker = new Ticker();

  // noprotect
  while(1) {
    await ticker.tick(down, {target: block},
      {duration: 2000, easing: p => p * p});
    await ticker.tick(up, {target: block},
      {duration: 2000, easing: p => p * (2 - p)});
  }
})();

前端性能優化

1. 性能評估方法

RAIL模型
關鍵指標:

  • 100ms內響應用戶輸入 Response
  • 10ms 動畫一幀 Animation
  • 主線程空閒時間最大化 Idle
  • 1000ms交互內容展示 Load
    chrome DevTools

2. 實際例子

針對瀏覽器渲染流程:頁面是怎麼樣展現出來的?

JS->Style(這一步的輸出是渲染樹)->Layout(計算 產出盒模型)->paint(柵格化)->Composite(渲染層合併)

Layout 和 paint 是能夠不出現的 因此會有各類場景

  • 火焰圖的使用
  • 加載優化

    • 資源效率優化
    • 圖片優化
    • 字體優化
    • 關鍵渲染路徑優化
  • 渲染優化

    • JS執行優化
    • 避免大型複雜佈局
    • 渲染層合併
相關文章
相關標籤/搜索