+ =를 가진 비동기 함수


63

let x = 0;

async function test() {
    x += await 5;
    console.log('x :', x);
}

test();
x += 1;
console.log('x :', x);

x기록 된 값 은 15입니다. 내 질문은 : 왜 x 5두 번째 로그 의 값 입니까?

이 경우 test후에 실행된다 x += 1(이것은 비동기 함수이기 때문에)를 x의 값은 시간에 의해 1 test실행되므로, x += await 5의 값을 확인한다 x 6.


1
당신은 차이를 알고 있어야 await (x += 5) 하고 x += await 5.
Singhi John

답변:


60

TL; DR : 때문에 +=판독 x하기 전에, 그러나 변경된 후에 의한, 그 기록을 await두 번째 피연산자 (오른쪽)에서 키워드.


async함수는 첫 번째 await명령문 까지 호출 될 때 동기식으로 실행됩니다 .

따라서을 제거 await하면 일반 함수처럼 작동합니다 (여전히 Promise를 반환하는 것을 제외하고).

이 경우에는 취득 56콘솔에서 :

let x = 0;

async function test() {
  x += 5;
  console.log('x :', x);
}

test();
x += 1;
console.log('x :', x);

은 첫째 await도 동 기적으로 인수 가능한 경우, 그래서 다음은 반환, 동기 실행을 중지 1하고 6예상대로 :

let x = 0;

async function test() {
  // Enter asynchrony
  await 0;

  x += 5;
  console.log('x :', x);
}

test();
x += 1;
console.log('x :', x);

그러나 귀하의 경우는 조금 더 복잡합니다.

await을 사용하는 표현식 안에 넣었습니다 +=.

JS에서 x += y와 동일하다는 것을 알고있을 것입니다 x = (x + y). 더 나은 이해를 위해 후자의 형식을 사용하겠습니다.

let x = 0;

async function test() {
  x = (x + await 5);
  console.log('x :', x);
}

test();
x += 1;
console.log('x :', x);

통역사가이 줄에 도착하면 ...

x = (x + await 5);

... 평가를 시작하면 ...

x = (0 + await 5);

... 그러면 도달 await하고 멈 춥니 다.

함수 호출 이후의 코드는 실행을 시작하고 값을 수정 x한 다음 기록합니다.

x지금 1입니다.

그런 다음 기본 스크립트가 종료 된 후 인터프리터는 일시 정지 된 test기능 으로 돌아가서 해당 라인을 계속 평가합니다.

x = (0 + 5);

그리고의 값 x은 이미 대체되었으므로 그대로 남아 있습니다 0.

마지막으로, 인터프리터는 추가, 저장을 수행 5하는 x, 그것을 기록합니다.

객체 속성 getter / setter에 로그인하여이 동작을 확인할 수 있습니다 (이 예에서는 y.z다음 값을 반영 함) x.

let x = 0;
const y = {
  get z() {
    console.log('get x :', x);
    return x;
  },
  set z(value) {
    console.log('set x =', value);
    x = value;
  }
};

async function test() {
  console.log('inside async function');
  y.z += await 5;
  console.log('x :', x);
}

test();
console.log('main script');
y.z += 1;
console.log('x :', x);

/* Output:

inside async function
get x : 0   <-- async fn reads
main script
get x : 0
set x = 1
x : 1
set x = 5   <-- async fn writes
x : 5       <-- async fn logs

*/
/* Just to make console fill the available space */
.as-console-wrapper {
  max-height: 100% !important;
}


아마도 주목할 가치가 있을 것입니다x += yx = (x + y) : "아마도, 그것은 같은 것 입니다." -모든 언어에서 모든 상황에 해당되는 것은 아니지만 일반적으로 동일한 방식으로 행동 할 수 있습니다.

11

당신의 진술 x += await 5

const _temp = x;
await;
x = _temp + 5;

_temporary 값은 0, 그리고 당신이 변경되면 xawait(코드가 수행하는)이이 할당됩니다, 중요하지 않습니다 5이후.


9

이 코드는 예상치 못한 비동기 점프가 앞뒤로 걸리기 때문에 따르기가 매우 복잡합니다. 실제로 어떻게 실행되는지 살펴보고 (이후) 그 이유를 설명하겠습니다. 또한 콘솔 로그를 변경하여 숫자를 추가했습니다. 콘솔 로그를 쉽게 참조하고 기록 된 내용을 더 잘 보여줍니다.

let x = 0;                        // 1 declaring and assigning x

async function test() {           // 2 function declaration
    x += await 5;                 // 4/7 assigning x
    console.log('x1 :', x);       // 8 printing
}

test();                           // 3 invoking the function
x += 1;                           // 5 assigning x
console.log('x2 :', x);           // 6 printing

