当前位置: 首页 > news >正文

veImageX 演进之路:Web 图片加载提速50%

背景说明

火山引擎veImageX演进之路主要介绍了veImageX在字节内部从2012年随着字节成长过程中逐步演进的过程,演进中包括V1、V2、V3版本并最终面向行业输出;整个演进过程中包括服务端、客户端、网络库、业务场景与优化等多个角度介绍在图像处理压缩、省成本与体验优化的经验与方案;

本篇文章重点介绍在web端演进和提供的能力,图片是 Web 站点中的重要元素,图片体积、格式、分辨率以及渲染方式对用户体验有着显著影响。火山引擎veImageX 为业务提供了灵活、高效的一站式图片解决方案和静态素材托管方案,涵盖了上传、存储、处理、分发、评估等图片生产和消费阶段的全部链路。

解决的问题

Web 场景下图片的应用非常广泛,从传统的图文到视频封面都有图片的身影,图片体验是用户体验中很重要的一环,常用于衡量站点性能的 LCP 和 CLS 指标都把图片列为最重要的元素之一。随着业务的发展,用户量增长的同时也带来了 CDN 带宽成本的快速提升,最主要的元素则是图片和视频。因此,方案从体验和成本出发,旨在为用户提升体验的同时降低带宽成本。

用户体验可视化

图片体验问题通常有以下几点:

  • 加载速度慢:图片体积、网络、CDN、处理耗时等因素均会影响加载耗时;

  • 加载失败率高:导致图片加载失败的因素很多,重点在于如何及时定位问题;

  • 渲染体验差:包括图片区域长时间空白、加载后导致页面抖动、出错后无兜底等场景;

开发者往往忽视了图片体验,也不了解图片对站点性能的影响,并且缺少可量化的数据来衡量站点的图片体验。参考 Lighthouse 性能优化指南,方案整合了图片压缩、图片懒加载、图片稳定性布局、错误兜底等能力,并集成了数据监控能力,可结合 火山引擎veImageX 控制台实时大盘数据查看,为业务提供数据上报、数据分析、数据追踪、数据告警等全链路支持。

带宽成本问题

以下问题通常会带来额外的带宽成本:

  • 图片压缩率低;

  • 图片原始分辨率和渲染分辨率不匹配;

  • 采用传统的 PNG、JPEG 等低压缩率格式;

  • 图片未进行懒加载;

除了图片压缩,方案支持了 WebP、AVIF 等高压缩率图片格式的自适应加载和图片分辨率的自适应加载,尽可能减小图片体积。同时集成了图片懒加载,避免不可见区域的图片加载,降低站点 CDN 成本,同时也提升站点整体加载速度。根据内部业务数据,图片传输带宽和图片加载耗时通常可降低 50% 以上。

方案架构

方案总体上可划分为图片加载和数据监控两个部分。

ec572bc4afd4957ccc79dc953d9c2664.png
方案架构.png

如图所示,图片加载部分支持分辨率、格式自适应以及懒加载、稳定性布局等特性,其中涉及到图片处理部分基于火山引擎veImageX 服务实现,如图片转码、缩放、压缩等。SDK 侧生成当前环境下最佳的图片格式和分辨率,从服务获取相应的图片 URL,借助云端处理能力在运行时动态生成所需的图片。

数据监控部分可分为加载耗时监控、图片详情监控、画质评估、大图监控、云控配置几部分,监控 SDK 收集相关数据,根据云端下发的配置上报数据,火山引擎veImageX 服务对数据做清洗后可在控制台侧查看数据大盘。

模块详细介绍

图片加载

图片格式自适应

常见的图片格式有 PNG、JPEG、GIF、WebP、AVIF、HEIC 等,其中 WebP、AVIF、HEIC 等高压缩率图片格式可显著减小图片体积。但由于不同浏览器对高压缩率格式的支持情况不同,因此在应用时需要考虑图片加载的环境。三种高压缩率格式在 Web 侧的兼容性如下:

  1. WebP

937183fd82c8f69e4789bc25f0d57ea9.png
  1. AVIF

0e5fdc74b67564bbd81a8ef777a9b77f.png
  1. HEIC

16e7d4125e051317cdcefef3bfaa23af.png

