当前位置:网站首页>富媒体在客服IM消息通信中的秒发实践
富媒体在客服IM消息通信中的秒发实践
2022-08-09 11:08:00 【InfoQ】
引言
一、背景
二、面临的挑战

三、解决方案与成效
export function getFileInfo(file: File): Promise<any> {
return new Promise((resolve, reject) => {
try {
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = (event: ProgressEvent<FileReader>) => {
resolve(event)
}
} catch (e) {
reject(e)
}
})
}export function getVideoInfo(file) {
return new Promise((resolve, reject) => {
getFileInfo(file)
.then(fileReader => {
const target = fileReader.target.result
if (/video/g.test(file.type)) {
const video = document.createElement('video')
video.muted = true
video.setAttribute('autoplay', 'autoplay')
video.setAttribute('src', target)
video.addEventListener('loadeddata', () => {
// ...
})
video.onerror = e => reject(e)
}
})
.catch(e => reject(e))
})
}
if (/*******/) {
// ...
//. blob作为预览视频的url
state.previewVideoSrc = URL.createObjectURL(file)
state.previewVideo = true
state.cachePreviewVideoFile = file
nextTick(() => {
focus()
})
} else {
// ...
}
export function getVideoInfo(file, msgid?: string) {
return new Promise((resolve, reject) => {
getFileInfo(file, msgid)
.then(fileReader => {
const target = fileReader.target.result
if (/video/g.test(file.type)) {
const video = document.createElement('video')
video.muted = true
video.setAttribute('autoplay', 'autoplay')
// target只作为url创建视频用于获取视频大小、播放时长等基本信息,不用于页面渲染
video.setAttribute('src', target)
video.addEventListener('loadeddata', () => {
const canvas = document.createElement('canvas')
canvas.width = video.videoWidth
canvas.height = video.videoHeight
const width = video.videoWidth
const height = video.videoHeight
canvas.getContext('2d')!.drawImage(video, 0, 0, width, height)
const src = canvas.toDataURL('image/jpg')
const imgFile = dataURLtoFile(src, `视频_${Math.random()}.png`)
return getImgInfo(imgFile, fileReader.msgid).then(
({ width: imgWidth, height: imgHeight, file: imgFile, size: imgSize, src: imgSrc, msgid }) => {
resolve({
// ...
})
}
)
})
video.onerror = e => {
// ...
reject(e)
}
}
})
.catch(e => {
reject(e)
})
})
}// 拼接的获取图片首帧的URL地址
export const thumbSuffix = `?x-oss-process=video/snapshot,****`
export function addOssImageParams(url, isThumb = false) {
const suffix = isThumb ? thumbSuffix : urlSuffix
if (!url) return ''
// ...
return url
}
- 浏览器主线程在执行发送文件的时候,如果发送文件任务没有结束,则会阻塞其他的任务,相当于发送期间,客服什么事情也做不了;
- 浏览器主子线程在执行发送文件的时候,通过子线程读取文件,在读取文件期间,主线程可以继续执行其他的任务,等到子线程读取完文件通过postMessage发送相关的信息告知主线程文件读取完毕,主线程再开始渲染。整个过程对于客服没有任何阻塞。

// 子线程任务
export function subWork() {
self.onmessage = ({ data: { file } }) => {
try {
// 读取文件信息
// ...
// 发送对应信息
self.postMessage({ fileReader: **** })
} catch (e) {
self.postMessage({ fileReader: undefined })
}
}
}export const createWorker = (subWorker, file, resolve, reject) => {
const worker = new Worker(URL.createObjectURL(new Blob([`(${subWorker.toString()})()`])))
// 发到子线程
worker.postMessage({
file
})
// 监听子线程返回数据
worker.onmessage = ({ data: { fileReader } }) => {
resolve(fileReader)
// 获取到结果后关闭线程
worker.terminate()
}
// 监听异常
worker.onmessageerror = function () {
worker.terminate()
}
}// 创建主线程任务
export const getFileInfoFromSubWorker = files => {
return new Promise((resolve, reject) => {
createWorker(subWork, files, resolve, reject)
})
}export function getVideoInfo(file, blob, msgid?: string) {
return new Promise((resolve, reject) => {
if (/video/g.test(file.type)) {
const video = document.createElement('video')
video.muted = true
video.setAttribute('autoplay', 'autoplay')
// blob作为url: URL.createObjectURL(file)
video.setAttribute('src', blob)
video.addEventListener('loadeddata', () => {
const width = video.videoWidth
const height = video.videoHeight
resolve({
videoWidth: width,
videoHeight: height,
videoDuration: video.duration * 1000,
videoFile: file,
videoSize: file.size,
videoSrc: blob,
msgid
})
})
video.onerror = e => {
reject(e)
}
}
})
}四、总结
五、知识扩展
1、文件读取的实现差异
- 通过FileReader.readAsDataURL(file)获取到的是一段data:base64的字符串,base64位的字符串较大
- 通过URL.createObjectURL(blob)获会创建一个DOMString,其中有包含了文件信息的URL(指定的 File 对象或 Blob 对象)
- createObjectURL是立即的执行
- FileReader.readAsDataURL是(过一段时间)异步执行
- createObjectURL返回一段带hash的url,并且一直存储在内存中,当document被触发了unload或者执行revokeObjectURL进行内存释放;
- FileReader.readAsDataURL返回的是base64的字符串,比blob url消耗更多的内存,不过这个数据会通过垃圾回收机制自动清除。
- 用createObjectURL能够节省性能,获取的速度也更快;
- 如果设备性能足够好,而且想要获取图片的base64,可以用FileReader.readAsDataURL。
2、流媒体、富媒体、多媒体的概念
边栏推荐
猜你喜欢

Netscope: Online visualization tool for neural network structures

wait系统调用

x86异常处理与中断机制(3)中断处理过程

tensorflow实现线性方程的参数调整

无刷无霍尔BLCD电机控制

OpenSSF's open source software risk assessment tool: Scorecards

Preparation for gold three silver four: how to successfully get an Ali offer (experience + interview questions + how to prepare)

Getting Started with MNIST Machine Learning

备战金三银四:如何成功拿到阿里offer(经历+面试题+如何准备)

数论知识点
随机推荐
论文分享 | ACL2022 | 基于迁移学习的论元关系提取
二进制加法
Julia资料收集
OpenSSF's open source software risk assessment tool: Scorecards
自从我使用HiFlow场景连接器后,在也不用担心成为“落汤鸡”了
1005 Spell It Right (20分)
grpc系列-初探grpc 路由注册和转发实现
1006 Sign In and Sign Out (25分)
pip常见命令和更改源文件
Numpy常用操作博客合集
性能测试(05)-表达式和业务关联-json关联
1003 Emergency (25分)
七夕?程序员不存在的~
C语言中信号函数(signal)的使用
美的数字化平台 iBUILDING 背后的技术选型
PTA习题 三角形判断
C语言数组题_校门外的树_标记法
golang源代码阅读,sync系列-Cond
prometheus接入mysqld_exporter
微信小程序——天气查询