为什么使用了await却执行了function?

Why function is executed although await is used?

我在主函数中使用了 await 关键字来等待对 poll() 的异步函数调用完成,但对 my_plot 的函数调用是在 poll() 函数完成之前进行的。

async function main() {
    getParametersData()
    await poll()
    my_plot()
} 
async function getData() {
    const response = await fetch(API)
    const message = await response.json()
    return message
}

async function poll(count = 1) {
    console.log(`Polling ${count}`);
    try {
        const data = await getData();
        if (data && Object.keys(data).length !== 0) {
            console.log("Poll", data)
            return;
        } else {
            setTimeout(poll, 5000, ++count);
        }
    } 
    catch (err) {
        console.log(`${err}. Polling again in 5 seconds.`);
        setTimeout(poll, 5000, 1);
    }

}

async function my_plot() {
    console.log("my plot")
}

代码输出:

Polling 1
my plot 
Polling 2
Polling 3
Poll [1,2,3]

预计:

Polling 1
Polling 2
Polling 3
Poll [1,2,3]
my plot

不要直接在 async 函数中使用 setTimeout。相反,使用基于 Promise 的包装器。

令人惊讶的是,现代 ECMAScript 没有随附基于 PromisesetTimeout:

的现成版本
function delay( timeout ) {
    if( typeof timeout !== 'number' || timeout < 0 ) throw new Error( "Timeout must be a non-negative integer milliseconds delay value." );

   return new Promise( function( resolve ) { 
       setTimeout( resolve, timeout );
   });
}
  • 然后你可以用“真正的”while 循环重写你的 poll 函数,如下所示。
  • 我认为你的 poll 函数应该 return 一个 true/false 值来向调用者指示成功或失败,如果你需要的话。
  • 考虑使用 typeof 而不是像 Object.keys(data).length 这样不太安全的检查 - 或者至少使用 typeof 检查 之前使用 Object.keys.
    • 虽然烦人typeof null === 'object',所以你总是需要!== null检查,抱怨...
    • 作为替代方案,考虑拥有自己的类型保护函数(是的,我知道这不是 TypeScript),这样你就可以更强有力地保证 data 包含你需要的东西(就像 JS 那样)没有静态类型检查)。
async function poll( count = 1 ) {
    
    console.log(`Polling ${count}`);
 
    let i = 0;
    do {
        try {
            const data = await getData();
            if( isMyData( data ) ) {
                return true;
            }
        }
        catch( err ) {
            console.error( err );
        }

        console.log( "Polling again in 5 seconds." );
        await delay( 5000 );

        i++;
    }
    while( i < count );

    console.log( `Gave up after ${count} attempts.` );
    return false;
}

// Type-guard:
function isMyData( data ) {
    
    return (
        ( typeof data === 'object' )
        &&
        ( data !== null )
        &&
        ( 'this is my object' in data )
        &&
        ( data['there are many like it but this one is mine'] )
        &&
        ( data.myJavaScriptEngineIsMyBestFriend )
        &&
        data.itIsMyLife
        &&
        data.withoutMe_javaScriptIsUseless
        &&
        data.withoutJavaScript_iAmUseLess > 0
    );
}

请注意,如果您打算捕获 getData 抛出的错误,您应该使用最小范围的 try 而不是在其中包含更多逻辑,因为通常您不想捕获不相关的错误.

使用 How to make a promise from setTimeout 的答案,您可以使用传统循环。

function later(delay, value) {
  return new Promise(resolve => setTimeout(resolve, delay, value));
}

async function poll() {
  for (let count = 1;; count++) {
    console.log(`Polling ${count}`);
    try {
      const data = Math.random(); // simulated data
      if (data < 0.2) { // simulated 20% success rate
        console.log("Poll", data)
        return data;
      } else {
        console.log("Retrying in 5 seconds");
        await later(5000);
      }
    } catch (err) {
      console.log(`${err}. Polling again in 5 seconds.`);
      count = 1;
      await later(5000);
    }
  }
}

async function main() {
  console.log("Start");
  await poll();
  console.log("Poll done");
}

main();