Async function with +=

后端 未结 5 2029
礼貌的吻别
礼貌的吻别 2020-12-24 11:39



        
5条回答
  •  感情败类
    2020-12-24 12:17

    This code is quite complex to follow because it takes some unexpected async jumps back and forth. Let's examine (close to) how it's actually going to be executed and I'll explain why afterwards. I've also changed the console logs to add a number - makes referring to them easier and also shows better what is logged:

    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

    So, the code is not actually going in a straight manner, that's for sure. And we have a weird 4/7 thing as well. And that is really the entirety of the problem here.

    First of all, let's clarify - async functions are not actually strictly asynchronious. They would only pause the execution and resume later if the await keyword is used. Without it, they execute top to bottom, expression after expression synchronously:

    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");

    So, the first thing we need to know that using await will make the rest of the function execute later. In the given example, that means that console.log('x1 :', x) is going to executed after the rest of the synchronous code. That's because any Promises will be resolved after the current event loop finishes.

    So, this explains why we get x2 : 1 logged first and why x2 : 5 is logged second but not why the latter value is 5. Logically x += await 5 should be 5...but here is the second catch to the await keyword - it will pause the execution of the function but anything before it has already run. x += await 5 is actually going to be processed in the following manner

    1. Fetch the value of x. At the time of the execution, that's 0.
    2. await the next expression which is 5. So, function pauses now and will be resumed later.
    3. Resume the function. Expression is resolved as 5.
    4. Add the value from 1. and the expression from 2/3: 0 + 5
    5. Assign the value from 4. to x

    So, the function pauses after it read that x is 0 and resumes when it's already changed, however, it doesn't re-read the value of x.

    If we unwrap the await into the Promise equivalent that would execute, you have:

    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

提交回复
热议问题