360前端星—promise.all—0411

什么是前端工程化?:https://blog.csdn.net/qq_36934866/article/details/105458505

03 组件化

組件化和模块化的核心思想都在于分治,实际带来的好处就是团队协作效率和项目可维护性的提升。

什么是组件

  • UI为主:

    页面上的个UI块可以封装成一个组件。

  • 逻辑为主:

    某一个功能逻辑也可以封装成一个组件。

在WEB前端领域,我们可以将由特定逻辑和UI进行的高内聚,低耦合的封装体称为一个组件。

侧重UI进行封装的组件:代码结构清晰,组件内的模块就近放置,方便进行修改和维护。这种组件具备高内聚低耦合,但普适性不高。

侧重逻辑进行封装的组件:除了具备上述有点外,还具有很高的普适性。

组件内可以包含组件:比如偏UI的组件往往都是包含有逻辑的组件。

04 自动化

核心思想:能由机器自动完成的事情,绝不让人来做。自动化是前端工程化的核心。

  • 自动初始化:vue-cli

  • 自动构建:webpack

  • 自动测试:karma, jest

  • 自动部署: Jenkins

自动化测试

1.png

自动化部署

2.png

自动化构建

WEBPACK PARCEL

实例:360搜索专题页开发工具

写一个基于Node.js的CLI

3.png

如何捕获用户输入的是参数和命令,获得参数并出发回调?


const program = require('commander');

program.on('--help', =>{});

program.command('init').action((name, option) => {});

如何出发询问与用户交互?


const inquirer = require('inquirer');

inquirer.prompt({

    type: 'confirm',

    name: 'name',

    message: '是否将产品发布至线上?',

    default: true

}).then(answer => {...do sth...})

如何帮我们执行命令?如何帮我们发送HTTP请求?


const child_process = require('child_process');

const HTTP = require('http');

如何增强交互效果?


const chalk = require('chalk');

console.log(chalk.redBright('专题名称已被使用,请重新输入'));

const ora = require('ora');

const spinner = ora('正在加载中').start();

setTimeout(_=> {

    spinner.text = '加载完成';

    spinner.succeed();

}, 1000)

使用webpack4进行项目构建


module.exports = {

    mode: 'development',

    entry: {

        main: './src/main/js'

    },

    output: {

        path: path.resolve(__dirname, '../dist'),

        filename: '[name].js'

    },

    module: {

        rules: []

    },

    plugins: []

}
![4.png](https://upload-images.jianshu.io/upload_images/22890329-591f247e460ea30e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

前端动画

https://blog.csdn.net/xinyu_huo/article/details/105458676

椭圆轨迹:

代数方程:

image

参数方程:

image

周期运动:

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

  }

}

椭圆周期运动:

function update({target}, {timing}) {

  const x = 150 * Math.cos(Math.PI * 2 * timing.p);

  const y = 100 * Math.sin(Math.PI * 2 * timing.p);

  target.style.transform = `

    translate(${x}px, ${y}px)

  `;

}

const ticker = new Ticker();

ticker.tick(update, {target: block},

  {duration: 2000, iterations: 10});

连续运动:

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

        }

      });     

    });

  }

}
function left({target}, {timing}) {

  target.style.left = `${100 + 200 * timing.p}px`;

}

function down({target}, {timing}) {

  target.style.top = `${100 + 200 * timing.p}px`;

}

function right({target}, {timing}) {

  target.style.left = `${300 - 200 * timing.p}px`;

}

function up({target}, {timing}) {

  target.style.top = `${300 - 200 * timing.p}px`;

}

(async function() {

  const ticker = new Ticker();

  await ticker.tick(left, {target: block},

    {duration: 2000});

  await ticker.tick(down, {target: block},

    {duration: 2000});

  await ticker.tick(right, {target: block},

    {duration: 2000});

  await ticker.tick(up, {target: block},

    {duration: 2000});

})();

线性插值(lerp):

f(p) = from + (to - from) * p

f(p) = to * p + from * (1 - p)

