首屏加载优化

最近沉迷逛某蓝色软件,收益良多!万分感谢博主 海阔_天空,写的太棒了👍🎉

下面是原文链接,我在原文的基础上浅做个笔记,方便个人快速复习

前端性能优化——首页资源压缩63%、白屏时间缩短86% - 掘金提升首屏的加载速度,是前端性能优化中最重要的环节,这里笔者梳理出一些 `常规且有效` 的首屏优化建议 通过对比优化前后的性能变化,来验证方案的有效性,了解并掌握其原理https://juejin.cn/post/7188894691356573754#heading-6

目录

1、路由懒加载

打包对比

实现原理 import()(分离 chunk)

webpackChunkName(指定打包时生成的代码块名)

路由懒加载 - 示例

2、组件懒加载

为啥用组件懒加载

组件懒加载 - 示例

组件懒加载 - 使用场景(条件触发的组件、公共组件、大体积 .js)

3、Tree shaking

作用(删除无用代码)

原理(ES6 可静态分析)

局限(只对用 export 导出的变量生效)

4、骨架屏

原理(将骨架屏内容放到 html 文件的根节点中)

骨架屏插件(vue-skeleton-webpack-plugin)

5、虚拟滚动

原理(监听 scroll,根据 scrollTop 截取 list 并展示)

虚拟滚动插件

6、Web Worker 优化长任务

控制台查看长任务(执行时间超过 50ms 的任务)

Web worker 举例(计算 20w 条数据)

Web Worker 通信时长

7、requestAnimationFrame GUI 定时器

是什么?有什么作用?(解决动画卡顿)

定时器区别(引擎、时间准确度、性能)

8、JavaScript 的加载方式

1)正常模式(阻塞DOM)

2)async 模式(不阻塞DOM,加载无序)

3)defer 模式(不阻塞DOM,加载有序)

4)module 模式(不阻塞DOM,加载有序)

5)preload 模式(link 属性,首页[关键]资源提前加载)

6)prefetch 模式(link 属性,非首页[关键]资源提前加载)

9、图片优化

动态裁剪图片(压缩裁剪)

图片懒加载(到可视区域再加载)

使用字体图标(体积小、样式灵活、兼容性好)

图片转 base64 格式(减少 http 请求)

10、参考文章


1、路由懒加载

打包对比

普通路由 vs 路由懒加载,在 SPA 项目中:

  • 若采用普通路由,会把所有页面打包成一个文件,一次性加载所有资源
  • 若将路由改成懒加载,会把单个路由页面打包成多个文件,体积大幅减小

实现原理 import()(分离 chunk)

路由懒加载实现原理:

  • 通过 ES6 动态加载模块 import() 实现
  • 调用 import() 之处,被作为分离的模块起点,被请求的模块和它引用的所有子模块,会分离到一个单独的 chunk

webpackChunkName(指定打包时生成的代码块名)

webpackChunkName:是一个注释,用于指定 webpack 在打包时生成的代码块的名称。它的作用是让 webpack 在打包时,将具有相同名称的模块打包到同一个代码块中,从而实现代码分割和按需加载的效果;如果不指定名字,则生成的文件名将不够语义化

路由懒加载 - 示例

下面是设置 路由懒加载 的例子:

// 通过 webpackChunkName 设置分割后代码块的名字
const Home = () => import(/* webpackChunkName: "home" */ "@/views/home/index.vue");
const MetricGroup = () => import(/* webpackChunkName: "metricGroup" */ "@/views/metricGroup/index.vue");

const routes = [
    {
       path: "/",
       name: "home",
       component: Home
    },
    {
       path: "/metricGroup",
       name: "metricGroup",
       component: MetricGroup
    },
 ]

 

2、组件懒加载

为啥用组件懒加载

以 公共组件-弹框 为例,如果在多个页面中引入,则打包时会被重复打包进多个文件

同时,弹框组件不是一进入页面就加载,而是需要用户手动触发显示

此时,就应该考虑 组件懒加载 了

组件懒加载 - 示例

弹框组件懒加载示例:

<script>
const dialogInfo = () => import(/* webpackChunkName: "dialogInfo" */ '@/components/dialogInfo');
export default {
  name: 'homeView',
  components: {
    dialogInfo
  }
}
</script>

 

