Javascript 嵌套多层异步/等待不';我似乎等不及了

Javascript 嵌套多层异步/等待不';我似乎等不及了,javascript,promise,async-await,Javascript,Promise,Async Await,我有一段代码,简化版如下: let dataStorage1; //declare global vars for easier access later on let dataStorage2; let stopLight = true; //this variable is used to 'mark' an iteration as successful (= true) or //failed (= false) and in need of a retry before continu

我有一段代码,简化版如下:

let dataStorage1; //declare global vars for easier access later on
let dataStorage2;
let stopLight = true; //this variable is used to 'mark' an iteration as successful (= true) or
//failed (= false) and in need of a retry before continuing to the next 
//iteration
let delay = 2000; //the standard time for a delay between api calls

async function tryFetch() {
  try {
    dataStorage1 = await api.fetch('data_type_1'); //fetch needed data trough api, which
    //fills the global variable with an 
    //object
    dataStorage2 = await api.fetch('data_type_2'); //do the same
    stopLight = true; //change the value of stopLight to true, thus marking this iteration
    //as successful
  } catch (err) {
    console.log(err);
    stopLight = false;
  }
}

async function fetchData() {
  stopLight = true; //change the stopLight to default before execution

  await tryFetch(); //fetch data and assign it to variables

  //this section is needed for retrial of fetching after a 2s delay if the first attempt was
  //unsuccessful, which is repeated until it's either successful or critical error occurred
  while (stopLight == false) {
    setTimeout(async () => await tryFetch(), delay);
  }
}

(async function main() {
  await fetchData(); //finally call the function
  setTimeout(main, delay); //repeat the main function after 2s
})();
如您所见,自执行的伪递归
main()
调用
await fetchData()
,然后
fetchData()
调用
await tryFetch()
,最后
tryFetch()
调用
await api.fetch('~')
,正如api中定义的那样

然而,当我启动脚本并在几次迭代后暂停它时,我注意到
dataStorage1
dataStorage2
仍然
未定义。如果我在debugger中一步一步地检查代码,所发生的情况是执行从
fetchData()
的开头开始,移动到
wait tryFetch()行,跳过它,然后进入下一个迭代

作为参考,如果我调用
dataStorage1/2=wait-api.fetch(`~`)main()
的主体中直接使用code>而不进行任何嵌套,它可以完美地工作(除非发生错误,因为它们没有得到正确的处理)


所以,我的问题是我错过了什么?

我认为问题出在这一行:
setTimeout(async()=>await-tryFetch(),delay)。回调中的
await
语句使回调返回的承诺等待,而不是整个函数。因此,
async()=>await-tryFetch()
是一个返回承诺的函数,但不等待该承诺完成

试着用一行代码替换代码

await new Promise((resolve) => setTimeout(resolve, delay));
await tryFetch();

实际上,如果在
async
函数中调用
setTimeout
,则不能期望它对传递给
setTimeout
的回调相关的任何内容执行
wait
。对
setTimeout
的调用立即返回,而
while
循环实际上是一个同步循环。这就是所谓的“忙循环”——阻塞GUI,因为它可能会循环数千次

根据经验,只能使用一次
setTimeout
:定义
delay
函数,然后再也不要使用

还要避免使用全局变量,如
stopLight
:这是一种不好的做法。让异步函数返回一个承诺,该承诺在假设为真时解析,否则拒绝

// Utility function: the only place to use setTimeout
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));

async function tryFetch() {
    try {
        let dataStorage1 = await api.fetch('data_type_1'); 
        let dataStorage2 = await api.fetch('data_type_2'); 
        return { dataStorage1, dataStorage2 }; // use the resolution value to pass results
    } catch (err) {
        console.log(err);
        // retry
        throw err; // cascade the error!
    }
}

async function fetchData() {
    while (true) {
        try { 
            return await tryFetch(); // fetch data and return it
        } catch (err) {} // repeat loop
    }
}

(async function main() {
    let intervalTime = 2000; //the standard time for a delay between api calls

    while (true) { // for ever
        let { dataStorage1, dataStorage2 } = await fetchData();
        // ... any other logic that uses dataStorage1, dataStorage2
        //     should continue here...
        await delay(intervalTime); //repeat the main function after 2s
    }
})();

这不是答案,但有两点您可能需要考虑:(1)通过使
tryFetch()
递归,可以避免
fetchData()和
tryFetch()之间的catch-throw-catch-try\u交互作用;(2) 如果
api.fetch('data\u type\u 1')
api.fetch('data\u type\u 2')
容易失败,那么每次尝试都进行这两次抓取会最大限度地提高失败的机会。通过在每次尝试时将
dataStorage1
dataStorage2
放在“银行”中,可以增加
tryFetch()
成功的机会(这很简单)。如果回迁是可靠的,那么采取这种预防措施就不会有什么损失。