function lerp(setter, from, to) {

  return function({target}, {timing}) {

    const p = timing.p;

    const value = {};

    for(let key in to) {

      value[key] = to[key] * p + from[key] * (1 - p);

    }

    setter(target, value);

  }

}

function setValue(target, value) {

  for(let key in value) {

    target.style[key] = `${value[key]}px`;

  }

}

const left = lerp(setValue, {left: 100}, {left: 300});

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

const right = lerp(setValue, {left: 300}, {left: 100});

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

(async function() {

  const ticker = new Ticker();

  await ticker.tick(left, {target: block},

    {duration: 2000});

  await ticker.tick(down, {target: block},

    {duration: 2000});

  await ticker.tick(right, {target: block},

    {duration: 2000});

  await ticker.tick(up, {target: block},

    {duration: 2000});

})();

弹跳的小球:

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

  }

})();

弹跳的小球2:

(async function() {

  const ticker = new Ticker();

  let damping = 0.7,

      duration = 2000,

      height = 300;

  // noprotect

  while(height >= 1) {

    let down = lerp(setValue, {top: 400 - height}, {top: 400});

    await ticker.tick(down, {target: block},

      {duration, easing: p => p * p});

    height *= damping ** 2;

    duration *= damping;

    let up = lerp(setValue, {top: 400}, {top: 400 - height});

    await ticker.tick(up, {target: block},

      {duration, easing: p => p * (2 - p)});

  }

})();

滚动:

const roll = lerp((target, {left, rotate}) => {

    target.style.left = `${left}px`;

    target.style.transform = `rotate(${rotate}deg)`;

  }, 

  {left: 100, rotate: 0},

  {left: 414, rotate: 720});

const ticker = new Ticker();

ticker.tick(roll, {target: block},

  {duration: 2000, easing: p => p});

平稳变速:

function forward(target, {y}) {

  target.style.top = `${y}px`;

}

(async function() {

  const ticker = new Ticker();

  await ticker.tick(

    lerp(forward, {y: 100}, {y: 200}),

    {target: block},

    {duration: 2000, easing: p => p * p});

  await ticker.tick(

    lerp(forward, {y: 200}, {y: 300}),

    {target: block},

    {duration: 1000, easing: p => p});

  await ticker.tick(

    lerp(forward, {y: 300}, {y: 350}),

    {target: block},

    {duration: 1000, easing: p => p * (2 - p)});

}());

甩球:

function circle({target}, {timing}) {

  const p = timing.p;

  const rad = Math.PI * 2 * p;

  const x = 200 + 100 * Math.cos(rad);

  const y = 200 + 100 * Math.sin(rad);

  target.style.left = `${x}px`;

  target.style.top = `${y}px`;

}

function shoot({target}, {timing}) {

  const p = timing.p;

  const rad = Math.PI * 0.2;

  const startX = 200 + 100 * Math.cos(rad);

  const startY = 200 + 100 * Math.sin(rad);

  const vX = -100 * Math.PI * 2 * Math.sin(rad);

  const vY = 100 * Math.PI * 2 * Math.cos(rad);

  const x = startX + vX * p;

  const y = startY + vY * p;

  target.style.left = `${x}px`;

  target.style.top = `${y}px`;

}