重新打包后:

  • 引入 dialogInfo 组件的页面中,不会被加入 dialogInfo 组件的代码
  • dialogInfo 组件被独立打包成 dialogInfo.js,当用户点击按钮时,才会去加载 dialogInfo.js 和 dialogInfo.css

组件懒加载 - 使用场景(条件触发的组件、公共组件、大体积 .js)

组件懒加载的使用场景:

  • 该组件不是一进入页面就展示需要一定条件下才触发(比如弹框组件)
  • 该组件复用性高,很多页面都有引入,利用组件懒加载抽离出该组件,一方面可以很好利用缓存,同时也可以减少页面的 JS 文件大小(比如表格组件、图形组件等)
  • 该页面的 JS 文件体积大,导致页面打开慢,可以通过组件懒加载进行资源拆分,利用浏览器并行下载资源,提升下载速度(比如首页)

PS:资源拆分的过细也不好,会造成浏览器 http 请求增多

3、Tree shaking

作用(删除无用代码)

Tree shaking 的作用:消除无用的 JS 代码,减少代码体积

举个🌰:项目中只用了 targetType(),未使用 deepClone();则 deepClone() 不会被打包

// util.js
export function targetType(target) {
  return Object.prototype.toString.call(target).slice(8, -1).toLowerCase();
}
export function deepClone(target) {
  return JSON.parse(JSON.stringify(target));
}

 

原理(ES6 可静态分析)

依赖于 ES6 的模块特性,ES6 模块依赖关系是确定的,可以进行静态分析,和运行时状态无关(也就是说,不用执行代码,就能判断啥用了啥没用),这就是 tree-shaking 的基础

CommonJS 是动态加载,执行后才知道引用的什么模块,不能通过静态分析去优化

局限(只对用 export 导出的变量生效)

并不是说所有无用的代码都可以被消除,下面的 deepClone() 仍然会被打包

// util.js
export default {
  targetType(target) {
    return Object.prototype.toString.call(target).slice(8, -1).toLowerCase();
  },
  deepClone(target) {
    return JSON.parse(JSON.stringify(target));
  }
};

// 引入并使用
import util from '../util';
util.targetType(null)

原因分析:

  • export default 导出的是一个对象,无法通过 静态分析 判断对象的哪些属性变量未被使用
  • tree-shaking 只对用 export 导出的变量生效,这也是函数式编程越来越火的原因,因为可以很好利用 tree-shaking 精简项目的体积,也是 vue3 全面拥抱了函数式编程的原因之一

4、骨架屏

使用骨架屏,可以缩短 FP 白屏时间(高达86%),提升用户体验

原理(将骨架屏内容放到 html 文件的根节点中)

SPA 单页应用,无论 vue 还是 react,最初的 html 都是空白的,需要通过加载 JS 将内容挂载到根节点上,造成长时间的白屏

骨架屏插件基于这种原理,在项目打包时,将骨架屏内容放到 html 文件的根节点中(根节点内部为骨架屏)

使用骨架屏插件,打包后的 html 文件:

<div id="app" >
  // 根节点内部为骨架屏
  <div class="skeleton loading">
    <div class="header"></div>
    <div class="content"></div>
  </div>
</div>

骨架屏插件(vue-skeleton-webpack-plugin)

这里以 vue-skeleton-webpack-plugin 插件为例,可以给 不同页面 设置不同骨架屏

安装

npm i vue-skeleton-webpack-plugin

vue.config.js 配置

// 骨架屏
const SkeletonWebpackPlugin = require("vue-skeleton-webpack-plugin");
module.exports = {
   configureWebpack: {
      plugins: [
       new SkeletonWebpackPlugin({
        // 实例化插件对象
        webpackConfig: {
          entry: {
            app: path.join(__dirname, './src/skeleton.js') // 引入骨架屏入口文件
          }
        },
        minimize: true, // SPA 下是否需要压缩注入 HTML 的 JS 代码
        quiet: true, // 在服务端渲染时是否需要输出信息到控制台
        router: {
          mode: 'hash', // 路由模式
          routes: [
            // 不同页面可以配置不同骨架屏
            // 对应路径所需要的骨架屏组件id,id的定义在入口文件内
            { path: /^\/home(?:\/)?/i, skeletonId: 'homeSkeleton' },
            { path: /^\/detail(?:\/)?/i, skeletonId: 'detailSkeleton' }
          ]
        }
      })        
      ]
   }
}

