-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?

guest271314
  • 1
  • 15
  • 104
  • 177
  • 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 – Jaromanda X Nov 08 '17 at 04: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. – guest271314 Nov 08 '17 at 04:19
  • fn() will only ever return true ... don't need to knwo anything about the dogs breakfast inside the "condition" – Jaromanda X Nov 08 '17 at 04: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? – guest271314 Nov 08 '17 at 04: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 – Jaromanda X Nov 08 '17 at 04:26
  • @JaromandaX Was inverting the boolean at the incorrect location `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;` – guest271314 Nov 08 '17 at 04:52
  • my comments were about the code in the question and explaining why it was always false ... of course different code will produce different results ... like answering "why isn't 1 + 1 = 3" ... with "if you change that to 1 + 2, that will = 3" ... whereas my comment was "because 1 + 1 is 2" – Jaromanda X Nov 08 '17 at 04:55
  • @JaromandaX _"my comments were about the code in the question and explaining why it was always false"_ Can you post an Answer including your description of the reason for the resulting value? – guest271314 Nov 08 '17 at 04:57
  • no, because I haven't bothered reading the 259 characters between `!` and `);` to even care what the code is attempting to achieve – Jaromanda X Nov 08 '17 at 04:58
  • @JaromandaX You already stated that that portion of code is irrelevant and doubled down on your strict interpretation and reason for the result _"`while done = !.... all this is irrelevant ....);` means that the only exit is when done === false, which is what the function returns after the loop"_ Why do you not formalize your evaluation of the code as an Answer? The code is attempting to ascertain the limits of expectations as to variable assignment using `await`. – guest271314 Nov 08 '17 at 05:01
  • because I don't care – Jaromanda X Nov 08 '17 at 05:03
  • @JaromandaX What does caring have to do with anything? Did not ask for your emotion, but rather for your formal answer to a question. – guest271314 Nov 08 '17 at 05:04
  • look ... it's clear that done will always be returned as a Promise of `false` in that code - how can you make it `true`? well, you could `return !done` - but that doesn't address any of the 259 characters of code that I haven't bothered with ... returning `!done` ... will return the expected result, but how does that relate to the 259 characters? I simply don't know, and don't wish to analyse it, which is why I made a comment, rather than post an answer in the first place – Jaromanda X Nov 08 '17 at 05:08
  • @JaromandaX Your comments answered the question nonetheless. – guest271314 Nov 08 '17 at 05:15

2 Answers2

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

Shawn31313
  • 5,978
  • 4
  • 38
  • 80
  • Function parameter `(a, b)` has own scope as well, yes? – guest271314 Nov 08 '17 at 04:29
  • The parameters are locally scoped to the function. – Shawn31313 Nov 08 '17 at 04:31
  • Why is the `true` returned from `.then()` not retained as the value of `done`? – guest271314 Nov 08 '17 at 04:32
  • 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: https://jsfiddle.net/dpry01ca/ – Shawn31313 Nov 08 '17 at 04:40
  • 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;` – guest271314 Nov 08 '17 at 04:49
  • Thats is what I use noticed. You use `await` so it will also give you false – Shawn31313 Nov 08 '17 at 04:50
  • The code at Question does not use the statement option of `while` – guest271314 Nov 08 '17 at 04:51
  • But you are using fn() while still uses the while loop – Shawn31313 Nov 08 '17 at 04:52
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));
guest271314
  • 1
  • 15
  • 104
  • 177