前端笔记

143 阅读6分钟

常见排序算法文字描述

冒泡排序 两两比较将最大的数沉到最底下;

// 冒泡排序
const bubblingSort = (array)=> {
  console.log(array);
  for(let i = 0; i<array.length; i++) {
    for(let j = 0; j<array.length - i; j++) {
      if(array[j]>array[j+1]){
        [array[j],array[j+1]] = [array[j+1],array[j]]
      }
    }
  }
  return array;
};

选择排序 循环找到最小数的下标 与目标值进行比较交换;

// 选择排序
const selectSort = (array) => {
  for(let i = 0; i<array.length; i++) {
    let minIndex = i;
    for (let j = i + 1; j < array.length; j++) {
      if (array[minIndex] > array[j]) {
        minIndex = j;
      }
    }
    [array[minIndex], array[i]] = [array[i], array[minIndex]]
  }
  console.log('array',array);
  return array;
};

插入排序 定义新的数组 从原数组中取元素与新的数组比较,通过splice方法插入到新数组合适的位置;

// 插入排序
const insertSort = (array)=>{
  let resArr = [array[0]];
  for(let i = 1; i < array.length; i++){
    for(let j = resArr.length - 1; j>=0; j--){
      if(array[i]>resArr[j]){
        resArr.splice(j+1,0,array[i]);
        break;
      }
      if(j===0) {
        resArr.unshift(array[i])
      }
    }
  }
  return resArr;
};

快速排序 递归实现 取第一个元素 循环剩下的部分与次元素做比较 大的小的分别放到两个个新的数组中,递归这两个新的数组,递归出口 数组长度小于等于1

// 快速排序
const quickSort = (array)=>{
  if(array<=1) return array;
  let left = [];
  let right = [];
  const current = array[0];
  for(let i = 1; i<array.length; i++) {
    array[i] < current ? left.push(array[i]) : right.push(array[i])
  }
  return quickSort(left).concat([current],quickSort(right))
};

归并排序 先使用递归的方式把数组分治,分成left right两个,递归的出口是数组的长度小于2,然后将数组进行合并;合并时循环比较两个数组的长度 使用shift()方法截取数组的第一个元素,push到新的结果数组中

// 归并排序
const mergeSort = (array)=>{
  if( array.length <= 2) return array;
  const middle = array.length / 2 | 0;
  const left = array.slice(0, middle);
  const right = array.slice(middle);
  console.log(left,right);
  return merge(mergeSort(left),mergeSort(right))
};

const merge = (left, right)=>{
  const res = [];
  while(left.length && right.length) {
    left[0]>right[0] ? res.push(right.shift()) : res.push(left.shift())
  }

  while(left.length){
    res.push(left.shift())
  }

  while(right.length){
    res.push(right.shift())
  }

  return res;
};

http强缓存 协商缓存

强缓存 响应头返回 cache-control(http1.1)的属性(expires http 1.0返回的是时间,根据浏览器时间来校验是否走强缓存),cache-control可以设置的属性值: max-age=30000 表示(当前时间+30000秒)内不与服务器请求新的数据资源;private:只缓存客户端,代理服务器不缓存;public:都可以缓存;no-store:不缓存任何内容;no-cache:缓存要进行新鲜度的校验;

协商缓存 响应返回 last-modified(时间) Etag(唯一标识),等再次发起请求时带上这两个属性,服务器端判断是否过期 Etag是否有改变,如果命中缓存则返回304状态码,告知浏览器取本地缓存;请求头带上的两个属性:if-modified-since:last-modified,if-none-match:Etag; 缓存顺序 Cache-control -> expires -> Etag -> last-modified

http https区别

http: 超文本传输协议,应用层协议,是以存文本的形式传输,没有任何的加密操作,默认端口号80;

https: http+ssl/tls加密算法,传输的内容是二进制流,不再是文本传输,相对来说更安全,默认端口443; https流程 1、客户端请求 HTTPS 请求并连接到服务器的 443 端口,此过程和请求 HTTP 请求一样,进行三次握手; 2、服务端向客户端发送数字证书,其中包含公钥、证书颁发者、到期日期,现比较流行的加解密码对,即公钥和私钥。公钥用于加密,私钥用于解密。所以服务端会保留私钥,然后发送公钥给客户端。 3、客户端收到证书,会验证证书的有效性。验证通过后会生成一个随机的 pre-master key。再将密钥通过接收到的公钥加密然后发送给服务端 4、服务端接收后使用私钥进行解密得到 pre-master key 5、获得 pre-master key 后,服务器和客户端可以使用主密钥进行通信。

http1.0 http1.1 http2.0

http1.0 http1.1区别

缓存 host头 连接方式:长连接 状态码

http2 新增

多路复用 头部压缩 二进制分帧 主动推送

js事件循环机制

js是单线程执行语言,一次只能有一个正在执行的任务,为了防止代码的阻塞,js代码分为同步代码异步代码,先执行同步代码,再执行异步代码;异步代码又分为微任务,宏任务,当遇到同步代码时立即执行,遇到异步代码 宏任务放到宏任务队列,微任务进微任务队列,等同步代码执行完毕再执行微任务队列,再执行宏任务队列;

宏任务

  • script(整体代码)
  • setTimeout
  • setInterval
  • setImmediate
  • I/O
  • UI/render

微任务

  • process.nextTick
  • Promise
  • Async/Await
  • html5新特性(MutationObserver)
async function async1() {
  console.log("async1 start");
  setTimeout(() => {
    console.log("timeout1");
  }, 0);
  await async2();
  console.log("async1 end");
}

async function async2() {
  console.log("async2");
}

async1();

setTimeout(() => {
  console.log("timeout0");
}, 0);

new Promise(function (resolve) {
  console.log("promise1");
  resolve();
}).then(function () {
  setTimeout(() => {
    console.log("timeout3");
  }, 0);
  console.log("promise2");
});

console.log("script end");

微信图片_20221109171105.jpg

特殊说明:async1 end要等所有同步代码执行完之后再执行(await阻塞);将 then(async1 end)加入微任务

webpack打包

Loader Plugin 是webpack的两个核心;

Loader 本质是一个函数,在函数中对接受到的内容进行转换,返回转换后的结果。因为webpack只认识js语言,所以loader就成了翻译官,对其他类型的文件进行预处理操作。在 module.rules 配置,数组参数,数组的元素是对象包括test(类型文件)、loader、options (参数)等属性;

Plugin 就是插件,基于事件流框架 Tapable,插件可以扩展 Webpack 的功能,在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。在 plugins 中单独配置,类型为数组,每一项是一个 Plugin 的实例,参数都通过构造函数传入;

webpack打包流程:

  • 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数

  • 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译

  • 确定入口:根据配置中的 entry 找出所有的入口文件

  • 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理

  • 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系

  • 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会

  • 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统

总结简化流程

  • 初始化:启动构建,读取与合并配置参数,加载 Plugin,实例化 Compiler

  • 编译:从 Entry 出发,针对每个 Module 串行调用对应的 Loader 去翻译文件的内容,再找到该 Module 依赖的 Module,递归地进行编译处理

  • 输出:将编译后的 Module 组合成 Chunk,将 Chunk 转换成文件,输出到文件系统中