新建 skeleton.js 入口文件

// skeleton.js
import Vue from "vue";
// 引入对应的骨架屏页面
import homeSkeleton from "./views/homeSkeleton";
import detailSkeleton from "./views/detailSkeleton";

export default new Vue({
    components: {
        homeSkeleton,
        detailSkeleton,
    },
    template: `
    <div>
      <homeSkeleton id="homeSkeleton" style="display:none;" />
      <detailSkeleton id="detailSkeleton" style="display:none;" />
    </div>
  `,
});

5、虚拟滚动

原理(监听 scroll,根据 scrollTop 截取 list 并展示)

只渲染可视区域的列表项,非可视区域的不渲染,滚动时 动态更新 可视区域

虚拟滚动原理:

  • 计算出 totalHeight 列表总高度
  • 触发滚动事件时,根据 scrollTop 值不断更新 startIndex 以及 endIndex
  • 根据 startIndex 以及 endIndex ,从列表数据 listData 中截取对应元素,并在可视区域展示

虚拟滚动好处:在渲染 10w 个文本节点的情况下,使用虚拟滚动可以缩短 78% 白屏时长

虚拟滚动插件

虚拟滚动的插件有很多,比如:

  • vue-virtual-scroller
  • vue-virtual-scroll-list
  • react-tiny-virtual-list
  • react-virtualized
  • ...

简单介绍 vue-virtual-scroller 的使用,该插件主要有 RecycleScroller.vue、DynamicScroller.vue 两个组件:

  • RecycleScroller 需要 item 的高度为静态的,也就是列表每个 item 的高度都是一致的
  • DynamicScroller 可以兼容 item 的高度为动态的情况
// 安装插件
npm install vue-virtual-scroller

// main.js
import VueVirtualScroller from 'vue-virtual-scroller'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'

Vue.use(VueVirtualScroller)

// 使用
<template> 
  <RecycleScroller 
    class="scroller" 
    :items="list" 
    :item-size="32" 
    key-field="id" 
    v-slot="{ item }"> 
      <div class="user"> {{ item.name }} </div>
  </RecycleScroller> 
</template>

6、Web Worker 优化长任务

控制台查看长任务(执行时间超过 50ms 的任务)

浏览器 GUI 渲染线程与 JS 引擎线程是互斥的关系

当页面中有很多长任务(执行时间超过 50ms 的任务)时,会造成页面 UI 阻塞,出现界面卡顿、掉帧等情况

查看页面的长任务:

  • 打开控制台,选择 Performance 工具
  • 点击 Start 按钮,展开 Main 选项,会发现有很多红色的三角,这些就属于长任务

Web worker 举例(计算 20w 条数据)

把下方代码丢到 主线程 中执行,计算过程中,页面一直处于卡死状态,无法操作

let sum = 0;
for (let i = 0; i < 200000; i++) {
    for (let i = 0; i < 10000; i++) {
      sum += Math.random()
    }
  }

使用 Web Worker 执行上述代码时,计算过程中,页面正常可操作、无卡顿

// worker.js
onmessage = function (e) {
  // onmessage获取传入的初始值
  let sum = e.data;
  for (let i = 0; i < 200000; i++) {
    for (let i = 0; i < 10000; i++) {
      sum += Math.random()
    }
  }
  // 将计算的结果传递出去
  postMessage(sum);
}

Web Worker 具体的使用与案例,详情见下方文章:

一文彻底了解Web Worker,十万、百万条数据都是弟弟🔥icon-default.png?t=N2N8https://juejin.cn/post/7137728629986820126

Web Worker 通信时长

并不是执行时间超过 50ms 的任务,就可以使用 Web Worker,还要考虑 通信时长

举个🌰:一个运算执行时长为 100ms,但是通信时长为 300ms, 用了 Web Worker 可能会更慢

当任务的运算时长 - 通信时长 > 50ms,推荐使用 Web Worker

新建一个 Web worker,浏览器会加载对应资源,下图中的 Time 是这个资源的通信时长(也叫加载时长)

7、requestAnimationFrame GUI 定时器

是什么?有什么作用?(解决动画卡顿)

requestAnimationFrame 是浏览器专门为动画提供的 API,功能类似于 setTimeout/setInterval