따라서 코드는 실제로 똑바로 진행되지는 않습니다. 그리고 우리에게는 이상한 4/7것도 있습니다. 그리고 그것은 실제로 문제의 전체입니다.

우선, 비동기 함수는 실제로 엄격하게 비동기 적이 지 않습니다 . await키워드가 사용 된 경우에만 실행을 일시 중지하고 나중에 다시 시작 합니다. 그것없이, 그들은 식에서 동기식으로 위에서 아래로 실행합니다.

async function foo() {
  console.log("--one");
  console.log("--two");
}

console.log("start");
foo();
console.log("end");

async function foo() {
  console.log("--one");
  await 0; //just satisfy await with an expression
  console.log("--two");
}

console.log("start");
foo();
console.log("end");

그래서, 먼저 우리가 사용하는 것을 알아야 await할 것입니다 나머지 함수의 나중에 실행합니다. 주어진 예에서, 이는 나머지 동기 코드 이후console.log('x1 :', x) 에 실행될 것임을 의미합니다 . 현재 이벤트 루프가 완료되면 약속이 해결되기 때문입니다.

우리가받을 이유 그래서,이 설명 x2 : 1로그인 한 첫 번째 이유는 x2 : 5두 번째 기록되지만 후자의 값이없는 이유 5. 논리적 x += await 5이어야한다 5여기 ...하지만 것은 두 번째 캐치입니다 await키워드 - 그것은 것이다 일시 정지 이미 실행되기 전에 함수의 실행 아무것도하지만. x += await 5실제로 다음과 같은 방식으로 처리됩니다

  1. 의 값을 가져옵니다 x. 실행 당시는 0입니다.
  2. await다음 표현식 5. 이제 기능이 일시 중지되고 나중에 다시 시작됩니다.
  3. 기능을 재개하십시오. 표현은 5로 해결됩니다.
  4. 1의 값과 2/3의 식을 추가하십시오. 0 + 5
  5. 값을 4에서 x

따라서 함수 x는 읽은 후에 일시 중지 0되고 이미 변경되면 다시 시작되지만의 값을 다시 읽지 않습니다 x.

우리 가 실행 await하는 Promise것과 동등한 것을 풀면 다음이 있습니다.

let x = 0;                        // 1 declaring and assigning x

async function test() {           // 2 function declaration
    const temp = x;               // 4 value read of x
    await 0; //fake await to pause for demo
    return new Promise((resolve) => {
      x = temp + 5;               // 7 assign to x
      console.log('x1 :', x);     // 8 printing
      resolve();
    });
}

test();                           // 3 invoking the function
x += 1;                           // 5 assigning x
console.log('x2 :', x);           // 6 printing


3

나중에 실제로 일어나는 일이 조금 까다 롭습니다. 추가 작업이 두 개씩 일어나고 있으므로 작업은 다음과 같습니다.

약속 내 : x += await 5==> x = x + await 5==> x = 0 + await 5==>5

외부 : x += 1==> x = x + 1==> x = 0 + 1==>1

위의 모든 동작이 왼쪽에서 오른쪽으로 일어나기 때문에 추가의 첫 번째 부분이 동시에 계산 될 수 있으며 5 이전에 대기 시간이 있기 때문에 additio가 비트를 지연시킬 수 있습니다. 코드 내에 중단 점을 넣어 실행을 확인할 수 있습니다.


1

비동기 및 대기는 약속의 확장입니다. async 함수에는 async 함수의 실행을 일시 중지하고 전달 된 Promise의 해결을 기다린 다음 async 함수의 실행을 다시 시작하고 해결 된 값을 반환하는 await식이 포함될 수 있습니다. await 키워드는 비동기 함수 내에서만 유효합니다.

테스트 함수를 호출 한 후 x 값을 변경 한 경우에도 여전히 x 값은 0으로 남아 비동기 함수가 이미 새 인스턴스를 작성했기 때문입니다. 변수 외부의 변수에 대한 모든 변경 사항은 변수가 호출 된 후에 그 내부의 값을 변경하지 않음을 의미합니다. 증분을 테스트 기능 위에 두지 않는 한.


" 변수 외부의 모든 변수가 변경되었다는 의미는 " 라고 불리는 후에 내부 변수의 값을 변경 하지 않습니다. 사실이 아닙니다. 비동기 함수 실행 중에 변수 변경을 수신합니다. 이것을 시도하십시오 : let x="Didn't receive change"; (async()=>{await 'Nothing'; console.log(x); await new Promise(resolve=>setTimeout(resolve,2000)); console.log(x)})(); x='Received synchronous change'; setTimeout(()=>{x='Received change'},1000)그것은 출력 Received synchronous change하고Received change
FZs
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.