【问题标题】:How can I repeat an iteration on an element with an exact index in a for loop?如何在 for 循环中对具有精确索引的元素重复迭代?
【发布时间】:2019-06-27 18:51:16
【问题描述】:

我有一个带有 url 的数组,我必须遍历它才能下载 HTML 文件。如果一个 url 没有加载,例如由于连接问题,它的 HTML 文件将不会被下载,因为循环进入下一个迭代的问题。我的目标是,如果发生错误,程序应该重复当前迭代 3 次,然后进入下一个迭代。

这是我想要实现的目标:

let filteredUrls = [ 'url1', 'url2', 'url3'];
for (let id in filteredUrls) {
  let currentUrl = filteredUrls[id];
    try {
      //open currentUrl, do some stuff...
    } catch (error) {
      //if there's an error, repeat the current loop 3 times, 
      //after that, move to the next iteration
    }
}

我该怎么做?有什么办法吗?

【问题讨论】:

  • 从 http 请求中获取响应是异步的。您必须展示如何打开网址并使用响应“做一些事情”。
  • For ... In 可用于数组,但要小心,强烈建议不要使用它(developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • @trincot 我用 puppeteer 的虚拟浏览器打开 url,是的,整个程序是异步的。

标签: javascript arrays loops for-loop


【解决方案1】:

如果您的下载代码是异步的,那么您可能想要使用递归函数,而不是仅仅重新迭代循环。

let filteredUrls = [ 'url1', 'url2', 'url3'];
for (let id in filteredUrls) {
  let currentUrl = filteredUrls[id];
  downloadFile( currentUrl, 0 );
}

function downloadFile( url, tryCount ) {
  try {
    //open currentUrl, do some stuff...
  } catch (error) {
    tryCount++;
    if ( tryCount < 3 ) {
      downloadFile( url, tryCount );
    }
  }
}

【讨论】:

  • 如果它是异步的,几乎可以肯定每次调用都需要以await开头。
  • 在这种情况下,他必须将该回调包装成一个 Promise 和 await 以使您的代码正常工作。
【解决方案2】:

您尚未展示如何获取页面内容,但我假设您使用的是 fetchXMLHttpRequest 之类的东西。如果您使用 fetch,它会返回一个拒绝网络错误的 Promise,这意味着您可以将回调附加到其 .catch() 方法以重试 fetch。如果您使用的是 XMLHttpRequest,它有一个 onerror 事件,您可以附加相同的重试回调。

我建议您将内容获取代码分解为一个函数,该函数接受 URL 和重试次数,然后返回 XMLHttpRequest 或 fetch Promise。这样你就可以让错误回调再次调用相同的函数,但为重试参数传递retries-1

例子:

function fetchWithRetry(url, tries) {
    if (tries <= 0) { return Promise.reject('Could not fetch.'); }
    return fetch(url).catch(() => fetchWithRetry(url, tries - 1));
}

// OR:

function fetchWithRetry(url, tries) {
  if (tries <= 0) { throw new Error('Could not fetch.'); }
  const xhr = new XMLHttpRequest();
  xhr.open('GET', url);
  xhr.onerror = () => fetchWithRetry(url, tries - 1);
  xhr.send();
  return xhr;
}

基于 Promise 的方法更好一些,因为由于 Promise 链接,您的主代码可以假设正在处理重试,您可以附加一个 .then(),如果任何尝试成功,它将运行,以及一个 @ 987654329@ 只有在所有尝试都失败时才会运行。对于 XHR,其基于​​事件的特性意味着如果它必须重试,您的主代码将失去对当前 XHR 的引用。

【讨论】:

    猜你喜欢
    • 2018-08-19
    • 1970-01-01
    • 2014-07-24
    • 1970-01-01
    • 1970-01-01
    • 2015-02-22
    • 2022-12-16
    相关资源
    最近更新 更多