在 APP 端,对于不支持的图片格式可采用 SDK 软解的方式进行解码、渲染,Native 侧的性能可保证图片解码的耗时和流量的节省都能有不错的收益。在 Web 侧,由于浏览器性能限制,veImageX 内部性能测试表明,SDK 软解在图片整体耗时方面的收益并不明显,尤其是多图场景下,因此在 Web 侧更适合走格式自适应的方案,即根据浏览器的支持性加载相对最优的图片格式。

常见的做法是采用标签以实现格式的自适应,标签有相对不错的兼容性,支持包含零或多个元素和一个  元素来为不同的浏览器环境提供图片版本,浏览器会自上而下选择可以被渲染的图片,若没有匹配的,则选择  元素当中的图片作为兜底。加载 SDK 最初也采用了该方案,如下:

<picture><source srcset="image1.webp" type="image/webp" /><img src="image1.jpg" decoding="async" loading="lazy"/>
</picture>

但由于浏览器版本众多,在实际应用中,可能会出现很多预期以外的情况,比如:

  • 会同时加载多个图片资源,造成带宽的浪费;

  • 并非完全支持 WebP 的所有特性,存在加载失败的场景;

  • 只支持 AVIF 静图格式,不支持动图;

  • ...

为了保证图片加载成功率,因此在实际应用中无法直接使用标签,加载 SDK 目前采用格式探测 +相结合的方式来解决该问题。同时,由于 HEIC 支持率太低,格式自适应目前只做了 WebP 和 AVIF 的自适应,同等质量下,WebP 相比 JPEG 可减少 30% 的图片体积,AVIF 则可在 WebP 的基础上再减少 20%;

图片分辨率自适应

分辨率自适应指的是客户端根据实际渲染的宽高获取相应分辨率的图片,从而减小图片体积。常见的做法是我们可以借助 HTML 中原生的 srcset 属性来定义图像集,以及每个图像应用的场景。由以下三部分组成:

  • 文件名

  • 空格

  • 图像描述符,有两种描述方式

    • 宽度描述符 w,描述图像的固有宽度,以像素为单位。比如 480w 表示当浏览器需要 480 像素宽的图像时应该使用的图像资源

    • 像素密度描述符 x,描述了显示器的像素密度和图片资源之间的对应关系,通过window.devicePixelRatio可查询显示器像素密度

sizes 则定义了一组媒体条件,比如:屏幕宽度。并且指明当媒体条件为真时最佳的图片尺寸。每个条件由以下三部分组成:

  • 一个媒体条件,比如max-width:480px,表示可视窗口的宽度不超过480像素时

  • 空格

  • 当媒体条件为真时,应该选用的图片大小

可以将标签和 srcset 属性相结合,实现格式和分辨率的自适应,如下:

<picture><source   srcset="image1.webp 200w,image2.webp 600w"sizes="100vw"type="image/webp"/><img srcset="image1.jpg 200w,image2.jpg 600w"sizes="100vw"decoding="async"loading="lazy"/>
</picture>

然而在实际中又会面临一些问题,如:

  • 指定多个 srcset 会增加 HTML 文件大小,尤其是当中存在多个的场景;

  • 媒体查询条件只能是屏幕宽度和像素密度,不能准确反映真实的图片渲染情况;

  • srcset 配合 sizes 使用,理解成本相对较高;

  • ...

在实际应用中,某些情况下可以提前知道图片渲染大小或者图片所在区域的大小,结合方案内置的几种布局方式以及设备像素密度等信息,加载 SDK 内部可以分析并选择出当前模块渲染的最佳分辨率。

图片稳定性布局

Web 侧通常基于 CLS(Cumulative Layout Shift,累积布局偏移)指标用于衡量页面布局的视觉稳定性。当可见元素的位置在页面生命周期内发生了变化时,就会产生布局偏移。

导致布局偏移的因素有很多(如:动态插入元素、iframe加载),无尺寸的图片是影响 CLS 指标的重要因素之一。例如下面两个页面中,右侧指定了图片宽高的页面要比左侧没有指定图片宽高的页面稳定性更好。

6aaac940f0db16cd4dfc57328086b969.gifc851de30a7408cddcb5e0fa9af7bc0b9.gif

受 next/image 的启发,加载 SDK 内置了四种稳定性布局方式:intrinsic、responsive、fixed、fill,通过生成稳定的 dom 结构来提升视觉稳定性,减少业务开发量。效果如下:

07081ea04373379e164300cfbda837cd.gif1422c4c5c004c493251d5e76b7c19c00.gif

d738bee7a43a70327e0e9bf426241a23.gif65a868195f4dffb4196e2aa883fa803c.gif

  • intrinsic: 若指定宽度小于容器宽度,则根据指定宽高渲染图片;反之则图片宽度为容器宽,图片高度按照比例缩小;

  • responsive: 图片渲染宽度等于容器宽度,高度按比例缩放;

  • fixed: 根据指定宽高渲染图片;

  • fill: 图片缩放以填充容器,可传入 objectFit、objectPosition 属性表示不同的填充模式;

图片懒加载

对于图片懒加载最简单的做法是基于  的原生属性 loading="lazy",但在实际的应用中也发现了两个问题:

  • 该属性的兼容性不达标,多数浏览器不支持;

  • 在部分 Safari 浏览器上存在 bug,可能会导致图片加载被阻塞;

因此,SDK 内部基于 IntersectionObserver API 实现,该 API 相对更可控,且可以设置懒加载的距离、目标元素等属性。

数据监控

df95d3e3e3bb3c15b5663f2bb3a612e3.png
数据监控.png

数据监控的整体链路为:

  1. 监听全局的 Load 和 Error 事件,并筛选出属于图片的部分;

  2. 基于 PerformanceObserver 监听图片资源加载,该事件回调中可拿到图片加载耗时相关的指标,如 DNS、TCP、SSL、请求、下载各个阶段的耗时,并且可以基于该 API 监听 CSS 中图片资源的加载;

  3. 对于图片格式、状态码、画质打分等信息则依赖 Response Header,而拿到 Response Header 仅有 request 资源这一种方式,因此在资源加载后再去 request 本地缓存中的信息,同时为避免并发请求影响其他类型的 HTTP 请求,SDK 会根据采样率、当前请求量等信息在空闲时读取需要上报的图片的缓存;

  4. 整合所有原始数据,根据采样率上报至 veImageX 数据服务,由数据服务对原始数据做清洗;

  5. 经过后端服务处理后最终即可在 veImageX 质量监控大盘查看,具体支持的指标及维度如下图所示:

    1. 下行网络监控

    2. ce24bc03eb445c935ea2e2e7557ed034.png

    3. 客户状态监控

    4. 7cb8a0c466fe783a710ccc3f7fc44635.png

方案演进

方案致力于为 Web 场景提供极致的图片加载体验,同时在稳定性和场景覆盖上也在不断提升。

更低的错误率

上面提到在某些浏览器下会存在部分 WebP、AVIF 图片加载失败的场景,在监控到此类场景后加载 SDK 基于格式探测的方式最低成本的解决了此类问题,同时保证了性能。

例如:在 iOS 14.3 & 14.4 版本下的 Safari 浏览器加载部分的 WebP 失败,而标签并不会对 WebP 的支持性做检测,其对于传入的 WebP 格式是全盘接收的,且 SDK 也无法对所有传入的图片做检测,因此只能通过构造特定图片,在业务图片加载前对其进行检测从而规避该问题,如下:

const checkWebP = () => {const pro: Promise<boolean> = new Promise<boolean>((resolve) => {if(typeof window === 'undefined') resolve(false);if (window['__support_webp__'] !== undefined) {resolve(!!window['__support_webp__']);} else {const img = new Image();img.onload = () => {window['__support_webp__'] = true;resolve(true);};img.onerror = () => {window['__support_webp__'] = false;resolve(false);};img.src = 'error image';}});return pro;
};

更多的场景覆盖

目前方案支持了 React、Vue2、Vue3 以及小程序,为了保证体验的一致性、降低维护成本,加载 SDK 做了分层的设计,将核心的 Core 层抽离出来给到各个框架使用,并对各项能力做了插件化。

17dbe67c65b4aac9ae23ef27e2b02691.png
场景覆盖.png

小结

随着方案的迭代,我们也在尝试覆盖更多的业务场景,比如:加密图渲染、Hybrid HEIC 渲染等,火山引擎veImageX 希望给客户带来全面、稳定、流畅的图片体验,同时给业务带来极致的成本收益。

我们将如上能力封装成简单的webSDK,向行业输出,并可以免费获取和使用此SDK,更高级的能力也可以配合veImageX来使用;

webSDK接入地址:https://www.volcengine.com/docs/508/177943

相关文章:

veImageX 演进之路:Web 图片加载提速50%

