抖音直播原理解析-如何在 Web 中播放 FLV 直播流
抖音相信大家都听说过,但是知道有 Web 版抖音 的人可能要少一些,和 TikTok 一样抖音也有 Web 版本,可以让我们在浏览器中就可以刷短视频和观看抖音直播。抖音是如何实现在浏览器中直播的呢?本篇文章来解析抖音直播的技术原理。
调试
首先点击 https://live.douyin.com 进入抖音直播页面。
然后随便进入一个直播间并打开开发者工具,查看播放器相关 DOM 结构,如下图所示。
首先可以发现原来抖音也是使用的 xgplayer。另外还可以发现 video
元素的 src
属性是 blob:
开头的视频地址,和我们平时用 video
元素播放的视频有点不一样,要了解为什么视频地址是 blob:
开头的,就需要了解接下来介绍的 MSE API。
Media Source Extensions 介绍
Media Source Extensions API(MSE)媒体源扩展 API 提供了实现无插件且基于 Web 的流媒体的功能,不同于简单的使用 video
元素,video
元素对于开发者来说完全是一个黑盒,浏览器自己去加载数据,加载完了自己解析,解码再播放,这个过程中开发者无法进行任何操作。利用 MSE API 开发者可以自定义获取流媒体数据并且还可以对数据做一些操作。
MSE 的兼容性如下图所示。
可以发现 MSE 的兼容性还算可以,IE 11 都支持。但是号称现代 IE 的 Safari 浏览器的 iphone 版,到现在都还不支持 MSE API,应该是苹果想推广自家的 HLS 协议吧,让你在 iphone 设备上播放流媒体只能用他家的协议。
MSE API 主要有 MediaSource
和 SourceBuffer
两个对象,MediaSource
表示是一个视频源,它下有一个或多个 SourceBuffer
,SourceBuffer
表示一个源数据,比如一个视频分为视频和音频,我们可以创建两个 SourceBuffer
一个用于播放视频,一个播放音频,MSE 架构图如下所示。
通过上图还可以发现 SourceBuffer
下面还细分了 TrackBuffer
,因为你还可以不创建两个 SourceBuffer
,只用一个 SourceBuffer
来播放视频和音频,让它内部自己分离音视频,用不同的解码器进行解码播放。
使用 MSE 播放视频的流程如下图所示。
首先我们使用 fetch 或 XHR 去下载数据,然后做些处理过后,将数据交给 MediaSource
,最后通过 video
元素进行播放,
如何将 MediaSource
和 video
元素连接呢?这就需要用到 URL.createObjectURL
它会创建一个 DOMString
表示指定的 File
对象或 Blob
(二进制大对象) 对象。这个 URL 的生命周期和创建它的窗口中的 dcument
绑定。这就是为什么上面调试中的 video
元素的 src
是一个 blob
开头的字符串。
下面来看看使用 MSE 播放视频的最小代码。
const video = document.querySelector('video')const mediaSource = new MediaSource()
mediaSource.addEventListener('sourceopen', ({ target }) => { URL.revokeObjectURL(video.src) const mime = 'video/webm; codecs="vorbis, vp8"'
const sourceBuffer = target.addSourceBuffer(mime) // target 就是 mediaSource
fetch('/static/media/flower.webm')
.then(response => response.arrayBuffer())
.then(arrayBuffer => {
sourceBuffer.addEventListener('updateend', () => { if (!sourceBuffer.updating && target.readyState === 'open') {
target.endOfStream()
video.play()
}
})
sourceBuffer.appendBuffer(arrayBuffer)
})
})
video.src = URL.createObjectURL(mediaSource)
复制
addSourceBuffer
方法会根据给定的 MIME 类型创建一个新的 SourceBuffer
对象,然后会将它追加到 MediaSource
的 SourceBuffers
列表中。
我们需要传入相关具体的编解码器(codecs)字符串,这里第一个是音频(vorbis),第二个是视频(vp8),两个位置也可以互换,知道了具体的编解码器浏览器就无需下载具体数据就知道当前类型是否支持,如果不支持该方法就会抛出 NotSupportedError
错误。更多关于媒体类型 MIME 编解码器可以参考 RFC 4281。
这里还在一开始就调用了 revokeObjectURL
。这并不会破坏任何对象,可以在 MediaSource
连接到 **video**
后随时调用。它允许浏览器在适当的时候进行垃圾回收。
视频并没有直接推送到 MediaSource
中,而是 SourceBuffer
,一个 MeidaSource
中有一个或多个 SourceBuffer
。每个都与一种内容类型关联,可能是视频、音频、视频和音频等。
HTTP-FLV 介绍
了解了 Web 环境是如何播放流媒体,现在来看看抖音直播是使用的什么流媒体协议吧。打开开发者工具的网络面板,如下图所示。
可以发现抖音直播使用的是 HTTP-FLV 协议,其实不看也知道抖音使用的是 HTTP-FLV,因为国内直播平台全部都使用 HTTP-FLV!所以国内直播基础建设对 HTTP-FLV 支持比较好。但是在国外 HTTP-FLV 几乎没有人用,国外用的最多的是 HLS 和 DASH 协议。
FLV(全称 Flash Video)是一种流媒体格式,由 Adobe 公司开发,并在 2003 年发布。它的出现有效的解决了视频文件在网络上传播放的问题,在当时它是实际意义的 Web 流媒体标准,非常多的流媒体平台都使用它来播放视频。
但是随着技术的进步, HTML5 的 Video 元素,已经替换 Flash 视频播放,目前 Flash 技术已经被弃用,各大流媒体平台也切换到了 HLS 或 DASH 技术来实现 Web 流媒体播放。虽然 Flash 被弃用,在国外 FLV 也几乎没人使用,但是在国内它并没有被弃用,反而被广泛用于国内直播场景,所以了解 FLV 格式还是很有必要的。
要在 Web 环境拉取 flv 直播流,不能使用 XHR,需要使用 fetch
API 去拉流,因为 HTTP-FLV 会用到 HTTP/1.1 的 chunked transfer encoding 功能流式去加载数据,是客户端和服务器建立起一个 HTTP 连接后保持连接不断开,服务器不断发送直播流数据给客户端,类似于 IM 中的长轮询。
下面是使用 fetch
拉流的实例代码。
fetch('./a.flv')
.then((res) => { const reader = res.body.getReader() const pump = async () => { const data = await reader.read(); if (!data.done) pump();
} pump()
})
复制
可能大家还听过 WS-FLV,这是使用 WebSocket 去拉 FLV 流,相比 HTTP-FLV 没啥优势,所以开始尽可能使用 HTTP-FLV。在我看来 WS-FLV 唯一的作用是兼容 IE 11 浏览器,因为 IE 11 是不支持 fetch
的,并且 IE 自带的 MSStream
又有很多问题,这时候只有用 WebSocket 去拉流。
FLV 格式
接下来让我们再更深入了解下 FLV 文件格式,FLV 格式的文件构成是比较简单的,整个文件是由一个文件头和一个文件体组成,文件体是由一个个标签组成。
FLV 文件头
FLV 文件由 9 个字节的文件头开始,FLV 文件头结构如下表所示。
字段 | 类型 | 描述 |
---|---|---|
签名 | UI8 | 字节 0x46 表示字符 F |
签名 | UI8 | 字节 0x4C 表示字符 L |
签名 | UI8 | 字节 0x56 表示字符 V |
版本 | UI8 | 该 FLV 文件版本 |
保留 | UB[5] | 5 个比特的保留段,必须为 0 |
音频标识 | UB[1] | 1 比特,表示该文件是否存在音频 |
保留 | UB[1] | 1 比特的保留段,必须为 0 |
视频标识 | UB[1] | 1 比特,表示该文件是否存在视频 |
数据偏移 | UI32 | 表示文件体在整个文件的偏移,一般为 9,也就是文件头的大小 |
FLV 文件体
FLV 文件头之后就是文件体,文件体是由上一个 FLV 标签大小和 FLV 标签循环组成,如下表所示。
字段 | 类型 | 描述 |
---|---|---|
前标签大小 | UI32 | 总是为 0,因为它之前没有 FLV 标签 |
FLV 标签 | FLVTAG | 第一个 FLV 标签 |
前标签大小 | UI32 | 第一个 FLV 标签大小 |
… | … | … |
最后一个 FLV 标签 | FLVTAG | 最后一个 FLV 标签 |
前标签大小 | UI32 | 最后一个 FLV 标签大小 |
需要注意的是,FLV 标签大小是标签它之前的 FLV 标签大小,所以第一个标签大小总是为 **0**
。
一共有 3 种类型的 FLV 标签,FLV 标签如下表所示。
字段 | 类型 | 描述 |
---|---|---|
标签类型 | UI8 | 8 表示音频, 9 表示视频, 18 表示脚本数据 |
数据大小 | UI24 | 数据字段的大小 |
时间戳 | UI24 | 该标签数据表示的毫秒单位时间戳,如果是第一个标签则为 0 |
高位时间戳 | UI8 | 表示高位字节 |
流 ID | UI24 | 总是为 0 |
数据字段 | DATA | 该标签中的数据 |
FLV 标签中的数据字段的结构会因为标签的类型不同而不同,音频标签数据字段为 AUDIODATA
,视频标签为 VIDEODATA
,脚本数据标签为 SCRIPTDATAOBJECT
。
FLV 音频标签
音频 FLV 标签数据字段结构如下表所示。
字段 | 类型 | 描述 |
---|---|---|
音频类型 | UB[4] | 该音频数据的类型2 为 MP37 为 G711 A-law8 为 G711 mu-law10 为 AAC |
音频采样率 | UB[2] | 0 表示 5.5kHz1 表示 11kHz2 表示 22kHz3 表示 44kHz(对于 AAC 编码将一直是 3) |
音频位深 | UB[1] | 0 表示 8Bit1 表示 16Bit |
音频声道 | UB[1] | 0 表示单声道1 表示立体声(对于 AAC 编码将总是 1) |
音频数据 | DATA | 如果是 AAC 编码为 AACAUDIODATA,否则音频数据根据音频编码不同而不同 |
对于常用的 AAC 编码的音频数据,FLV 规范还定义了 **AACAUDIODATA**
数据结构,如下表所示。
字段 | 类型 | 描述 |
---|---|---|
AAC 包类型 | UI8 | 描述接下来 AAC 数据的类型0 为 AAC 配置1 为 AAC 帧数据 |
AAC 数据 | UI8[n] | 如果 AAC 包类型是 0 为 AudioSpecificConfig,1 为 AAC 帧数据 |
FLV 视频标签
视频 FLV 标签数据字段结构如下表所示。
字段 | 类型 | 描述 |
---|---|---|
帧类型 | UB[4] | 1 表示 I 帧2 表示非 I帧 |
编码 ID | UB[4] | 视频编码 ID,7 表示 AVC 编码 |
视频数据 | DATA | 根据编码 ID 不同而不同,7 为 AVCVIDEOPACKET |
编码 ID 一般为 7
表示 AVC 编码,官方规范是不支持 HEVC 编码的,但是现在 HEVC 编码越来越流行,所以社区一般把编码 ID 12
定义为 HEVC 编码。
AVCVIDEOPACKET
表示 AVC 视频数据结构,它的结构如下表所示。
字段 | 类型 | 描述 |
---|---|---|
AVC 数据类型 | UI8 | 0 表示视频配置 AVCDecoderConfigurationRecord1 表示一个或多个 NAL2 表示 AVC 序列结束 |
CTS | SI24 | 有符号整数,毫秒,表示该帧 PTS 和 DTS 时间差 |
AVC 数据 | UIB[n] | AVC 数据类型为 0 表示 AVCDecoderConfigurationRecord 数据1 表示一个或多个 NAL 数据 |
关于 AVCDecoderConfigurationRecord
数据结构,请查看 ISO 14496-15 的第 5.2.4.1 章节。
FLV 数据标签
FLV 视频元数据存放在 FLV 数据标签里面,它的结构如下表所示。
字段 | 类型 | 描述 |
---|---|---|
对象 | SCRIPTDATAOBJECT[] | 多个脚本数据对象 |
结束 | UI24 | 总是为 9,表示结束 |
**SCRIPTDATAOBJECT**
描述的是一个对象,它由一个键值对组成,结构如下表所示。
字段 | 类型 | 描述 |
---|---|---|
键 | SCRIPTDATASTRING | 对象键 |
值 | SCRIPTDATAVALUE | 对象值 |
键和值的数据结构如下表所示。
字段 | 类型 | 描述 |
---|---|---|
类型 | UI8 | 该键或值的类型是什么 |
数组长度 | UI32 | 如果是数组类型,这里是数组长度 |
具体数据 | TYPE | 具体的数据,根据类型不同而不同 |
数据终止符 | TYPE | 如果类型是 3 或 8,表示对象和数组的终止 |
FLV 文件的元信息一般放在 onMetaData
字段中,解析完成 FLV 数据标签后将返回下面这个对象。
interface FLVScriptData {
onMetaData?: {
duration?: number;
width?: number;
height?: number;
videodatarate?: number;
framerate?: number;
videocodecid?: number;
audiosamplerate?: number;
audiosamplesize?: number;
stereo?: boolean;
audiocodecid?: number;
filesize?: number;
}
}
复制
onMetaData
对象的字段含义如下。
duration
是视频的总时长,单位是秒。width
是视频的宽度,单位是像素。height
是视频的高度,单位是像素。videodatarate
是视频的码率,单位是 kb 每秒。framerate
是视频的帧率。videocodecid
是视频的编码 ID,同 FLV 视频标签中的编码 ID。audiosamplerate
是音频的采样率。audiosamplesize
是音频的位深。stereo
表示是否为立体声。audiocodecid
是音频的编码 ID,同 FLV 音频标签中的编码 ID。filesize
是文件的大小,单位是字节
FMP4 格式
MP4 格式相信大家都听说过,MP4 或称 MPEG-4 第 14 部分是一种标准的数字多媒体容器格式,它被定义在 ISO 14496-14 中,是由苹果的 QuickTime 视频格式演化而来(也就是我们常见的 .mov
视频格式)。
FMP4 是 fragmented MP4 的缩写,FMP4 更适合流媒体传输,它们的区别如下所示。
这是一个普通的 MP4 文件,可以看到它有一个很大的 mdat
(实际电影数据)box
,所有视频元信息都存放在 moov
盒子,所有音视频数据都存放在 mdat
盒子,所以 mp4 格式并不适合流媒体传输。
这是 fragmented MP4 的截图,它是由 ISO BMFF 初始化分片(ftyp
后跟单个电影标题盒子 moov
),加上一个个 moof
和 mdat
盒子组成的视频分片组成,它的元信息和音视频数据分散到一个个的 moof
和 mdat
盒子中,一次性只加载需要展示的部分,有点类似于前端的瀑布流分页的数据加载。
因为 MP4 格式比 FLV 复杂的多,这里篇幅有限就不再详细介绍了,感兴趣的同学可以去看看 ISO 14496-12。
视频格式
上面之所以介绍 FMP4 格式是因为 MSE API 并不是所有视频格式都支持(比如上面介绍的 flv,或者普通的 mp4 格式就不会支持)根据浏览器的不同,可能支持的视频格式也不同,但是 FMP4 格式所有的浏览器都支持,更多信息可以查看 ISO BMFF Byte Stream Format。
上面介绍的 FLV、MP4、FMP4、MOV 这些全都是视频封装格式,他们就像一个盒子来存放真正的音视频流数据。
所以要在浏览器中播放 flv 直播流,还需要将 flv 视频格式转换成 fmp4 视频格式。根据上面介绍的 flv 文件格式对 flv 进行解析,这个操作一般称为解封装(demux),解析出来音视频等信息数据后,再封装(remux)成 fmp4 视频格式,最后交给 MSE API 来播放。
如上图所示,我们需要将 FLV 格式转换成 FMP4 格式,其中的音视频流是不变的,这个操作也称为转封装。
整体播放流程
那么在 Web 中播放 HTTP-FLV 直播流的整体流程如下所示。
- 首先使用
fetch
去拉 flv 直播流。 - 使用 HTTP/1.1 的 chunked transfer encoding 功能,流式下载视频 chunk 片段。
- 使用
FlvDemuxer
流式解封装 flv 视频流。 - 对视频流进行修复做音视频同步。(一些音视频流可能会有问题)
- 使用
FMP4Remuxer
将视频流封装成 FMP4 格式。 - 最后将封装好的 FMP4 片段数据交给 MSE 播放。
上面 FlvDemuxer
和 FMP4Remuxer
的代码需要自己根据 flv 和 fmp4 文件格式编写,将 flv 中的每一帧的音频、视频和元信息都解出来,然后再将它们封装成 fmp4 格式。
总结
本篇文章讲解抖音直播的技术原理,它是使用 HTTP-FLV 来播放直播流,不光是抖音在使用 HTTP-FLV 直播方案,国内几乎所有的直播平台都在使用 HTTP-FLV 方案,所以看完这篇文章相当于了解了国内所有平台的直播技术直播原理。不过各个平台会在 HTTP-FLV 基础上加点自己的东西,例如斗鱼直播还使用了 P2P 技术来节省服务器流量。相比和其他平台用一样直播方案的抖音直播,抖音短视频播放原理其实更有意思,下次将分享抖音短视频技术原理。
转自:https://cloud.tencent.com/developer/article/2160220?areaSource=102001.10&traceId=tUXCHGXm8t75PfQpCdmA4
相关文章:

常见的七种加密算法及实现
**数字签名**、**信息加密** 是前后端开发都经常需要使用到的技术,应用场景包括了用户登入、交易、信息通讯、`oauth` 等等,不同的应用场景也会需要使用到不同的签名加密算法,或者需要搭配不一样的 **签名加密算法** 来达到业务目标。这里简单的给大家介绍几种常见的签名加密算法和一些典型场景下的应用。## 正文### 1. 数字签名**数字签名**,简单来说就是通过提供 **可鉴别** 的 **数字信息** 验证 **自身身份** 的一种方式。一套 **数字签名** 通常定义两种 **互补

每天一个摆脱if-else工程师的技巧——优雅的参数校验
在日常的开发工作中,为了程序的健壮性,大部分方法都需要进行入参数据校验。最直接的当然是在相应方法内对数据进行手动校验,但是这样代码里就会有很多冗余繁琐的if-else。throw new IllegalArgumentException("用户姓名不能为空");throw new IllegalArgumentException("性别不能为空");throw new IllegalArgumentException("性别错误");

计算机世界的“十六进制”为什么如此重要
在计算机世界中,十六进制扮演着不可或缺的角色。它以其紧凑的表示形式、与二进制的天然对应关系以及在各个领域的广泛应用,成为了计算机科学中的一把重要工具。总体而言,计算机需要十六进制并非偶然,它是一种为了更好地满足人类理解和处理数据的需求而产生的工具,为计算机科学的发展和应用提供了便利和支持。

