前言
在我的开源项目中,很早之前实现了图文混输的功能,但是在解析消息时,解析到图片需要将其上传至服务器拿到图片地址进行特殊拼接,上传图片是异步,解析图片是同步,这就造成了文字消息已经发出去了,图片才开始上传,导致图片拼接失败。
本文就跟大家分享下我解决这个问题的实现思路以及过程,欢迎各位感兴趣的开发者阅读本文。
先跟大家展示下最终实现的效果:
实现思路
正如开头所讲,上传图片是异步,处理文字消息是同步,那么我们想办法让上传图片执行完,拿到图片返回地址后再去执行后续的处理代码,这样就可以解决我们遇到的问题了。
所以,我们现在要做的就是等异步函数执行完再执行同步函数,于是,我想到了await
,我们将上传图片的函数单独提取出来,让其返回一个Promise
对象,将发送消息的函数改为 async function
,这样我们就可以使用await
操作符等待图片上传函数执行完成返回图片地址,将其拼接后继续执行后面的同步代码,完美解决我们遇到的问题。
接下来,我们将上述思路进行整理,如下所示:
- 提取上传图片函数,返回一个Promise对象
- 将发送消息的函数改为异步async
- 解析图片时使用await执行上传图片函数
- 消息文本拼接上传图片函数返回的文件名
await只能用于promise用于等待一个Promise 对象,要使用await当前函数必须为async的异步函数。
实现过程
实现之前先跟大家看下我的消息内容是如何描述图片信息的,如下所示,我们会用//将图片信息包裹起来。
let msgTest = `你好,我是大白/1290219.jpeg?width=658&height=658/`;
提取上传图片函数
将上传图片的函数提取出来,返回一个promise,代码如下所示:
// 上传图片
uploadImage: function(formData: FormData) {
return new Promise((resolve, reject) => {
// 将图片上传至服务器
this.$api.fileManageAPI
.upload(formData)
.then((res: responseDataType) => {
// 文件上传失败
if (!_.isEqual(res.code, 0)) {
alert(res.msg);
reject({ msg: res.msg, code: -1 });
}
// 图片名
let msgImgName = "";
const imgSrc = `${base.lkBaseURL}/uploads/chatImg/${res.fileName}`;
// 获取图片大小
const img = new Image();
let imgWidth = 0;
let imgHeight = 0;
// 赋值图片地址
img.src = imgSrc;
// 判断图片是否有缓存
if (img.complete) {
imgWidth = img.width;
imgHeight = img.height;
msgImgName = `/${res.fileName}?width:${imgWidth}&height:${imgHeight}/`;
resolve({ msg: msgImgName, code: 0 });
} else {
img.onload = () => {
imgWidth = img.width;
imgHeight = img.height;
msgImgName = `/${res.fileName}?width=${imgWidth}&height=${imgHeight}/`;
resolve({ msg: msgImgName, code: 0 });
};
}
});
});
}
修改发送消息函数为异步
这一步很简单,只需要在原函数声明时添加async即可,如下所示:
// 消息发送
sendMessage: async function(event: KeyboardEvent) {
// 其他代码省略,可移步至github查看
}
对消息发送函数代码感兴趣的开发者请移步:sendMessage
使用await执行图片上传函数
我们在sendMessage函数内部,解析到图片时,调用上传函数上传时在其函数前面加上await
,用一个变量接收它,就能拿到我们promise中resolve所返回的数据,代码如下所示。
// 上传图片获取图片地址
const res: { code: number; msg: string } = await this.uploadImage(
formData
);
完整代码在sendMessage中,感兴趣的开发者欢迎移步。
拼接图片信息至消息文本中
上述await会等图片上传函数执行完,将resolve返回的值复制给res,此时我门只需要从res中取值进行拼接即可,代码如下:
// 将图片地址拼接至待发送消息中
msgText += res.msg;
完整代码在sendMessage中,感兴趣的开发者欢迎移步。
实现效果
完成上述步骤后,我们的问题解决了,效果正如文章开头所看到的那样,图文混发的效果QQ是实现了的,但是微信就没实现,不晓得原因,可能正如张小龙所说的:每天都有人在教我做产品😂
文中代码地址:message-display.vue
在线体验地址:chat-system
写在最后
-
文中如有错误,欢迎在评论区指正,如果这篇文章帮到了你,欢迎点赞和关注😊
-
本文首发于掘金,未经许可禁止转载💌
评论区