web-dev-qa-db-ja.com

Javascriptで待機しない非同期関数

非同期の2つの関数abがあり、前者はawaitなしで、後者はawaitあります。コンソールに何かを記録し、undefinedを返します。関数のいずれかを呼び出した後、別のメッセージを記録し、関数の本体を実行する前または実行した後にメッセージが書き込まれるかどうかを調べます。

function someMath() {
  for (let i = 0; i < 3000000; i++) { Math.sqrt(i**5) }
}

function timeout(n) {
   return new Promise(cb => setTimeout(cb, n))
}

// ------------------------------------------------- a (no await)
async function a() {
  someMath()
  console.log('in a (no await)')
}

// ---------------------------------------------------- b (await)
async function b() {
  await timeout(100)
  console.log('in b (await)')
}

clear.onclick = console.clear

aButton.onclick = function() {
  a()
  console.log('after a (no await) call')
}

bButton.onclick = function() {
  b()
  console.log('after b (await) call')
}
<button id="aButton">test without await</button>
<button id="bButton">test with await</button>
<button id="clear">clear console</button>

awaitなしでテストを起動すると、関数は同期のように機能するようです。ただし、awaitでは、関数が非同期に実行されるため、メッセージはinvertedです。

だから私の質問は:javascriptがasyncキーワードが存在しないときにawait関数を実行する方法ですか?


実際のユースケース:条件付きで実行されるawaitキーワードがあり、関数が同期的に実行されるかどうかを知る必要があります要素をレンダリングする順序:

async function initializeComponent(stuff) {
   if (stuff === undefined)
      stuff = await getStuff()
   // initialize

   if (/* context has been blocked */)
       renderComponent() // render again if stuff had to be loaded
}

initializeComponent()
renderComponent()

P.S:タイトルにはjavascriptキーワードがあり、他の言語での同じ質問との混同を避けています(つまり awaitなしでasyncを使用

29
Ulysse BN

mozilla docから:

非同期関数canには、非同期関数の実行を一時停止し、渡されたPromiseの解決を待機してから非同期関数の実行を再開するawait式を含めることができます解決された値を返します。

想定したとおり、待機が存在しない場合、実行は一時停止されず、コードは同期的に実行されます。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function#Description

24
Karim

Javascript非同期関数が実行されるまで、すべてが同期的です。 async-awaitを使用する場合、awaitは非同期であり、awaitの後はすべてイベントキューに配置されます。 .then()に似ています。

よりよく説明するには、この例を取り上げます。

function main() {
  return new Promise( resolve => {
    console.log(3);
    resolve(4);
    console.log(5);
  });
}

async function f(){
    console.log(2);
    let r = await main();
    console.log(r);
}

console.log(1);
f();
console.log(6);

awaitは非同期であり、残りはpromiseを含むすべて同期であるため、出力は

1
2
3
5
6
// Async happened, await for main()
4

main()の同様の動作も約束なしです:

function main() {
    console.log(3);
    return 4;
}

async function f(){
    console.log(2);
    let r = await main();
    console.log(r);
}

console.log(1);
f();
console.log(5);

出力:

1
2
3
5
// Asynchronous happened, await for main()
4

awaitを削除するだけで、async関数全体が同期されます。

function main() {
    console.log(3);
    return 4;
}

async function f(){
    console.log(2);
    let r = main();
    console.log(r);
}

console.log(1);
f();
console.log(5);

出力:

1
2
3
4
5
10
NAVIN

関数は、awaitの有無にかかわらず同じように実行されます。 awaitが行うことは、関数によって返されるpromiseが解決されるのを自動的に待つことです。

await timeout(1000);
more code here;

以下とほぼ同等です。

timeout(1000).then(function() {
    more code here;
});

async function宣言は、関数が戻るときに解決されるプロミスを関数が自動的に返すようにします。

8
Barmar