可以使用 requestAnimationFrame 来执行一些需要高性能的操作,例如动画、滚动、拖拽等

requestAnimationFrame 的刷新频率,与显示器的刷新频率保持一致,因此,使用 requestAnimationFrame 可以解决用 setTimeout/setInterval 制作动画卡顿的情况

定时器区别(引擎、时间准确度、性能)

setTimeout/setInterval、requestAnimationFrame 区别:

  • 引擎层面:setTimeout/setInterval 属于 JS 引擎,requestAnimationFrame 属于 GUI 引擎;JS 引擎与 GUI 引擎互斥,也就是说,GUI 引擎在渲染时,会阻塞 JS 引擎的计算
  • 时间是否准确:setTimeout/setInterval 是宏任务,根据事件轮询机制,其他任务会阻塞或延迟 js 任务的执行,会出现定时器不准的情况;requestAnimationFrame 刷新频率是固定且准确的
  • 性能层面:当页面被隐藏或最小化时,setTimeout/setInterval 定时器仍会在后台执行动画任务,而使用 requestAnimationFrame 当页面处于未激活的状态下,屏幕刷新任务会被系统暂停

8、JavaScript 的加载方式

1)正常模式(阻塞DOM)

正常模式下,JS 会阻塞 dom 渲染

浏览器必须等待 index.js 加载和执行完成后,才能去做其它事情

<script src="index.js"></script> 

2)async 模式(不阻塞DOM,加载无序)

<script async src="index.js"></script>

async 模式下,JS 的加载是异步的,不会阻塞 DOM 渲染

async 加载是无顺序的,当它加载结束,JS 会立即执行

使用场景:若该 JS 与 DOM 元素没有依赖关系,可以使用 async 模式,比如埋点统计

3)defer 模式(不阻塞DOM,加载有序)

defer 可以用来控制 JS 文件的执行顺序,比如 element-ui.js 和 vue.js

因为 element-ui.js 依赖于 vue,所以必须先引入 vue.js,再引入 element-ui.js

<script defer src="vue.js"></script>
<script defer src="element-ui.js"></script>

defer 模式下,JS 的加载是异步的,不会阻塞 DOM 渲染

defer 资源会在 DOMContentLoaded 执行之前,如果有多个设置了 defer 的 script 标签存在,则会按照引入的前后顺序执行,即便是后面的 script 资源先返回

使用场景:一般情况下都可以使用 defer,特别是需要控制资源加载顺序时

4)module 模式(不阻塞DOM,加载有序)

<script type="module">import { a } from './a.js'</script>

在主流的现代浏览器中,script 标签的属性可以加上 type="module",浏览器会对其内部的 import 引用发起 HTTP 请求,获取模块内容

这时 script 的行为会像是 defer 一样,在后台下载,并且等待 DOM 解析

Vite 就是利用浏览器支持原生的 es module 模块,开发时跳过打包的过程,提升编译效率

5)preload 模式(link 属性,首页[关键]资源提前加载)

<link rel="preload" as="script" href="index.js">

link 标签的 preload 属性:提前加载某些依赖

preload 特点:

  • preload 加载的资源,是在浏览器渲染机制之前进行处理的,并且不会阻塞 onload 事件;
  • preload 加载的 JS 脚本,加载完成后不会立即调用,而是等到需要时再调用;

vue2 项目打包生成的 index.html 文件,会给 首页资源 全部添加 preload,实现关键资源的提前加载

6)prefetch 模式(link 属性,非首页[关键]资源提前加载)

<link rel="prefetch" as="script" href="index.js">

link 标签的 prefetch 属性:利用浏览器的空闲时间,加载页面将来可能用到的资源

prefetch 特点:

  • pretch 加载的资源,可以获取非当前页面的资源,并将其放入缓存至少5分钟(无论资源是否可以缓存)
  • 当页面跳转时,未完成的 prefetch 请求不会被中断

可以用于加载其他页面(非首页)所需要的资源,以便加快后续页面的打开速度

PS:现代框架已经将 preload、prefetch 添加到打包流程中了,可以通过灵活的配置,去使用预加载功能

9、图片优化

如何去压缩图片,让图片更快的展示出来,有很多优化工作可以做(比如淘宝首页的图片资源都很小)

动态裁剪图片(压缩裁剪)

