web-dev-qa-db-ja.com

待機後のコードがすぐに実行されないのはなぜですか?ノンブロッキングなのではないですか?

こんにちは私は非同期と待機が舞台裏でどのように機能するかを理解するのに苦労しています。 「then」関数を使用して非ブロックコードを作成する約束があり、約束が解決された後に実行する必要があるすべての作業を配置できることを知っています。そして、並行して実行する作業は、then関数の外側に書き込むことを約束します。したがって、コードは非ブロッキングになります。ただし、asyncawaitが非ブロッキングコードを作成する方法がわかりません。

async function myAsyncFunction() {
  try {
    let data = await myAPICall('https://jsonplaceholder.typicode.com/posts/1');
    // It will not run this line until it resolves await.
    let result = 2 + 2;
    return data;
  }catch (ex){
    return ex;
  }
}

上記のコードを参照してください。 API呼び出しが解決されるまで先に進むことができません。それが私のコードをブロックするコードになる場合、それは約束よりもどのように優れていますか?それとも、asyncawaitについて見逃したことはありますか?待機呼び出しに依存しないコードはどこに配置しますか?実行を待たずに作業を続けることができますか?

非同期待機の例で複製したいPromiseコードを追加しています。

function myPromiseAPI() {
  myAPICall('https://jsonplaceholder.typicode.com/posts/1')
    .then(function (data) {
        // data
    });
   // runs parallel
  let result = 2 + 2;
}
14
Rohail Najam

その名前が示すように、awaitキーワードは、次の行を実行する前に、promiseが解決されるまで関数を「待機」させます。 awaitの目的は、操作が完了するまでコードを待機させてから続行することです。

このコードとブロッキングコードの違いは、関数outsideは、関数が非同期操作の終了を待機している間も実行を継続できることです。

asyncawaitは、promiseの上にある単なる構文上の砂糖です。カバーされたプロミスを使用していても、通常の同期コードによく似たコードを記述できます。ここであなたの例を明示的にpromiseで機能するものに翻訳すると、次のようになります。

_function myAsyncFunction() {
  return myAPICall('https://jsonplaceholder.typicode.com/posts/1')
    .then(function (data) {
       let result = 2 + 2;
       return data;
    })
    .catch(function (ex) {
        return ex;
    });
}
_

ここでわかるように、_let result = 2 + 2;_行は.then()ハンドラー内にあります。つまり、myAPICall()が解決されるまで実行されません。 awaitを使用する場合も同様です。 await.then()を抽象化するだけです。

心に留めておくべきことの1つ(そして、あなたが探している点だと思います)は、すぐにawaitを使用する必要がないことです。次のように関数を記述した場合、_let result = 2 + 2;_行をすぐに実行できます。

_const timeout = 
    seconds => new Promise(res => setTimeout(res, seconds * 1000));

function myAPICall() {
  // simulate 1 second wait time
  return timeout(1).then(() => 'success');
}

async function myAsyncFunction() {
  try {
    console.log('starting');

    // just starting the API call and storing the promise for now. not waiting yet
    let dataP = myAPICall('https://jsonplaceholder.typicode.com/posts/1');

    let result = 2 + 2;

    // Executes right away
    console.log('result', result);

    // wait now
    let data = await dataP;

    // Executes after one second
    console.log('data', data);

    return data;
  } catch (ex) {
    return ex;
  }
}

myAsyncFunction();_

いくつかの明確化の後、あなたが本当に知りたかったのは、2つの非同期操作を1つずつ待つのを避け、代わりにそれらを並列に実行させる方法であることがわかります。実際、1つのawaitを次々に使用すると、最初のものが終了するまで、2番目は実行を開始しません。

_const timeout = 
    seconds => new Promise(res => setTimeout(res, seconds * 1000));

function myAPICall() {
  // simulate 1 second wait time
  return timeout(1).then(() => 'success');
}

async function myAsyncFunction() {
  try {
    console.log('starting');

    let data1 = await myAPICall('https://jsonplaceholder.typicode.com/posts/1');
    // logs after one second
    console.log('data1', data1);

    let data2 = await myAPICall('https://jsonplaceholder.typicode.com/posts/2');
    // logs after one more second
    console.log('data2', data2);
  } catch (ex) {
    return ex;
  }
}

myAsyncFunction();_

これを回避するために、あなたができることはstart両方の非同期操作を待たずに実行し、約束をいくつかの変数に割り当てることです。その後、両方の約束を待つことができます:

_const timeout = 
    seconds => new Promise(res => setTimeout(res, seconds * 1000));

function myAPICall() {
  // simulate 1 second wait time
  return timeout(1).then(() => 'success');
}

async function myAsyncFunction() {
  try {
    console.log('starting');
    // both lines execute right away
    let dataP1 = myAPICall('https://jsonplaceholder.typicode.com/posts/1');
    let dataP2 = myAPICall('https://jsonplaceholder.typicode.com/posts/2');

    let data1 = await dataP1;
    let data2 = await dataP2;

    // logs after one second
    console.log('data1', data1);
    console.log('data2', data2);
  } catch (ex) {
    return ex;
  }
}

myAsyncFunction();_

これを行う1つの代替方法は、いくつかの配列分解でPromise.all()を使用することです。

_const timeout = 
    seconds => new Promise(res => setTimeout(res, seconds * 1000));

function myAPICall() {
  // simulate 1 second wait time
  return timeout(1).then(() => 'success');
}

async function myAsyncFunction() {
  try {
    console.log('starting');

    // both myAPICall invocations execute right away
    const [data1, data2] = await Promise.all([
        myAPICall('https://jsonplaceholder.typicode.com/posts/1'), 
        myAPICall('https://jsonplaceholder.typicode.com/posts/2'),
    ]);

    // logs after one second
    console.log('data1', data1);
    console.log('data2', data2);
  } catch (ex) {
    return ex;
  }
}

myAsyncFunction();_
31
JLRishe