我正在使用离子3和firebase构建应用程序。基本上,我希望能够拍摄多张照片,将它们上传到firebase存储,然后获取指向这些照片的链接并将这些链接放在firestore中的文档中。但是,我遇到包含downloadURL的数组的奇怪行为。如果我运行该函数一次,它会将文档上传到firestore,但带有下载链接的数组为空。如果我第二次运行该功能,链接会显示出来。这是我的代码:
变量:
export class AboutPage {
public photos: any;
public downloadURLs: any;
public link: string;
public base64Image: string;
ngOnInit() {
this.photos = [];
this.downloadURLs = [];
}
功能:
// Note: The uploading of the images works completely fine
uploadForm() {
//var testArray = [];
var kuerzel = "teacher";
var lehrerKuerzel = kuerzel.toUpperCase();
var date = Date();
var length = this.photos.length;
var i = 0;
while(i < length){
const ref = firebase.storage().ref(`pruefungen/${lehrerKuerzel}/${date}/${i}`);
ref.putString(this.photos[i], 'data_url').then((snapshot) => {
this.downloadURLs.push(snapshot.downloadURL);
});
if(i + 1 == length)
{
var db = firebase.firestore().collection(`${lehrerKuerzel}`);
db.add({
TestName: pruefungsName,
Klasse: klasse,
Abteilung: abteilung,
Datum: date,
DownloadURLs: this.downloadURLs,
Length: length,
I: i
});
}
i += 1;
}
}
我尝试过:
使用本地数组
放入db.add({});在.then()中,当数组总是完全显示时,包含i的if语句总是为true,因为某些原因我总是== length。因此,集合中的项目总是太多。
答案 0 :(得分:3)
上传功能res.putString
异步工作,这意味着您的while
循环在文件实际上传之前运行完成,因此this.downloadURLs === []
当时记录被添加,并且只有在照片一个接一个地完成时才会在以后填充。
您应该在添加记录之前等待所有上传完成,因此您已经拥有要在数据库上写入的所有下载URL。
一种方法是使用Observable ForkJoin,在this page中描述为:
如果您熟悉Promises,这与Promise.all()非常相似。 forkJoin()运算符允许我们获取Observable列表并并行执行它们。一旦列表中的每个Observable都发出一个值,forkJoin就会发出一个Observable值,该值包含列表中Observables的所有已解析值的列表。
该文章为您提供了处理此类要求的各种示例。
在您的特定情况下,我建议您在循环中进行存储调用数组,然后使用ForkJoin等待结果然后创建记录,如下所示:
// extra import you'll need
import { forkJoin } from "rxjs/observable/forkJoin";
var kuerzel = "teacher";
var lehrerKuerzel = kuerzel.toUpperCase();
var date = Date();
var upload = this.photos.map(i => {
const ref = firebase.storage().ref(`pruefungen/${lehrerKuerzel}/${date}/${i}`);
return ref.putString(i, 'data_url');
});
forkJoin(upload).subscribe(results => {
// results is an array of snapshots
var db = firebase.firestore().collection(`${lehrerKuerzel}`);
db.add({
TestName: pruefungsName,
Klasse: klasse,
Abteilung: abteilung,
Datum: date,
DownloadURLs: results.map(i => i.downloadURL),
Length: this.photos.length,
I: this.photos.length - 1
});
});
Haven未对代码进行测试,但该想法应该有效,您可以在链接文章中找到更完整的示例。
答案 1 :(得分:1)
使用promises
与Promise.all
:
...
let promises = [];
while(i < length){
promises.push(new Promise(resolve, reject) {
const ref = firebase.storage().ref(`pruefungen/${lehrerKuerzel}/${date}/${i}`);
ref.putString(this.photos[i], 'data_url').then((snapshot) => {
this.downloadURLs.push(snapshot.downloadURL);
resolve();
}).catch(e => {
console.log(e);
reject();
});
})
i++;
}
Promise.all(promises).then(() => {
var db = firebase.firestore().collection(`${lehrerKuerzel}`);
db.add({
TestName: pruefungsName,
Klasse: klasse,
Abteilung: abteilung,
Datum: date,
DownloadURLs: this.downloadURLs,
Length: length,
I: i
});
})