在获取请求后执行语句

Executing a statement after a fetch request

我的代码结构如下:

var cdict = new Map();

fetch("randomurl")
.then(res => res.json())
.then(data => {

    for (const obj of data.result) {
        // insert stuff into Map cdict
    }
    counter(0).then(res => {
        console.log(cdict);
    }) 
  
  // ^ here after calling of counter i need to do stuff

});


const cbegin = 0;
const ccount = 10;

function counter(cnt) {
    if (cnt < ccount) {
        setTimeout( () => {
            cnt++;
            
            fetch(someurl)
            .then(res => res.json())
            .then(data => {

                for (const obj of data.result) {
                    // do stuff
                }
                
            })
            .catch(err => {
                console.log(err);
            });

            counter(cnt);
        }, 1000);
    }
}


在执行 counter(0) 调用及其所有提取请求后,我希望执行一行 console.log(cdict);

如何实现?这是调用延迟 1 秒的提取请求的正确方法吗?

不要将 setTimeout 事件队列回调与基于承诺的代码混合 -

const sleep = time =>
  new Promise(resolve => setTimeout(resolve, time))

async function main()
{ console.log("please wait 5 seconds...")
  await sleep(5000)
  console.log("thanks for waiting")
  return "done"
}

main().then(console.log, console.error)

不要每次需要 JSON 时都写 .then(res => res.json())。写一次,重复使用-

const fetchJSON(url, options = {}) =>
  fetch(url, options).then(res => res.json())

async function main()
{ const data = await fetchJSON("path/to/data.json")
  console.log("data received", data)
  return ...
}

main().then(console.log, console.error)

不要尝试在 Promises 之外声明变量并在以后修改它们。你不能return the result of an asynchronous call。异步数据需要包含在承诺中,否则您将在代码中寻找难以发现的错误 -

async function main(urls)
{ const result = []
  for (const u of urls)           // for each url,
  { result.push(await getJSON(u)) // await fetch and append to result
    sleep(1000)                   // wait 1 second
  }
  return result
}

const myUrls =
  [ "foo/path/data.json"
  , "another/something.json"
  , "and/more/here.json"
  ]

main(urls)
  .then(result => /* counter logic */)
  .then(console.log, console.error)

继续抽象你认为合适的 -

// give reusable functions a name; use parameters for configurable behaviour
async function fetchAll(urls, delay = 100)
{ const result = []
  for (const u of urls)
  { result.push(await getJSON(u))
    sleep(delay)
  }
  return result
}

async function counter(urls)
{ const results = await fetchAll(urls) // use our generic fetchAll
  const cdict = /* counter logic... */
  return cdict
}

const myUrls =
  [ "foo/path/data.json"
  , "another/something.json"
  , "and/more/here.json"
  ]

counter(urls).then(console.log, console.error)

如您所见,asyncawait 防止使用 setTimeout.then 回调时发生的嵌套。如果正确使用它们,您的代码将保持平坦,并且您可以以同步方式考虑您的代码。