面试官:如何实现10亿数据判重?
以 Java 中的 int 为例,来对比观察 BitMap 的优势,在 Java 中,int 类型通常需要 32 位(4 字节*8),而 BitMap 使用 1 位就可以来标识此元素是否存在,所以可以认为 BitMap 占用的空间大小,只有 int 类型的 1/32,所以有大数据量判重时,使用 BitMap 也可以实现。所以数据库去重显然是不行的。而使用集合也是不合适的,因为数据量太大,使用集合会导致内存不够用或内存溢出和 Full GC 频繁等问题,所以此时我们的解决方案通常是采用布隆过滤器来实现判重。

希腊字母表及读音
序号大写小写国际音标中文读音意义1Ααa:lf阿尔法角度;系数2Ββbet贝塔磁通系数;角度;系数3Γγga:m伽马电导系数(小写)4Δδdelt德尔塔变动;密度;屈光度5Εεep`silon伊普西龙对数之基数6Ζζzat截塔系数;方位角;阻抗;相对粘度;原子序数7Ηηeit艾塔磁滞系数;效率(小写)8Θθθit西塔温度;相位角9Ιιaiot约塔

Velocity Engine基础
回到顶部Velocity是一个基于Java的模板引擎,可以通过特定的语法获取在java对象的数据 , 填充到模板中,从而实现界面和java代码的分离!Velocity Template Language (VTL) , 是Velocity 中提供的一种模版语言 , 旨在提供最简单和最干净的方法来将动态内容合并到网页中。简单来说VTL可以将程序中的动态数展示到网页中注释非解析内容 , 引用和指令。

第三方消息推送回调Java app消息推送第三方选择
由于最先集成的是极光,因此根据官方给的推送设备区分方式中,选择了使用标签tag来进行区分管理方式,其接口提供了设置和清理标签, 每次设置会覆盖上次的结果,当然这个需要和极光后台进行交互,是异步返回的。5、由于其接口没有使用免费和付费区分,对于接口的访问没有限制,从使用的情况来看,经常会出现不准的情况,并且设置标签的效果其实是添加,导致业务需要改变标签时,需要先清除在设置,然而接口又经常出问题,导致这部分也是一塌糊涂了;如果想使用不受免费版本限制特性的推送服务,可以联系平台提供的商务对接,购买付费版本。

为什么前后端都需要进行数据校验?
前端和后端各自的数据完整性校验是相辅相成的。前端校验可以提供即时反馈和优化用户体验,减轻后端服务器压力;后端校验是最终的安全防线,确保数据的完整性和一致性。通过前后端的数据完整性校验机制的结合,可以提供更可靠和安全的应用程序。

国内第三方移动推送对接调查:Android、IOS、Flutter,各种云推送、个推、极光、统一推送联盟
第三方移动推送对接,刚开始是移动端发起的。在开会讨论这个对接时,心里突然很迷茫,为什么要做第三方移动推送对接?我们自己为什么不能做移动推送?话说,项目里目前所使用的推送就是自己做的。但是在App离线情况下,消息就收不到了。想起来了,这是最最重要的问题,是为了在离线的情况下,App还能收到通知和消息。如果不是因为这个,这个对接可以不做。因为手机端的app层不出穷太多了,为了给手机省电,用户会主动把运行在前端的app给咔嚓掉…虽然咔嚓掉,但是在有信息的情况下,用户还是希望能够收到信息。

浏览器兼容video视频播放的多种方法&视频在浏览器播放格式,视频浏览器播放格式演示
对于老版本的IE可以通过HTML5shiv来使不支持HTML5的浏览器支持HTML新标签video和audio标签。主要解决HTML5提出的新的元素不被IE6/IE7/IE8识别,这些新元素不能作为父节点包裹子元素,且不能应用CSS样式。让CSS 样式应用在未知元素只需执行 document.createElement(elementName) 即可实现。html5shiv的工作原理也就是基于此。

手机的ip地址是固定的吗,每个手机ip地址一样吗?
简单点说,路由器开启了“DHCP功能”,会自动给连接路由器网络的设备自动分配IP地址,这包括有线网络和无线网络;当设备开启了DHCP功能之后,在路由器开启了DHCP功能的前提下,就会自动接收路由器分配的IP地址,不需要用户手动设置静态IP地址,用通俗的话来形容“DHCP”,它可以省去用户手动设置IP地址的过程。

说说你对 TypeScript 的理解?与 JavaScript 的区别?
超集,不得不说另外一个概念,子集,怎么理解这两个呢,举个例子,如果一个集合 A 里面的的所有元素集合 B 里面都存在,那么我们可以理解集合 B 是集合 A 的超集,集合 A 为集合 B 的子集。其是一种静态类型检查的语言,提供了类型注解,在代码编译阶段就可以检查出数据类型的错误。通过类型批注提供在编译时启动类型检查的静态类型,这是可选的,而且可以忽略而使用。如果缺乏声明而不能推断出类型,那么它的类型被视作默认的动态。等数据格式,对象的类型就是用接口来描述的。的语法,所以任何现有的。对于基本类型的批注是。

在 Spring MVC 中,用于接收前端传递的参数的注解常用的有以下几种
form-data参数使用multipart/form-data作为Content-Type,前端使用params格式传参,后端使用@RequestParam注解接收参数。- json请求体参数使用application/json作为Content-Type,前端使用data格式传参,后端使用@RequestBody注解接收参数。- 路径传参不需要设置Content-Type,前端将参数通过URL传递,后端使用@PathVariable注解接收参数。

在react中说说对受控组件和非受控组件的理解?以及应用场景
这时候当我们在输入框输入内容时,会发现输入的内容无法显示出来,此时input标签是一个可读的状态,因为value被this.state.username所控制,当用户输入时,this.state.username不会自动更新,这样的话input的内容就不会发生变化了,想要解除被控制,可以为input标签设置onChange事件,触发的时候更新state,从而导致input框内容更新。简单来讲,就是受我们控制的组件,组件的状态全程响应外部数据。

Python中如何简化if...else...语句
我们通常在Python中采用if...else..语句对结果进行判断,根据条件来返回不同的结果,如下面的例子。这段代码是一个简单的Python代码片段,让用户输入姓名并将其赋值给变量user_input。我们能不能把这几行代码进行简化,优化代码的执行效率呢?以下是对各行代码的解读。这里使用了or这个逻辑运算符,当user_input不为空时,user_input为真,name就被赋于user_input的值。采用这种方法可以轻松实现if...else语句的简化。我们可以使用一行简短的代码来实现上面的任务。

vue3 项目中 arguments 对象获取失败问题
在 vue3 项目中获取到的 arguments 对象与传入实参不符,打印出函数中的 arguments 对象如下...

前端JS代码中Object类型数据的相关知识
遍历JavaScript中的对象有几种方法,包括使用for…in循环、Object.keys()方法、Object.values()方法和Object.entries()方法。因此前端传入了日期类型数据之后,如果和后台数据库中的数据类型不一致,比如数据库中的日期数据类型格式是。前端传入的Object对象中其中某个字段值是日期类型的数据,则在前端的类型就是一个。,则数据传往后端之前需要做格式类型转换。,它的值是一个中国标准时间,比如。

深入解析JavaScript的原生原型
在JavaScript中,除了自定义对象,还存在很多由JavaScript语言本身提供的原生对象。这些原生对象同样基于原型继承机制,拥有自己的原型。理解原生对象的原型非常重要,可以让我们正确使用这些内置对象,也有助于进一步理解JavaScript的原型继承系统。本文将详细解析原生对象的原型结构,揭开一些常见原生对象原型的神秘面纱。学习原生对象的原型关系,有助于我们在日常开发中正确理解和使用这些JavaScript内置对象,避免一些常见陷阱。

深入解析JavaScript中new Function语法
Function是JavaScript中非常重要的内置构造函数,可以用来动态创建函数。new Function语法就是其中一种函数创建方式。但是new Function也有一定的缺点需要注意。本文将带您深入解析new Function语法,了解其应用场景以及需要注意的问题。new Function是动态创建函数的一种方式,但也有缺点。为了更好的代码质量和性能,应该慎用或避免使用。对JavaScript函数和作用域有深入理解,可以编写出更简洁、高效、稳定的代码。。

uniap vue3 组件使用uni.createSelectorQuery() 获取dom报错
批量查询时,结果是按照查询的顺序返回的。由于vue3中没有this,所以使用。

将 RGB 转换为十六进制、生成随机十六进制
RGB是一种加法混色模式,它通过调节红、绿、蓝三个颜色通道的亮度来混合出各种颜色。对于每个颜色通道,取值范围是0到255,0表示该通道对应的颜色分量没有亮度,255表示达到最大亮度。

nodemon(自动重启 node 应用程序)的安装与使用
(2).键入命令 set-ExecutionPolicy remoteSigned。windows 默认不允许 npm 全局命令执行脚本文件,所以需要修改执行策略。全局安装完成之后就可以在命令行的任何位置运行 nodemon 命令。(4)、再运行 nodemon app.js ok。我们可以执行安装选项 -g 进行全局安装。1、安装,在随意一个命令窗口都可以。自动重启 node 应用程序。(3)、输入Y 或者 A。

如何优化Uniapp应用程序的性能?
避免频繁的重绘和重排:频繁的DOM操作会导致浏览器频繁的重绘和重排,影响性能。使用v-for中的key属性:在使用v-for渲染列表时,为每个列表项添加唯一的key属性,这样可以减少渲染的次数,提高渲染的效率。减少页面加载时间:避免页面过多和过大的组件,减少不必要的资源加载。使用图片懒加载:对于图片较多的场景,可以使用图片懒加载的方式,当图片进入用户可视范围时再进行加载,减少初始页面加载的时间。节流和防抖:对于频繁触发事件的场景,可以使用节流和防抖的方法来减少事件处理的频率,从而提高性能。

优秀的代码都是如何分层的——阿里开发规范
总的来说业务分层对于代码规范是比较重要,决定着以后的代码是否可复用,是否职责清晰,边界清晰。当然这种分层其实见仁见智, 团队中的所有人的分层习惯也不同,所以很难权衡出一个标准的准则,总的来说只要满足职责逻辑清晰,后续维护容易,就是好的分层。最后,如果你的团队有更好的分层,或者上面所描述的有什么错误的地方还请留言指正一下。

鸿蒙开发-ArkTS基础,它与TS区别在那?
ArkTS是HarmonyOS优选的主力应用开发语言。ArkTS围绕应用开发在TypeScript(简称TS)生态基础上做了进一步扩展,继承了TS的所有特性,是TS的超集。说明: 也就是前端开发过程中所有的js/ts语法大部分支持的,比如es6中的箭头函数-模板字符串-promise-async/await-数组对象方法- 注意: 根据对下一代的Next版本的内部沟通,下一版本的ArkTs对类型最了更一步的限制。

vue+element ui实现图片上传并拖拽进行图片排序
vue+element ui实现图片上传并拖住进行图片排序

TypeScript基础知识:类型断言
语法,我们可以将一个值断言为特定类型或将联合类型的变量断言为其中一个类型。在实际开发中,合理使用类型断言可以提高代码的可读性和维护性。中,类型断言是一种强制将一个值视为特定类型的方式。它允许开发人员在编译时指定变量的类型,从而获得更好的类型检查和代码提示。类型断言是一种告诉编译器某个值的具体类型的方法。中的一项强大特性,它允许开发人员在编译时明确指定变量的类型,以获得更好的类型检查和代码提示。中的类型断言,并提供丰富的示例代码帮助读者更好地理解和应用这一特性。将一个联合类型的变量断言为其中一个类型。

2024年,前端必会的console骚操作
调试。程序员们努力地避免的东西,只为在代码中制造更多的错误。编写无错误的代码是即使是最好的程序员也会觉得难以实现的。这就是为什么你应该总是调试代码。而调试JavaScript代码的最好方法之一就是了不起的。除此之外,还有更好的方法。这也正是本文的重点。告诉你与控制台交互的更好方法。在复杂的IDE中输入控制台会出现各种自动补全。在Visual Studio Code中输入console时的自动补全选项。与使用普通的不同,这里有一些更好的选择。使用这些使调试过程变得更加容易和快速。

Vim 粘贴内容时全变成注释的问题
在使用vim粘贴代码时,会出现注释代码后面的代码全被注释的情况。在paste模式下进行复制粘贴就变得很正常了。

OpenHarmony之消息机制实现
以上只是消息机制核外用户态的实现,最后会执行到系统调用以上的内容只是简单介绍了OpenHarmony之消息机制实现,没有具体到代码分析,移植等细节。要想成为一名鸿蒙高级开发,以上知识点是必须要掌握的,除此之外,还需要掌握一些鸿蒙应用开发相关的一些技术,需要我们共同去探索。