繁体   English   中英

Javascript for 循环不等待。然后完成

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM