简体   繁体   English

如何等待异步函数?

[英]How to await an asynchronous function?

My case:我的情况:

 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...');

There are 2 things I don't understand in the code:代码中有两件事我不明白:

The first:首先:

await waiting();

waiting is a synchronous function (because it doesn't have async keyword). waiting是一个同步函数(因为它没有async关键字)。 So, why can I await a synchronous function?那么,为什么我可以等待一个同步函数呢?

The second:第二:

Why couldn't done... message be awaited after completing waitingAsync function?为什么无法done...完成waitingAsync函数后等待消息?

And main question: waitingAsync is an asynchronous function, why is await keyword not required when calling it?主要问题: waitingAsync是一个异步函数,为什么调用它时不需要await关键字? Just waitingAsync() instead of await waitingAsync() .只是waitingAsync()而不是await waitingAsync()

If I can await waitingAsync() , done... message would be printed last.如果我可以 await waitingAsync()done...消息将最后打印。

This isn't a function but a value that it returns which is awaited with await statement.这不是函数,而是它返回的值,该值由await语句await

async and normal functions aren't different to the caller. async和普通函数与调用者没有什么不同。 async just returns a promise without returning it explicitly when being called. async在被调用时只返回一个承诺而不明确返回它。 The result of waitingAsync() call is a promise. waitingAsync()调用的结果是一个承诺。 The result of waiting() call is a promise, too, so it isn't 'synchronous'. waiting()调用的结果也是一个承诺,所以它不是“同步的”。

According to the spec , both promises and non-promises can be await ed.根据规范,promises 和 non-promises 都可以await Non-promises are converted to promises with Promise.resolve() .使用Promise.resolve()将非承诺转换为承诺。

console.log('done...') can't be awaited because it isn't called inside async function. console.log('done...')不能等待,因为它不是在async函数中调用的。 And it doesn't have to be await ed because it doesn't return a promise but undefined .而且它不必是await ed,因为它不返回 promise 而是undefined await ing it would be possible within async function. awaitasync函数中是可能的。 These await usages are equal and equally useless, all they do is 1 tick delay:这些await用法是相同且同样无用的,它们所做的只是 1 个滴答延迟:

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

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

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

A async function does return a promise or, when it uses the await keyword, it must wait for a asynchronous function, being a Promise or another async function. async函数确实会返回一个承诺,或者,当它使用await关键字时,它必须等待一个异步函数,即一个 Promise 或另一个async函数。 In your code, waiting() is a function that returns a Promise.在您的代码中, waiting()是一个返回 Promise 的函数。 Then, await waiting() is correct (since it is waiting for a asynchronous function).然后, await waiting()是正确的(因为它正在等待一个异步函数)。

An async function is called as another basic functions is called.在调用另一个基本函数时调用async函数。 You may mark a function as async when you desire operate it as an asynchronous function and using the 'await' keyword.当您希望将函数作为异步函数操作并使用“await”关键字时,您可以将其标记为异步。 The 'done...' is printed because when you call asyncFunction() , it must await until waiting promise is finished.打印 'done...' 是因为当您调用asyncFunction() ,它必须await直到waiting promise完成。 But the program is not stopped and go on showing done... .但是程序并没有停止并继续显示done... If you want to wait for it, maybe you can use asyncFunction().then( () => console.log('done...') )如果你想等待,也许你可以使用asyncFunction().then( () => console.log('done...') )

Async keyword used to specify that function will be an instance of AsyncFunction so it will return Promise .用于指定该函数的Async关键字将是AsyncFunction一个实例,因此它将返回Promise

Await is used to wait for a promise resolving inside of async function. Await用于等待在异步函数内部解析的承诺。


According to a mdn - async function can contain an await expression, that pauses the execution of the async function and waits for the passed promise's resolution, and then resumes the async function's execution and returns the resolved value. 根据 mdn - async 函数可以包含一个await表达式,该表达式暂停异步函数的执行并等待传递的承诺的解析,然后恢复异步函数的执行并返回解析的值。

When you await a function, if that function returns a promise, its return value will be treated as the promise then value.当您await一个函数时,如果该函数返回一个承诺,则其返回值将被视为承诺的then值。 If the promise will reject, it will be cast to an Error.如果承诺将拒绝,它将被转换为错误。 If the function call returns something ohter than a thenable, well, await then just doesn't nothing.如果函数调用返回的不是 thenable 的东西,那么await那么什么都不是。

In the other hand, when you declare an async function, its return value will be returned as a Promise, and any Error thrown from it will be casted to a rejected Promise.另一方面,当你声明一个async函数时,它的返回值将作为一个 Promise 返回,并且从它抛出的任何错误都将被转换为一个被拒绝的 Promise。

You can use await only within an async declared function.您只能在async声明的函数中使用await

that's just about async and await are, just automatic casting to promises.这只是关于asyncawait ,只是自动转换为承诺。 You don't actually need code using await and async to be really asynchronous (while, well, it's not really useful).您实际上并不需要使用 await 和 async 的代码来实现真正的异步(虽然,它并不是真的有用)。

A quick demonstration:快速演示:

//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'.

So:所以:

waiting is a synchronous function (because it doesn't have async keyword).等待是一个同步函数(因为它没有 async 关键字)。 So, why can I await a synchronous function?那么,为什么我可以等待一个同步函数呢?

Because you can.因为你能。 The only thing await does is to resolve promise to real values and errors. await唯一能做的就是解决对真实值和错误的承诺。 You don't actually need the function to return a promise.您实际上并不需要该函数来返回承诺。

Why couldn't done... message be awaited after completing waitingAsync function?为什么无法完成...完成waitingAsync 函数后等待消息?

async and await only makes your code to behave as it would be synchronous iside async declared functions. asyncawait只会使您的代码表现得像同步 iside async声明函数一样。 Your last console.log('done') is outside any async function, so it will be just logged before that function ends, since it is asynchronous.您的最后一个console.log('done')在任何async函数之外,因此它只会在该函数结束之前被记录,因为它是异步的。

And main question: waitingAsync is an asynchronous function, why is await keyword not required when calling it?主要问题:waitingAsync 是一个异步函数,为什么调用它时不需要 await 关键字? Just waitingAsync() instead of await waitingAsync().只是waitingAsync() 而不是await waitingAsync()。

Because async keyword casts values to promises -and allows to use await - and nothing more.因为async关键字将值转换为 promises - 并允许使用await - 仅此而已。 In fact, since you can only use await inside async functions... you can't expect async functions to be called through await , you would need infinite async functions :-D.实际上,由于您只能在async函数中使用await ……您不能期望通过await调用async函数,因此您需要无限的async函数 :-D。

Before diving in, it's good to notice a few things.在潜入之前,最好注意一些事情。
Any reader of the code snippet代码片段的任何读者

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...');

may be mislead to believe that the output will be可能会误导认为输出将是

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

while – as you have already noted – done... gets printed before stop... . while - 正如您已经注意到的 - done...stop...之前打印。

The reason is that waitingAsync();原因是waitingAsync(); is a call to an asynchronous function, while console.log('done...');是对异步函数的调用,而console.log('done...'); is just a normal sequential/synchronous statement that gets carried out right away.只是一个正常的顺序/同步语句,可以立即执行。


Question 1 :问题 1

waiting is a synchronous function (because it doesn't have async keyword) [?] waiting是一个同步函数(因为它没有async关键字)[?]

Answer :回答
False.错误的。 The function waiting is a synchronousit returns a Promise .该功能waiting同步的-它返回一个承诺


Question 2 :问题2

Why couldn't done... message be awaited after completing waitingAsync function?为什么无法done...完成waitingAsync函数后等待消息?

Answer :回答
Because console.log('done...') is not asynchronous.因为console.log('done...')不是异步的。
(It does not return a Promise.) (它返回的承诺。)


Question 3 :问题 3

And main question: waitingAsync is an asynchronous function, why is await keyword not required when calling it?主要问题: waitingAsync是一个异步函数,为什么调用它时不需要await关键字?

Answer :回答
Well, in your example waitingAsync does not return any value.好吧,在您的示例中waitingAsync不返回任何值。 - If it would return a value that you care about, then you would need to await it to get it. - 如果它返回一个你关心的值,那么你需要等待它来获取它。
( Hello world! in my Stack Snippet below.) Hello world!在我下面的堆栈片段中。)


Question 4 :问题 4

If I can await waitingAsync() , [the] done... message would be printed last [?]如果我可以 await waitingAsync() ,[the] done...消息将最后打印 [?]

Answer :回答
That depends on what exactly you mean.这取决于你的意思。 – See my Stack Snippet below! – 请参阅下面的堆栈片段! As long as the Done!只要Done! message is printed within the same callback as the call await waitingAsync() , the answer is Yes!消息在与调用await waitingAsync()相同的回调中打印,答案是肯定的!
But if you put console.log('done...?') after the call to the asynchronous function that encloses await waitingAsync() then the answer is No!但是,如果您将console.log('done...?')放在对包含await waitingAsync()的异步函数的调用之后,那么答案是否定的!


When running the snippet below, pay attention to the order of the output!运行下面的代码片段时,请注意输出的顺序
Also notice how it takes 1400 ms for Promise resolved!还要注意Promise resolved!需要 1400毫秒Promise resolved! to show up.现身。

 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; }

The last asynchronous function is anonymous – without name – and gets called immediately.最后一个异步函数是匿名的——没有名字——并被立即调用。 In fact, this is the only function that gets called directly in the snippet.事实上,这是在代码片段中直接调用的唯一函数。 The function waitingAsync is only called in directly (by the anonymous function), and the function waiting is also called indirectly (by waitingAsync ).功能waitingAsync仅称为直接(通过匿名函数),并且函数waiting也(通过间接调用waitingAsync )。

A take away lesson外卖课

Don't ever put sequential/synchronous code after and outside a call to an asynchronous function!永远不要调用异步函数之后和之外放置顺序/同步代码!

You will just confuse yourself if you do.如果你这样做,你只会混淆自己。 – And even if you don't get confused, other readers of your code almost certainly will be. – 即使没有感到困惑,您的代码的其他读者几乎肯定会感到困惑。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM