3

我的情况:

let waiting = function () {
  return new Promise(resolve => {
    console.log('awaiting...');
    
    setTimeout(function () {
      resolve();
    }, 1000)
  });
};

let waitingAsync = async function () {
  console.log('start...');

  await waiting();

  console.log('stop...');
};

waitingAsync();
console.log('done...');

代码中有两件事我不明白:

首先:

await waiting();

waiting是一个同步函数(因为它没有async关键字)。那么,为什么我可以等待一个同步函数呢?

第二:

为什么done...完成waitingAsync功能后不能等待消息?

主要问题:waitingAsync是一个异步函数,为什么await调用它时不需要关键字?只是waitingAsync()代替await waitingAsync().

如果我可以 await waitingAsync()done...消息将最后打印。

4

5 回答 5

5

这不是一个函数,而是一个它返回的值,它在await语句中等待。

async正常功能与调用者没有什么不同。async在被调用时只返回一个promise而不显式返回它。调用的结果waitingAsync()是一个承诺。call的结果waiting()也是一个承诺,所以它不是“同步的”。

根据规范,可以await编辑承诺和非承诺。非承诺转换为带有 的承诺Promise.resolve()

console.log('done...')不能等待,因为它没有在async函数内部调用。并且它不必被awaited ,因为它不返回承诺但是undefined. await在功能范围内是可能的async。这些await用法相同且同样无用,它们所做的只是 1 个滴答延迟:

async function ... {
  ...
  await console.log('done...');
}

async function ... {
  ...
  console.log('done...');
  await undefined;
}

async function ... {
  ...
  await Promise.resolve(console.log('done...'));
}
于 2017-01-17T12:41:20.550 回答
3

一个async函数确实返回一个 Promise,或者,当它使用await关键字时,它必须等待一个异步函数,是一个 Promise 或另一个async函数。在您的代码中,waiting()是一个返回 Promise 的函数。然后,await waiting()是正确的(因为它正在等待异步函数)。

一个async函数被调用作为另一个基本函数被调用。当您希望将函数作为异步函数操作并使用“await”关键字时,您可以将其标记为异步。'done...' 被打印出来,因为当你打电话时asyncFunction(),它必须await直到waiting promise完成。但节目并没有停下来继续放映done...。如果你想等待它,也许你可以使用asyncFunction().then( () => console.log('done...') )

于 2017-01-17T13:01:47.243 回答
2

Async用于指定该函数将是一个实例的关键字,AsyncFunction因此它将返回Promise

Await用于等待 async 函数内部的 Promise 解析。


根据 mdn - async 函数可以包含一个await表达式,该表达式暂停 async 函数的执行并等待传递的 promise 的解析,然后恢复 async 函数的执行并返回解析的值。

于 2017-01-17T12:37:08.447 回答
2

当你await是一个函数时,如果该函数返回一个承诺,它的返回值将被视为承诺then值。如果 Promise 将被拒绝,它将被强制转换为错误。如果函数调用返回比 thenable 更重要的东西,await那么,就什么也不做。

另一方面,当你声明一个async函数时,它的返回值将作为 Promise 返回,并且从它抛出的任何错误都将被强制转换为被拒绝的 Promise。

await只能在async声明的函数中使用。

这就是asyncawait只是自动转换为承诺。您实际上并不需要使用 await 和 async 的代码才能真正异步(虽然,它并不是真的有用)。

快速演示:

//Will return the string 'Promise' if called through `await`
function getPromise(){
    return Promise.resolve('Promise');
}

//Casted to Promise.reject thrught await 
function throwError(){
    return Promise.reject('error'); 
}

function get(){
    return 'something simple'; 
}

async function getAsync() {
    var response = await getPromise();
    return response;
}
//await will cast the rejected Promise to an error
async function getErrorAsync() {
    var response = await throwError();
    return response;
}

async function simpleGet(){
    return get();
}

async function redundantGet(){
    return await get();
}

    async function catchTheError(){
      try{
          await throwError();
      }       
      catch(e){
         console.log('an error: ' + e );
      }
       return 'whatever';
 }

