1

my code :

const readline = require('readline');

function scan(callback) {
    const rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout,
        prompt: '> ',
    });

    rl.prompt();
    rl.on('line', (line) => {
        callback(line);
        rl.close();
    }).on('close', () => {
        process.exit(0);
    });
}

scan(data => {
    console.log('data: ', data);  // can console
});

I used callback and it can console data that u input , but it will not console when i use promise:

function scan() {
    return new Promise((resolve, reject) => {
        const rl = readline.createInterface({
            input: process.stdin,
            output: process.stdout,
            prompt: '> ',
        });

        rl.prompt();
        rl.on('line', (line) => {
            resolve(line);  
            rl.close();
        }).on('close', () => {
            process.exit(0);
        });
    });
}

scan().then(data => {
    console.log('data: ', data);   // can not console
});

what occurred to this ? what's different between callback and promise ?

Rife
  • 487
  • 2
  • 7
  • 18
  • possible dublicate [arent-promises-just-callbacks](https://stackoverflow.com/questions/22539815/arent-promises-just-callbacks) –  Dec 28 '17 at 09:40
  • 1
    Possible duplicate of [Aren't promises just callbacks?](https://stackoverflow.com/questions/22539815/arent-promises-just-callbacks) –  Dec 28 '17 at 09:41
  • @cometguy I read it , but i think it is not answer to my question . – Rife Dec 28 '17 at 09:54
  • A callback can be called multiple times (such as on every line in your example). A promise can settle (fulfill or reject) only once. It might be suitable to signal when the whole file is done, but you cannot use it to process the lines. – Bergi Dec 28 '17 at 11:02
  • If you ask me, this code is just structured wrong. You're doing a `process.exit()` from within a function, yet expecting its result to get processed by the caller before the exit actually happens. That's just a bad coding design and it bit you here because of nuances in asynchronous processing order. Fix the design so the order of operations is directly specified and controlled by the code rather than left to the nuances of how different types of async operations get scheduled. Also, in most cases, you can just let the program exit on its own when there is nothing else left to do. – jfriend00 Dec 28 '17 at 15:19

2 Answers2

0

For more detailed answer, see HMR's response.

Apparently you call rl.close() right after resolving the promise. Take a look at your on close event handler:

 process.exit(0);

Clearly it will stop all executions and terminate your program. Event though your promise gets resolved, exit gets called faster (Normal behaviour with the event loop).

So to solve your problem: Remove the on close event handler. After every promise got resolved, your program will terminate gracefully.

Bence Gedai
  • 1,461
  • 2
  • 13
  • 25
  • 1
    That doesn't explain it though, the callback has `process.exit(0)` in the close handler as well. The problem is that `resolve()` will eventually call resolveHandler from queue so the next in stack is `rl.colse()` this does not happen with the callback, calling the callback and `rl.close()` are on the same stack. – HMR Dec 28 '17 at 10:45
0

Stack and queue problem, your callback is on the same stack as rl.close but the resolve handler isn't (that one is on the queue).

For example:

new Promise(resolve=>resolve())
.then(_=>console.log("last"))//resolve handler is going on queue
console.log("first")//this is on the same stack so logs
//nothing more on the stack so get stuff from queue

Simple solution would be to put the close on the que after resolve handler that logs:

function scan() {
  return new Promise((resolve, reject) => {
      const rl = readline.createInterface({
          input: process.stdin,
          output: process.stdout,
          prompt: '> ',
      });

      rl.prompt();
      rl.on('line', (line) => {
          resolve(line);  
          //put close on queue
          Promise.resolve()
          .then(
            _=>rl.close()
          );
      }).on('close', () => {
          process.exit(0);
      });
  });
}

scan().then(data => {
  console.log('data: ', data);   // can not console
});

stack and queue video or ducumentation

HMR
  • 37,593
  • 24
  • 91
  • 160
  • Stack? Queue? Do you mean stack and heap? – Bergi Dec 28 '17 at 11:03
  • @Bergi stack as in [callstack](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#Stack) queue as in event loop or [message queue](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#Queue) – HMR Dec 28 '17 at 11:20
  • @Bergi Maybe it would be more correct to say the resolve handler function is not in current call stack but saved in heap and is invoked when an associated message is taken from the queue because that function is supposed to handle that message. Messages are not taken from queue until the call stack is empty so rs.close() and the on close handlers are called first. If the `readline` package was implemented differently then the close handler may be called after the resolve handler (for example: has a timeout in it to clear the call stack and yield to another message). – HMR Dec 28 '17 at 11:41
  • 1
    Yes, I guess that would be more correct. Or to put it differently: the `close` event is fired synchronously while the `resolve` always triggers the promise handlers asynchronously. – Bergi Dec 28 '17 at 13:22
  • @HMR callback() and rl.close() is sync because they are in one stack , resolve() and rl.close() is async because resolve is in callback queue but rl.close in stack . It 's right ? – Rife Dec 28 '17 at 14:06
  • @Rife Something with a callback can be on the same stack but would be considered async. Triggering an event can be on the same stack but when you use something like `setTimeout(...` or `Promise.resolve().then(...` the function you pass to it will definitely not be on the same stack. The package `readline` will invoke your `on close` handler synchronously, that's why the callback works and the promise doesn't. I suggest you watch the video, it's a good investment of your time. – HMR Dec 28 '17 at 14:31