循环异步引发的思考

循环异步引发的思考

前言

在上一篇思路整理中,我提出了我在开发中困扰了我很久的一个问题,那就是我总是要在获取完一个list后,我还要遍历这个list,对每一个item再进行一次网络请求来获取到一些东西,这样导致我不仅前端速度变慢了,而且代码也写的和💩一样,总是在解决异步的问题。所以这次我把这个问题总结出来写一篇来提醒自己。

首先先摆出结论:循环异步是最好不要在代码中出现的,如果出现了这个问题,大概率不是前端开发者的问题,问题在于后端数据库表设计存在缺陷

问题描述

那么首先我描述一下产品需求和现阶段我发现的问题。这是一款社交产品,用户需要在这个产品的聊天室中进行聊天。那么聊天列表界面就需要存在以下的功能:

  1. 用户可以看到聊天室列表
  2. 聊天室列表包括每一个聊天室的信息
  3. 聊天室信息需要包括聊天室的id(用户不可见)
  4. 聊天室信息需要包括聊天室的创建时间(用户不可见)
  5. 聊天室信息需要包括聊天室的image

(这里有一个小技巧,在freecodecamp中学到的,因为一个list中,每一个item需要有一个index,而index一般可以使用item.id或者item.key,但是有些后端很蠢的出现了相同的id,所以可以使用创建时间,即createdAt做为index)

接下来是我发现的问题:

  1. 聊天室列表并没有采用分页查找,API接口是一口气把所有的聊天室拿出来的,也就是说假设有2000个聊天室,他就会卡死很久,更不要说对于每一个item还需要去网络请求imageUrl了。(分页问题再开一篇来解释)

  2. 对于获取到的聊天室的list,需要遍历每一个item,通过item.id来获取storage里的imageUrl,再显示。样例代码如下:

    1
    // 我稍后补充

解决方案

解决方案1——修改上传、更新图片时的后端逻辑

可以参考我学习freecodecamp课程中写的社交界面(请确保在可全局访问google的情况下打开),这个项目的服务器端代码位于github上,数据库使用的是firebase,代码片段如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// Upload user profile image
exports.uploadImage = (req, res) => {
const Busboy = require('busboy');
const path = require('path');
const os = require('os');
const fs = require('fs');
const busboy = new Busboy({headers: req.headers});

let imageFileName;
let imageToBeUploaded = {};

busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
if (mimetype !== 'image/jpeg' && mimetype !== 'image/png') {
return res.status(400).json({error: 'Wrong file type submitted'});
}
// my.image.png => ['my','image','png']
const imageExtension = filename.split('.')[filename.split('.').length - 1];
// 235235255324.png
imageFileName = `${Math.round(Math.random() * 100000000000)}.${imageExtension}`;
const filePath = path.join(os.tmpdir(), imageFileName);
imageToBeUploaded = {filePath, mimetype};
file.pipe(fs.createWriteStream(filePath));
});

busboy.on('finish', () => {
admin.storage().bucket().upload(imageToBeUploaded.filePath, {
resumable: false,
metadata: {
metadata: {
contentType: imageToBeUploaded.mimetype
}
}
})
.then(() => {
const imageUrl = `https://firebasestorage.googleapis.com/v0/b/${config.storageBucket}/o/${imageFileName}?alt=media`;
return db.doc(`/users/${req.user.handle}`).update({imageUrl});
})
.then(() => {
return res.json({message: 'Image uploaded successfully'});
})
.catch(err => {
console.error(err);
return res.status(500).json({error: err.code});
})
});

busboy.end(req.rawBody);
};

我在image上传到storage后,立即对user这张数据库表进行update,那么我在前端的逻辑就是上传图片➡️获取图片➡️loading➡️渲染成功

0%