经过动态裁剪后的图片,可能会从 1.8M 降低至 12.8KB,加载速度显著提升

很多云服务,比如 阿里云 或 七牛云,都提供了图片的动态裁剪功能

只需在图片的 url 地址上动态添加参数,就可以得到你所需要的尺寸大小,比如:

http://7xkv1q.com1.z0.glb.clouddn.com/grape.jpg?imageView2/1/w/200/h/200

图片懒加载(到可视区域再加载)

JavaScript 图片懒加载 - Web前端工程师面试题讲解_哔哩哔哩_bilibiliJavaScript 图片懒加载 - Web前端工程师面试题讲解, 视频播放量 35335、弹幕量 150、点赞数 1291、投硬币枚数 899、收藏人数 1643、转发人数 107, 视频作者 技术蛋老师, 作者简介 技能和观点的长期分享,相关视频:转行前端后的第一次技术面试,凉凉咯,图片懒加载和预加载,Vue怎么做图片懒加载?,Async Await关键字 - 让我们更优化地写代码 - JavaScript前端Web工程师,面试官:假如有十万条数据,前端应该怎么处理?分页渲染?no,你应该回答这个...,前端面试:说几种图片懒加载的实现方式。追问:怎么知道是否进入可视区域了?这几点必说……,Cookie、Session、Token究竟区别在哪?如何进行身份认证,保持用户登录状态?,彻底搞懂图片懒加载和预加载,公司昨天入职的211大学毕业的程序员,昨天看了项目代码,今天就开始写了,而且还没有报错,真的很厉害,JavaScript基础语法-dom-bom-js-es6新语法-jQuery-数据可视化echarts黑马pink老师前端入门基础视频教程(500多集)持续https://www.bilibili.com/video/BV1FU4y157Li/?spm_id_from=333.999.0.0

什么是图片懒加载?

对于一些图片量较大的首页,只需呈现可视区域的图片,当用户滑动页面时,再去加载新的

图片懒加载原理?

  • 浏览器会自动对页面中的 img 标签的 src 属性 发送请求 并下载图片
  • 通过 html5 自定义属性 data-xxx 暂存 src 的值
  • 图片出现在可视区域时,再将 data-xxx 赋值给 img 的 src 属性
<img src="" alt="" data-src="./images/1.jpg">
<img src="" alt="" data-src="./images/2.jpg">

这里以 vue-lazyload 插件为例

// 安装 
npm install vue-lazyload 
    
// main.js 注册
import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload)
// 配置项
Vue.use(VueLazyload, {
  preLoad: 1.3,
  error: 'dist/error.png', // 图片加载失败时的占位图
  loading: 'dist/loading.gif', // 图片加载中时的占位图
  attempt: 1
})

// 通过 v-lazy 指令使用
<ul>  
    <li v-for="img in list">
        <img v-lazy="img.src" :key="img.src" >
    </li>
</ul>

使用字体图标(体积小、样式灵活、兼容性好)

字体图标优点:

  • 轻量级:一个图标字体要比一系列的图像小
  • 灵活性:可以随意改变样式
  • 兼容性:几乎支持所有的浏览器

图片转 base64 格式(减少 http 请求)

将小图片转换为 base64 编码字符串,并写入 HTML 或者 CSS 中,减少 http 请求

转 base64 格式的优缺点:

  • 善于处理非常小的图片,因为 Base64 编码后,图片大小会膨胀为原文件的 4/3,如果对大图也使用 base64 编码,后者体积会明显增加,即便减少了 http 请求,也无法弥补增大文件体积带来的性能开销
  • 在传输非常小的图片的时候,base64 带来的文件体积膨胀、以及浏览器解析 base64 的时间开销,与它节省掉的 http 请求开销相比,可以忽略不计

可以使用 url-loader 将图片转 base64:

// 安装
npm install url-loader --save-dev
    
// 配置
module.exports = {
  module: {
    rules: [{
        test: /.(png|jpg|gif)$/i,
        use: [{
            loader: 'url-loader',
            options: {
              // 小于 10kb 的图片转化为 base64
              limit: 1024 * 10
            }
        }]
     }]
  }
};

10、参考文章

路由懒加载原理及使用

vue-skeleton-webpack-plugin 骨架屏插件使用

前端性能优化-虚拟滚动