背景说明 火山引擎veImageX演进之路主要介绍了veImageX在字节内部从2012年随着字节成长过程中逐步演进的过程&#xff0c;演进中包括V1、V2、V3版本并最终面向行业输出&#xff1b;整个演进过程中包括服务端、客户端、网络库、业务场景与优化等多个角度介绍在图像处理压缩、省成…...

WebSocket实战之五JSR356

一、前言 前几篇WebSocket例子服务端我是用NodeJS实现,这一篇我们用Java来搭建一个WebSocket服务端&#xff0c;从2011年WebSocket协议RFC6455发布后&#xff0c;大多数浏览器都实现了WebSocket协议客户端的API,而对于服务端Java也定义了一个规范JSR356,即Java API for WebSoc…...

flask-sqlalchemy结合Blueprint遇到循环引入问题的解决方案

想要用flask_sqlalchemy结合Blueprint分模块写一下SQL的增删改查接口&#xff0c;结果发现有循环引入问题。 一开始&#xff0c;我在app.py中使用db SQLAlchemy(app)创建数据库对象&#xff1b;并且使用app.register_blueprint(db_bp, url_prefix/db)注册蓝图。 这使得我的依…...

05_对象性能模式

对象性能模式 面向对象很好地解决了“抽象”的问题,但是必不可免地要付出定的代价。对于通常情况来讲&#xff0c;面向对象的成本大都可以忽略计。但是某些情况&#xff0c;面向对象所带来的成本必须谨慎处理。 典型模型&#xff1a; SingletonFlyweight Singleton 单件模式…...

快速选择排序

"你经过我每个灿烂时刻&#xff0c;我才真正学会如你般自由" 前些天有些无聊&#xff0c;想试试自己写的快排能否过leetcode上的排序算法题。结果是&#xff0c;不用截图可想而知&#xff0c;肯定是没过的&#xff0c;否则也不会有这篇文章的产出。 这份快排算法代码…...

国庆中秋特辑(六)大学生常见30道宝藏编程面试题

以下是 30 道大学生 Java 面试常见编程面试题和答案&#xff0c;包含完整代码&#xff1a; 什么是 Java 中的 main 方法&#xff1f; 答&#xff1a;main 方法是 Java 程序的入口点。它是一个特殊的方法&#xff0c;不需要被声明。当 Java 运行时系统执行一个 Java 程序时&…...

Centos7 安装mysql 8.0.34

Centos7 安装mysql 8.0.34 准备工作 centos7 服务器 xshell 安装教程 安装并配置 在安装MySQL之前&#xff0c;我们应该确保系统已经更新到最新的软件包和安全补丁。打开终端&#xff0c;输入以下命令来更新系统 yum update为了方便安装MySQL&#xff0c;我们需要下载并…...

如何在 Google Earth 中创建轨迹、路线并制作动画

如何创建航迹 https://kurviger.de/en Google 地球飞行教程(天桥动画) 选择合适的点 &#xff08;可调整视图快照&#xff09;点击录制&#xff0c;依次点击图标即可...

蓝桥杯每日一题2023.9.30

蓝桥杯大赛历届真题 - C&C 大学 B 组 - 蓝桥云课 (lanqiao.cn) 题目描述 题目分析 对于此题&#xff0c;首先想到了dfs进行一一找寻&#xff0c;注意每次不要将重复的算进去&#xff0c;故我们每次循环可以记录一个开始的位置&#xff0c;下一次到这个位置时&#xff0c;…...

springboot和vue:十、vue2和vue3的差异+组件间的传值

首先用vue-cli创建一个vue2的项目。 vue2和vue3的差异 main.js的语法有所差别。 vue2是 import Vue from vue import App from ./App.vuenew Vue({render: h > h(App), }).$mount(#app)vue3是 import { createApp } from vue import App from ./App.vuecreateApp(App).…...

SQL:增、删、改、查 基本语句 Navicat建库(用法 + 例子)

文章目录 新建数据库新建表 增、删、改、查select 查找insert 添加delete 删除update 修改where 扩展 < > < > ! <> 比较运算符and or 逻辑运算符between...and... 介于..和..之间in 包含like 模糊查询is null 为空的 查询扩展order by 排序limit start coun…...

vue-cli搭建过程(HBuilder X搭建)

vue.js:前端主流框架&#xff08;对某一方面技术完整的封装&#xff0c;是一套完善的解决方案&#xff09; vue-cli搭建项目&#xff08;官方提供脚手架&#xff09; vue脚手架&#xff1a;是一套项目搭建的快捷方式&#xff0c;可以将项目中的依赖集成进来&#xff0c;生成统…...

MySQL索引:结构、语法、分类和优化

MySQL索引是数据库中非常关键的性能优化手段。它们提供了快速访问数据的方法&#xff0c;同时也可以极大地提高查询效率。本文将深入介绍MySQL索引的结构、语法、分类&#xff0c;以及如何使用Profile和EXPLAIN来优化查询性能&#xff0c;带有详细的实例演示。 索引结构 MySQ…...

Vue中添加旋转动画

// transform: scale(1.2) rotate(-180deg); 放大 旋转 // transform: rotate(-180deg); 旋转 <i class"el-icon-close"></i>i {font-size: 20px;line-height: 24px;transition: transform 0.2s linear;}i:hover {color: red;transform-origin: cen…...

基于SSM农产品商城系统

基于SSM农产品商城系统的设计与实现&#xff0c;前后端分离&#xff0c;文档 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringSpringMVCMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 农产品列表 产品详情 个人中心 登陆界面 管…...

基于matlab创作简易表白代码

一、程序 以下是一个基于MATLAB的简单表白代码&#xff1a; % 表白代码 clc; % 清除命令行窗口 clear; % 清除所有变量 close all; % 关闭所有图形窗口 % 输入被表白者的名字 name input(请输入被表白者的名字&#xff1a;, s); % 显示表白信息 fprintf(\n); fprintf(亲爱的…...

pandas

一、pandas初级 安装matplotlib:pip install matplotlib 安装pandas:pip install pandas 本地C:\Users\Administrator\pip&#xff0c;在此目录配置清华园的远程下载 配置内容&#xff1a; [global] index-urlhttps://pypi.tuna.tsinghua.edu.cn/simple [install] trusted-ho…...

使用关键字interface来声明使用接口-PHP8知识详解

继承特性简化了对象、类的创建&#xff0c;增加了代码的可重用性。但是php8只支持单继承&#xff0c;如果想实现多继承&#xff0c;就需要使用接口。PHP8可以实现多个接口。 接口类通过关键字interface来声明&#xff0c;接口中不能声明变量&#xff0c;只能使用关键字const声明…...

计算机毕业设计 基于SSM的高校毕业论文管理系统小程序的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb;…...

【Java 进阶篇】JDBC查询操作详解

在数据库编程中&#xff0c;查询是一项非常常见且重要的操作。JDBC&#xff08;Java Database Connectivity&#xff09;提供了丰富的API来执行各种类型的查询操作。本篇博客将详细介绍如何使用JDBC进行查询操作&#xff0c;包括连接数据库、创建查询语句、执行查询、处理结果集…...

我的企业证书是正常的但是下载应用app到手机提示无法安装“app名字”无法安装此app,因为无法验证其完整性解决方案

我的企业证书是正常的但是下载应用app到手机提示无法安装“app名字”无法安装此app&#xff0c;因为无法验证其完整性解决方案 首先&#xff0c;确保您从可信任的来源下载并安装企业开发者签名过的应用程序。如果您不确定应用程序的来源&#xff0c;建议您联系应用程序提供者…...

【数据结构】排序(2)—冒泡排序 快速排序

目录 一. 冒泡排序 基本思想 代码实现 时间和空间复杂度 稳定性 二. 快速排序 基本思想 代码实现 hoare法 挖坑法 前后指针法 时间和空间复杂度 稳定性 一. 冒泡排序 基本思想 冒泡排序是一种交换排序。两两比较数组元素&#xff0c;如果是逆序(即排列顺序与排序后…...

Redis与分布式-分布式锁

接上文 Redis与分布式-集群搭建 1.分布式锁 为了解决上述问题&#xff0c;可以利用分布式锁来实现。 重新复制一份redis&#xff0c;配置文件都是刚下载时候的不用更改&#xff0c;然后启动redis服务和redis客户。 redis存在这样的命令&#xff1a;和set命令差不多&#xff0…...

docker安装nginx详解

创建html的挂载目录docker volume create nginx8020 创建conf的挂载目录mkdir -p /opt/nginx/conf 拉取镜像docker pull nginx 初始化挂载目录的配置文件docker run --rm --name nginx-short -p 8020:80 -d nginx docker cp nginx-short:/etc/nginx/nginx.conf /opt/nginx/…...

优化思考二

优化思考一_云湖在成长的博客-CSDN博客 翻到了两年前写文章&#xff0c;有了不一样的观点。 先说一样的想法吧&#xff1a;数据&#xff08;输入&#xff09;>>优化模型&#xff08;处理&#xff09;>>结果方案&#xff08;输出&#xff09;。优化是其中最重要的…...

大模型微调概览

文章目录 微调 和 高效微调高效微调技术方法概述高效微调方法一:LoRA高效微调方法二: Prefix Tuning高效微调方法三: Prompt Tuning高效微调方法四: P-Tuning v2基于强化学习的进阶微调方法RLHF 训练流程微调 和 高效微调 微调,Fine-Tuning, 一般指全参数的微调(全量微调),…...

利用norm.ppfnorm.interval分别计算正态置信区间[实例]

scipy.stats.norm.ppf用于计算正态分布的累积分布函数CDF的逆函数&#xff0c;也称为百分位点函数。它的作用是根据给定的概率值&#xff0c;计算对应的随机变量值。scipy.stats.norm.interval&#xff1a;用于计算正态分布的置信区间&#xff0c;可指定均值和标准差。scipy.st…...

计算机网络各层设备

计算机网络通常被分为七层&#xff0c;每一层都有对应的设备。以下是各层设备的简要介绍&#xff1a; 物理层&#xff08;Physical Layer&#xff09;&#xff1a;负责传输二进制数据位流的物理媒体和设备&#xff0c;例如网线、光纤、中继器、集线器等。 数据链路层&#xf…...

java this用法

在Java中&#xff0c;this是一个关键字&#xff0c;表示当前对象。它可以用来引用当前对象的实例变量、实例方法或者调用当前对象的构造方法。在本文中&#xff0c;我们将深入探讨Java中this关键字的用法。 1. 引用当前对象的实例变量 在Java中&#xff0c;this关键字可以用来…...

【AI视野·今日NLP 自然语言处理论文速览 第四十六期】Tue, 3 Oct 2023

AI视野今日CS.NLP 自然语言处理论文速览 Tue, 3 Oct 2023 (showing first 100 of 110 entries) Totally 100 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers Its MBR All the Way Down: Modern Generation Techniques Through the …...

wordpress EDD Alipay/关键词seo排名公司

在亚马逊云科技&#xff0c;有着这么一群人&#xff0c;他们经常被认为只会写代码&#xff0c;而不善言辞。但这只是大家对他们的误解。他们的工作不仅需要懂开发、善沟通&#xff0c;还需要能够dive deep用户的需求。他们就是亚马逊云科技的 Software Dev Engineer&#xff01…...

绵阳的网站建设/可以免费打开网站的软件

laravel给我们提供了多渠道的消息通知功能&#xff0c;包括邮件,短信,数据库,slack等通知方式。本文主要分析基于数据库的消息通知的底层实现。为了方便&#xff0c;本文将需要接受通知消息的模型称为接收者。 ps:阅读本文前&#xff0c;请不了解Eloquent关联关系的读者先点击e…...

敦煌做网站 条件/已备案域名30元

React Hooks+Laravel 前端博客实战 阐述用create-next-app快速创建项目建立博客首页按需加载 Ant Design配置文件 blog\package.json阐述 我们先完成博客的前端界面的制作,主要完成的功能就是用户的访问,文章列表和文章详情页面。 因为Blog的前台需要SEO操作,所以我们一定…...

电子商务网站建设商城网站/关键词快速排名软件价格

原则一&#xff1a;注意WHERE子句中的连接顺序&#xff1a; ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前, 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾. 尤其是“主键ID&#xff1f;”这样的条件。 原则二&…...

利用jsp做网站/外贸高端网站设计公司

创建ISO文件命令&#xff1a; hdiutil makehybrid -o temp.iso foldertoadd 创建temp.iso文件&#xff0c;并把foldertoadd文件夹加入到temp.iso文件。 下面文章转自http://www.1mima.com/mac-os-x下dmg和iso文件之间的转换/ 听说Windows平台下ultraiso可以直接将dmg文件转换为…...

wordpress本地如何安装/网站托管维护

libevent学习笔记十四&#xff1a;libevent 信号处理实例代码 上一节介绍了libevent 实现多线程的方法&#xff0c;然而在多线程的环境中注册信号事件&#xff0c;还是有一些情况需要小心处理&#xff0c;那就是不能在多个 libevent 实例上注册信号事件。依然冠名追加到 libeve…...