getAsync().then( console.log ); //Promise
getErrorAsync().catch( console.log ); //error
simpleGet().then( console.log ); //something simple
redundantGet().then( console.log ); //something simple
catchTheError(); //will log 'an error: error'.

所以:

waiting 是一个同步函数(因为它没有 async 关键字)。那么,为什么我可以等待一个同步函数呢?

因为你能。唯一要做的await就是解决对真实价值和错误的承诺。您实际上并不需要该函数来返回承诺。

完成 waitingAsync 功能后,为什么不能 done... 等待消息?

async并且await只会使您的代码表现得像同步的 isideasync声明函数一样。您的最后一个console.log('done')在任何async函数之外,因此它将在该函数结束之前被记录,因为它是异步的。

主要问题:waitingAsync 是一个异步函数,为什么调用它时不需要 await 关键字?只是 waitingAsync() 而不是 await waitingAsync()。

因为async关键字将值转换为承诺 - 并允许使用await- 仅此而已。事实上,由于您只能使用await内部async函数......您不能期望async通过调用函数await,您将需要无限async函数:-D。

于 2017-01-17T13:10:14.150 回答
0

在潜入之前,最好注意一些事情。
代码片段的任何读者

let waiting = function () {
  return new Promise(resolve => {
    console.log('awaiting...');
    setTimeout(function () { resolve(); }, 1000);
  });
};

let waitingAsync = async function () {
  console.log('start...');
  await waiting();
  console.log('stop...');
};

waitingAsync();
console.log('done...');

可能会误导人们相信输出将是

start...
awaiting...
stop...
done...

done...而——正如你已经注意到的—— stop....

原因是这waitingAsync();是对异步函数的调用,而console.log('done...');只是一个立即执行的正常顺序/同步语句。


问题 1

waiting是一个同步函数(因为它没有async 关键字)[?]

答案
错误。该函数waiting 是同步——它返回一个 Promise


问题 2

为什么done...完成waitingAsync 功能后不能等待消息?


因为console.log('done...')不是异步的
(它不返回Promise。)


问题 3

主要问题:waitingAsync是一个异步函数,为什么 await调用它时不需要关键字?


嗯,在你的例子waitingAsync中没有返回任何值。- 如果它返回一个您关心的值,那么您需要等待它来获取它。
Hello world!在我下面的堆栈片段中。)


问题 4

如果我可以 await waitingAsync(),[the]done...消息将在最后打印 [?]

回答
这取决于你的意思。– 请参阅下面的堆栈片段!只要Done!消息在与 call 相同的回调中打印 await waitingAsync(),答案就是Yes!
但是,如果您console.log('done...?') 调用包含的异步函数之后放置,await waitingAsync()那么答案是否定的!


运行下面的代码片段时,请注意输出的顺序!另请
注意显示需要 1400毫秒Promise resolved!

function waiting () {
  return new Promise(resolve => {
    console.log('awaiting...');
    setTimeout(function () {
      resolve('Hello world!');
      console.log('Promise resolved!');
    }, 1400);
  });
}

async function waitingAsync () {
  console.log('start...');
  const toBeReturned = await waiting();
  console.log('stop...');
  return toBeReturned;
}

(async () => {
  console.log('Heads up! The next line makes an asynchronous call.');
  console.log('Result: ' + await waitingAsync());  // 'Hello world!'
  console.log('Done! This will be printed LAST! - Agreed?');
})();

console.log('done...?? This is LAST in the CODE. - I awaited \
"waitingAsync()" above. - So will this be printed at the very end??');
.as-console-wrapper { max-height: 100% !important; top: 0; }

最后一个异步函数是匿名的——没有名字——并被立即调用。事实上,这是在代码片段中直接调用的唯一函数。函数waitingAsync仅被直接调用(通过匿名函数),并且该函数也被间接调用 (通过)。waitingwaitingAsync

带走的教训

永远不要在调用异步函数之后和之外放置顺序/同步代码!

如果你这样做,你只会让自己感到困惑。– 即使没有感到困惑,您的代码的其他读者也几乎肯定会感到困惑。

于 2021-05-23T16:27:18.413 回答