requestAnimationFrame制作动画

浅谈script标签中的async和defer

Tree-Shaking性能优化实践 - 原理篇

使用 Preload&Prefetch 优化前端页面的资源加载

github.com/xy-sea/blog

再次鸣谢博主 海阔_天空,写的太棒了👍🎉

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/4743.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

溯源(五)之攻击源的获取

溯源&#xff08;一&#xff09;之溯源的概念与意义 溯源&#xff08;二&#xff09;之 windows-还原攻击路径 溯源&#xff08;三&#xff09;之Linux-入侵排查 溯源&#xff08;四&#xff09;之流量分析-Wireshark使用 溯源整体流程的思维导图 攻击源的获取 1、获取哪些数…

Spring Data JPA

1. Spring Data环境搭建 Spring Data提供了一套统一的基于Spring的数据访问模型&#xff0c;它可以轻松的实现数据库访问&#xff0c;包括各种关系型、非关系型数据库、Map-Reduce框架、云数据服务等。 Spring Data 包含多个子项目&#xff1a; • Commons - 提供共享的基础框架…

ExtScreen,为智能电视和VR设备打造的快应用引擎

和手机相比&#xff0c;智能电视端的生态一直都不怎么行&#xff0c;具体来讲有以下这几个问题&#xff1a; 电视芯片运算能力差&#xff0c;配置普遍不如手机&#xff1b;电视交互基于遥控器&#xff0c;完全不同于触摸屏操作的手机&#xff1b;电视的生态比较封闭&#xff0…

【JavaWeb】Cookie和Session

目录 Cookie Cookie定义 Cookie数据的来源 Cookie数据的存储 Cookie数据的使用 使用Cookie原因 Session Session定义 如何存储数据 Cookie和Session的区别 使用Cookie和Session简单实现登录页面 Cookie Cookie定义 Cookie是浏览器提供持久化存储数据的机制。 Cook…

这么方便吗?用ChatGPT生成Excel(详解步骤)

文章目录前言使用过 ChatGPT 的人都知道&#xff0c;提示占据非常重要的位置。而 Word&#xff0c;Excel、PPT 这办公三大件中&#xff0c;当属 Excel 最难搞&#xff0c;想要熟练掌握它&#xff0c;需要记住很多公式。但是使用提示就简单多了&#xff0c;和 ChatGPT 聊聊天就能…

【vue3】基础概念的介绍

⭐【前言】 首先&#xff0c;恭喜你打开了一个系统化的学习专栏&#xff0c;在这个vue专栏中&#xff0c;大家可以根据博主发布文章的时间顺序进行一个学习。博主vue专栏指南在这&#xff1a;vue专栏的学习指南 &#x1f973;博主&#xff1a;初映CY的前说(前端领域) &#x1f…

【音视频】zlmediakit总结一

推拉流理论 推流&#xff1a;将直播的内容推送至服务器的过程。 拉流&#xff1a;指服务器已有直播内容&#xff0c;用指定地址进行拉取的过程。 拉流&#xff0c;即是指服务器里面有流媒体视频文件&#xff1b; 但zlmediakit里也有个广义的拉流概念如下。对于用户而言&#xf…

面试官灵魂拷问[二]:SQL 语句中 where 条件后写上 1=1 是什么意思?

面试官灵魂拷问系列又来更新啦! “SQL 语句中 where 条件后写上 11 是什么意思&#xff1f;” 这玩意就跟很多新语言支持尾部逗号的原理一样的。 比如 Kotlin 支持数组写成 [1, 2, 3, 4, ] &#xff0c;注意4后边那个逗号&#xff0c;为什么呢&#xff1f;因为当你增加一个项…

医院LIS系统源码,云LIS系统源码,独立实验室LIS源码

实验室云LIS系统源码 LIS系统源码 LIS源码 基于B/S架构的实验室管理系统云LIS&#xff0c;整个系统的运行基于WEB层面&#xff0c;只需要在对应的工作台安装一个浏览器软件有外网即可访问。 私信了解更多源码内容&#xff01; 技术架构&#xff1a;Asp.NET CORE 3.1 MVC SQ…

MySQL表设计思路(一对多、多对多...)