(async function() {

  const ticker = new Ticker();

逐帧动画



Web Animation API(Working Draft)

element.animate(keyframes, options);

target.animate([

  {backgroundColor: '#00f', width: '100px', height: '100px', borderRadius: '0'},

  {backgroundColor: '#0a0', width: '200px', height: '100px', borderRadius: '0'},

  {backgroundColor: '#f0f', width: '200px', height: '200px', borderRadius: '100px'},

], {

  duration: 5000,

  fill: 'forwards',

});

function animate(target, keyframes, options) {

  const anim = target.animate(keyframes, options);

  return new Promise((resolve) => {

    anim.onfinish = function() {

      resolve(anim);

    }

  });

}

(async function() {

  await animate(ball1, [

    {top: '10px'},

    {top: '150px'},

  ], {

    duration: 2000,

    easing: 'ease-in-out',

    fill: 'forwards',

  });

  await animate(ball2, [

    {top: '200px'},

    {top: '350px'},

  ], {

    duration: 2000,

    easing: 'ease-in-out',

    fill: 'forwards',

  });

  await animate(ball3, [

    {top: '400px'},

    {top: '550px'},

  ], {

    duration: 2000,

    easing: 'ease-in-out',

    fill: 'forwards',

  });

}());

前端性能优化

前端性能优化有什么好处

和用户体验相关;影响用户转化率。

我们的目的是通过前端优化发现性能瓶颈,提升用户体验。

然后开始思考:如何做前端性能优化?

RAIL模型

使用RAIL模型评估性能

以用户为中心的性能模型,每个网络应用都有与其生命周期有关的四个方面,而且这些方面以不同的方式影响着性能。

image

延迟与用户反应

img

响应:50ms处理事件

目标:在100ms内响应用户输入

指导:

  • 50ms内处理用户输入事件,确保100ms内反馈用户可视的响应

  • 对于开销大的任务可分隔任务处理,或放到worker进程中执行,避免影响用户交互

  • 处理事件超过50ms的操作,始终给予反馈(进度和活动指示器)

为什么预算只剩下50ms?

img

动画:10ms一帧

目标:10ms或更短的事件内生成一帧

10ms = (1000ms / 60frames ≈ 16.67 ms per frame)- 6ms(渲染的预算)

指导:

  • 在动画这样的高压点,尽量不要处理逻辑,提高达到60fps的机会

  • 动画类型:① 滚动 ② 视觉动画 ③ 拖曳动画

空闲时间最大化

目标:

最大化空闲时间以增加页面在100ms内响应用户输入的几率

指导:

  • 利用空闲时间完成推迟的工作(预加载数据)

  • 空闲时间期间用户交互优先级最高

加载:5s呈现交互内容

目标:

首屏加载连接缓慢的移动设备,5s内呈现可交互内容

非首屏加载应该在2s内完成

指导:

  • 测试用户常用设备和网络连接情况的性能

  • 优化关键渲染路径以接触阻止渲染

  • 启用渐进式渲染和在后台执行一些工作

  • 影响加载性能的因素:① 网络速度 ② 硬件 ③ 解析 JavaScript

评估性能的工具

Lighthouse

已经集成到Chrome浏览器,可以测试不同终端、运行性能、SEO等

WebPageTest

可以返回测试报告,检测网页性能

Chrome DevTools

实战演练环节会告诉你哒!

实战环节

浏览器渲染场景

csstriggers.com:查看不同css属性对渲染流程的影响

  • JavaScript:实现动画,操作DOM

  • Style:生成 Render Tree(DOM树+CSSOM树)

  • Layout:盒模型,表征确切的位置和大小

  • Paint:栅格化,生成绘制消息

  • Composite:渲染层合并,交由GPU处理

绘制和布局不是必要的流程。比如 transform / opacity 只影响 composite。

  • js尽量少用全局变量;

  • 多个js变量声明合并;

  • 不使用eval函数,不安全,性能消耗严重;

  • 使用事件代理绑定事件,如将事件绑定到body上进行代理(利用冒泡原理将事件加到父级上,能够给动态增加的元素进行数据绑定);

  • 避免频繁的操作DOM节点,使用innerHTML代替;

  • 减少对象查找,如a.data.box1.name的查找方式非常耗性能,尽可能的将它定义在变量里;

动画场景

主要是动画不卡顿,下面是一个优化的实际例子

  • 面板的功能:console控制台;source源代码面板;Network显示一些请求;performance性能优化

  • 指标的性能评分;通过screenshot对屏幕进行录制

  • 打开主函数线程,会出现很多任务,在update一栏,带红∠的会有图形计算和布局的,点开后会有sumery可以提升的地方会链接到代码地方。

你可能感兴趣的:(360前端星—promise.all—0411)