-2

Given the JavaScript code

function* gen(start = 0, stop = 5) {
   while (start < stop) yield ++start;
}

async function fn(g = gen()) {
  while (done = !await new Promise(resolve => 
                   setTimeout(resolve, 1000, g.next()))
                   .then(({value, done}) => {
                     // `value:undefined, done:true` following
                     // `value:5, done:false`
                     console.log(`value:${value}, done:${done}`); 
                     return done 
                   }
                   , err => Promise.reject(err)));
  return done; // what happened to the `true` value assigned?
}
// why is `res` `false`?
fn().then(res => console.log(`res:${res}`), err => console.error(err));

the expected result of done returned from fn() is true when done is assigned the value true that is returned from .then() within while expression.

Why is the assignment using await at while statement expression not retained?

14
  • 3
    "why is res false" ... because the while loop will continue until !await new Promise(resolve => .... is false ... at which point, done === false, which is what fn will return Commented Nov 8, 2017 at 4:16
  • @JaromandaX !await new Promise(resolve => .... is evaluated to false at while expression when true is returned when value:undefined, done:true, as evidenced by value: true logged at console, though the assigned value is not retained. Commented Nov 8, 2017 at 4:19
  • fn() will only ever return true ... don't need to knwo anything about the dogs breakfast inside the "condition" Commented Nov 8, 2017 at 4:20
  • @JaromandaX Using a do..while loop returns expected result. The question is why is the true returned from .then() at last iteration using await assignment is not retained following while loop? Commented Nov 8, 2017 at 4:22
  • 2
    fn().then(res => with the question why is res false ... the reason is, that fn() will always ever only ever return a Promise that resolves to false, ever, never anything else, don't even need to read the 259 characters after the ! ... while done = !.... all this is irrelevant ....); means that the only exit is when done === false, which is what the function returns after the loop Commented Nov 8, 2017 at 4:26

2 Answers 2

2

JavaScript has "three" different types of scope: local, global, and block.

Global

This type of variable can be reach in all places of the code:

var b = "bar";
   (function test1(a) {
         if (a == true) {
              var b = "bar";
         } else {
              var b = "foo";
         }
         return b;
    })(true);
    alert(b);

Local

These variables can only be reached if the variable in the general scope of the code:

(function test2(a) {
     if (a == true) {
          var b = "bar";
     } else {
          var b = "foo";
     }
     return b;
})(true)

In this case, the general scope is the function. Even though the variable b is block scoped by the if statement, the function can still reach it.

Block

Self defined block scoped variables are pretty new to JavaScript and can be introduced using the let keyword:

(function test2(a) {
     if (a == true) {
          let b = "bar";
     } else {
          let b = "foo";
     }
     return b;
})(true)

This will result in an error because the variable b is now block scoped to the if state. Thus in your code, we can change your scoping to allow you to change done which in a while loop is block scoped in the case of asynchronous loops.

function* gen(start = 0, stop = 5) {
   while (start < stop) yield ++start;
}

async function fn(g = gen()) {
  let doneVal;
  while (done = !await new Promise(resolve => 
                   setTimeout(resolve, 1000, g.next()))
                   .then(({value, done}) => {
                     // `value:undefined, done:true` following
                     // `value:5, done:false`
                     console.log(`value:${value}, done:${done}`); 
                     return done 
                   }
                   , err => Promise.reject(err))) {
       doneVal = done;
  }

  return doneVal; // what happened to the `true` value assigned?
}
// why is `res` `false`?
fn().then(res => console.log(`res:${res}`), err => console.error(err));

Now you will get res:true. In your specific example, there is an issue with code like this:

var i;
var c = 0;
while (i = 90 && c < 10) {
    c++;
}
console.log(i, c);

i is false while c is equal to 10

Sign up to request clarification or add additional context in comments.

8 Comments

Function parameter (a, b) has own scope as well, yes?
The parameters are locally scoped to the function.
Why is the true returned from .then() not retained as the value of done?
It seems as loops scope using block scope. The value is retained. But does to scoping you can't see it by the way you wrote it. Check out this example: jsfiddle.net/dpry01ca
The expression can used without the statement by inverting the return value from .then() and the value returned from fn() while ((done = await new Promise(resolve => setTimeout(resolve, 1000, g.next())) .then(({value, done}) => {console.log(value, done); return !done} , err => Promise.reject(err)))); return !done;
|
1

The comments by @JaromandaX helped recognize that the ! was not in correct place within code to return expected result. The Answer by @Shawn31313 reminded to define variable using parameter or let within function call, as done being defined as a global variable was not intended

function* gen(start = 0, stop = 5) {
   while (start < stop) {
     yield ++start;
   }
}
async function fn(g = gen()) {
  let done;
  while ((done = await new Promise(resolve => 
                   setTimeout(resolve, 1000, g.next()))
                   .then(({value, done}) => {
                     console.log(value, done); 
                     return !done
                   }
                   , err => Promise.reject(err))));
  return !done;
}

fn().then(res => console.log(res), err => console.error(err));

2 Comments

Btw, you really should just use for (let value of g) { await new Promise(r => setTimeout(r, 1000)); console.log(value, false); } return true
@Bergi That is not the gist of the Question

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.