要开始单独负责需求了&#xff0c;捋一捋表设计的思路。 文章目录一、MySQL中的数据类型二、一对一的关系设计二、一对多的关系设计三、多对多的关系设计四、经验总结一、MySQL中的数据类型 字符串类型 varchar&#xff1a;即variable char &#xff0c;可边长度的字符串&#…

Tomcat启动JSP项目,搞起来了

虽然有点复古&#xff0c;但是还是有很多小伙伴在使用的&#xff0c;小编来一篇保姆级教程 1、用idea打开jsp项目 2、添加tomcat配置 3、点击后会出现配置框,这里画框的地方都选上&#xff0c;版本选择1.8&#xff0c;其他的信息内容默认后&#xff0c;点击确认 4、点击…

FITC-PEG-Biotin,荧光素-聚乙二醇-生物素的相关检测

FITC-PEG-Biotin 荧光素聚乙二醇生物素 英文名称&#xff1a;Fluorescein (polyethylene glycol) Biotin 中文名称&#xff1a;荧光素聚乙二醇生物素 激光/发射波长&#xff1a;515nm&#xff5e;520 nm 分子量&#xff1a;2000、3400、5000其他分子量可制定 溶剂&#xff…

【C++】异常

文章目录C传统处理错误方式C异常概念异常使用1.异常的抛出和捕获2.异常的重新抛出异常安全异常规范自定义异常体系C标准库的异常体系异常的优缺点C传统处理错误方式 C语言传统的错误处理机制&#xff1a; 1. 终止程序&#xff0c;如assert&#xff0c;缺陷&#xff1a;用户难以…

nodejs+vue文旅门户信息网站 elementui旅游项目推荐系统 景点门票预订网站vscode

在社会快速发展的影响下&#xff0c;服务行业继续发展&#xff0c;随着旅游的人数不断增加&#xff0c;使哈尔滨旅游项目推荐平台的管理和运营比过去十年更加信息化&#xff0c;依照这一现实为基础&#xff0c;设计一个快捷而又方便的网上哈尔滨旅游项目推荐平台是一项十分重要…

day73【代码随想录】二刷链表

文章目录前言一、环形链表||&#xff08;力扣142&#xff09;二、寻找重复数&#xff08;力扣287&#xff09;三、缺失的第一个正数&#xff08;力扣41&#xff09;每日一题day73&#xff1a;等差子数组&#xff08;力扣1630&#xff09;前言 1、等差子数组 2、寻找重复数 3、…

ThreeJS-纹理(十)

关键代码&#xff1a; const textureLoader new THREE.TextureLoader(); //纹理加载器加载图片 const docColorLoader textureLoader.load(static/1.webp) // let color new THREE.Color(Math.random(), Math.random(), Math.random()); const cubeMaterial new THREE.Mesh…

法规标准-GB/T 39901标准解读(2021版)

GB/T 39901是做什么的&#xff1f; GB/T 39901全名为乘用车自动紧急制动系统(AEBS)性能要求及试验方法&#xff0c;其中主要对AEBS的功能要求、性能要求及测试要求进行介绍 一般要求 1.安装有自动紧急制动系统的车辆应安装符合GB 21670-2008要求的防抱制动系统 2.AEBS的电磁…

近世代数 笔记和题型连载 第七章(阿贝尔群和循环群)

文章目录基础概念1.阿贝尔群2.循环群3.有限循环群4.元素的阶5.无限循环群相关题型1.判断一个代数系统的代数结构2.判定一个群是否是循环群3.判定一个群是否是循环群4.循环群的生成元有关问题5.判定元素的阶6.判定元素的阶7.判定元素的阶8.求给定循环群的所有子群9.求给定循环群…

七. MySQL 其它优化相关

目录一. 数据库问题排查流程二. 表连接驱动表与被驱动表Nested Loop Join 与小表驱动大表JoinBuffer 连接缓冲区Index Nested-Loop Join 索引嵌套循环连接Batched Key Access join 批量的key访问连接Block Nested-Loop Join 缓存块嵌套循环连接三. 半连接in 与 existssemi-join…

Vue 04 - Vue模板语法

目录 介绍 Mustache 插值语法 Attribute指令语法 代码演示 运行效果 介绍 Vue.js 使用了基于 HTML 的模板语法&#xff0c;允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。所有 Vue.js 的模板都是合法的 HTML&#xff0c;所以能被遵循规范的浏览器和 HTML 解析器解…