[英]Javascript for loop not waiting for .then to finish
我有以下代码从 Firebase 中检索一些文件信息:
function loadUserProfileKeys(key) {
// Get the Firebase storage ref for the InitialUserProfiles folder
var storageRef = firebase.storage().ref();
var initialUserProfilesRef = storageRef.child('InitialUserProfiles'); // .txt files folder
// Array
const keyResults = [];
// Retrieve all profiles
initialUserProfilesRef.listAll()
.then(function(res) {
// Loop over each item
for (const itemRef of res.items) {
console.log("Start for loop");
// Ignore profiles with symbols (workaround - TODO: fix this)
if (/,|&/.test(itemRef.name)) {} else {
// Path of the file
var pathRef = initialUserProfilesRef.child(itemRef.name);
// Get the file's download URL
var downloadURL = pathRef.getDownloadURL()
.then((url) => {
// Get the given key from the user profile text file
getValueKey(url, key)
.then((value) => {
// Add it to the keyResults array
keyResults.push(value);
});
});
}
}
console.log("End for loop");
console.log(keyResults);
}).catch((error) => {
console.log("ERROR");
console.log(error);
});
}
async function getValueKey(fileURL, key) {
let response = await fetch(fileURL);
if (response.status == 200) {
let json = await response.text(); // (3)
var lines = json.split("\n");
var results = [];
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
var pairs = line.split(":");
if (pairs.length == 2 && pairs[0].trim() == key) {
results.push(pairs[1].trim());
}
}
return Promise.resolve(results[0]);
}
}
日志记录本身很好 - 在所有循环(即多个“循环开始”日志)完成之前,它不会记录“循环结束”。 问题是这仍然在keyResults.push(value);
之前。 被调用 - 因此数组是空的(或者偶尔只是部分填充)。
如何让var downloadURL = pathRef.getDownloadURL()
和getValueKey(url, key)
阻塞 - 以便在调用嵌套的.then((value)
以添加到数组之前它不会遍历循环?
我无法弄清楚异步等 - 我不断收到语法错误。
function loadUserProfileKeys(key) {
// Get the Firebase storage ref for the InitialUserProfiles folder
var storageRef = firebase.storage().ref();
var initialUserProfilesRef = storageRef.child('InitialUserProfiles'); // .txt files folder
const keyResults = Promise.all(initialUserProfilesRef.listAll().then(function(res) {
// Loop over each item
return res.items.map((itemRef) => {
// Ignore profiles with symbols (workaround - TODO: fix this)
if (/,|&/.test(itemRef.name)) {} else {
// Path of the file
var pathRef = initialUserProfilesRef.child(itemRef.name);
// Get the file's download URL
return pathRef.getDownloadURL()
.then((url) => {
// Get the given key from the user profile text file
return getValueKey(url, key)
});
};
});
}));
console.log("End for loop");
console.log(keyResults);
}
async function getValueKey(fileURL, key) {
let response = await fetch(fileURL);
if (response.status == 200) {
let json = await response.text(); // (3)
var lines = json.split("\n");
var results = [];
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
var pairs = line.split(":");
if (pairs.length == 2 && pairs[0].trim() == key) {
results.push(pairs[1].trim());
}
}
return Promise.resolve(results[0]);
}
}
如果要等待多个异步操作全部完成,则需要使用Promise.all()
。
这样的事情应该越来越接近:
const keyResults = Promise.all(initialUserProfilesRef.listAll().then(function(res) {
// Loop over each item
return res.items.map((itemRef) => {
// Ignore profiles with symbols (workaround - TODO: fix this)
if (/,|&/.test(itemRef.name)) {} else {
// Path of the file
var pathRef = initialUserProfilesRef.child(itemRef.name);
// Get the file's download URL
return pathRef.getDownloadURL()
.then((url) => {
// Get the given key from the user profile text file
return getValueKey(url, key)
});
}
}
})
console.log("End for loop");
console.log(keyResults);
我会将loadUserProfileKeys
设为异步 function。
这样你就可以简单地等待你的其他异步函数( pathRef.getDownloadURL()
, getValueKey(url, key)
)。
这是您使用 async 和 await 修改的 Snipped。 我没有测试它,但它应该可以工作。
async function loadUserProfileKeys(key) {
// Get the Firebase storage ref for the InitialUserProfiles folder
var storageRef = firebase.storage().ref();
var initialUserProfilesRef = storageRef.child('InitialUserProfiles'); // .txt files folder
// Array
const keyResults = [];
try {
// Retrieve all profiles
const profileRes = await initialUserProfilesRef.listAll();
// Loop over each item
for (const itemRef of profileRes.items) {
console.log("Start for loop");
// Ignore profiles with symbols (workaround - TODO: fix this)
if (/,|&/.test(itemRef.name)) {} else {
// Path of the file
var pathRef = initialUserProfilesRef.child(itemRef.name);
// Get the file's download URL
var downloadURL = await pathRef.getDownloadURL();
// Get the given key from the user profile text file
keyResults.push(await getValueKey(downloadURL, key));
}
}
console.log("End for loop");
console.log(keyResults);
} catch(error) {
console.log("ERROR");
console.log(error);
}
}
一般来说,我个人建议尽量避免封装.then() 调用。
它只会使代码更难阅读和理解。
我发现 async & await 更干净。
你可以这样做
async function loadUserProfileKeys(key) {
// Get the Firebase storage ref for the InitialUserProfiles folder
var storageRef = firebase.storage().ref();
var initialUserProfilesRef = storageRef.child('InitialUserProfiles'); // .txt files folder
// Array
const keyResults = [];
// Retrieve all profiles
const res = await initialUserProfilesRef.listAll();
// Loop over each items
res.items.forEach(async (itemRef) => {
console.log("Start for loop");
// Ignore profiles with symbols (workaround - TODO: fix this)
if (/,|&/.test(itemRef.name)) {
// skip
} else {
// Path of the file
const pathRef = initialUserProfilesRef.child(itemRef.name);
// Get the file's download URL
const url = await pathRef.getDownloadURL();
// Get the given key from the user profile text file
const value = await getValueKey(url, key);
.
// Add it to the keyResults array
keyResults.push(value);
}
});
console.log("End for loop");
console.log(keyResults);
}
async function getValueKey(fileURL, key) {
let response = await fetch(fileURL);
if (response.status == 200) {
let json = await response.text(); // (3)
var lines = json.split("\n");
var results = [];
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
var pairs = line.split(":");
if (pairs.length == 2 && pairs[0].trim() == key) {
results.push(pairs[1].trim());
}
}
return Promise.resolve(results[0]);
}
}
所以补充一下 - 这可以按预期工作,但可能不是最佳的 + 可能会稍微整理一下:
async function loadUserProfileKeys(key) {
// Get the Firebase storage ref for the InitialUserProfiles folder
var storageRef = firebase.storage().ref();
var initialUserProfilesRef = storageRef.child('InitialUserProfiles'); // .txt files folder
// Results array
var keyResults = [];
// Retrieve all profiles
const profiles = await initialUserProfilesRef.listAll()
var promises = [];
// Loop over each file
for (const itemRef of profiles.items) {
console.log("Start for loop");
// Ignore profiles with symbols (workaround - TODO: fix this)
if (/,|&/.test(itemRef.name)) {} else {
// Path of the file
var pathRef = initialUserProfilesRef.child(itemRef.name);
// Add to the array of Promises
promises.push(doSomething(pathRef, key));
};
};
// Wait for all Promises to resolve
keyResults = await Promise.all(promises)
console.log("End for loop");
console.log(keyResults);
}
async function doSomething(pathRef, key) {
var downloadURL = await pathRef.getDownloadURL();
var value = await getValueKey(downloadURL, key);
return value
}
async function getValueKey(fileURL, key) {
let response = await fetch(fileURL);
if (response.status == 200) {
let json = await response.text(); // (3)
var lines = json.split("\n");
var results = [];
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
var pairs = line.split(":");
if (pairs.length == 2 && pairs[0].trim() == key) {
results.push(pairs[1].trim());
}
}
return results[0];
}
}
尝试使用async/await语法而不是回调。 否则,您需要在回调中自行删除 for 循环并调用下一次迭代。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.