2

I wrote the code below:

function readFile(path) {
    return new Promise(function(resolve, reject){
        if(!fs.existsSync(path))
            return reject(new Error("data.json file does not exist"));
        else {
            console.log("File is actually found!");
            return Promise.resolve("File found");
        }
    })
}

readFile(path)
    .then(value => {
        console.log(value);
    })
    .catch(err => {
        console.log(err);
    })

What happens:
If the file exists, the console output is just File is actually found! If the file does not exist, it displays: data.json file does not exist along with the error stack.

What I want:
When the file does exist, I want File found to be displayed in addition to File is actually found!. I found that this happens when I replace return Promise.resolve("File found"); with just resolve("File found"); or even return resolve("File found");.

Question:
What really is the difference between resolve() and Promise.resolve()? Why does returning or not returning not make a difference (I guess it is because it is the last statement in the function).

Note: I use existsSync() because I want the process to be blocking until the file is actually read, because if the file is not read, then there is nothing to be done! I understand promise might not be needed here, but I still use it because that is what I am trying to learn.

Thanks!

Edit: One more question - what actually should be rejected and resolved? I mean, in the code above, I pass new Error(...) to reject() and a string to resolve() - is that alright?

J. Doe
  • 1,291
  • 2
  • 10
  • 19
  • Promise.resolve returns a promise resolved to the given value. resolve resolves the promise you call it in ... you would never need to use Promise.resolve like you are, since it won't resolve the promise you are calling it in - note: Promise.resolve is a method of Promise, resolve is just a convention ... you could do new `Promise((good, bad) => good(1));` ... and the promise is resolved – Jaromanda X Aug 09 '19 at 04:02
  • Possible Duplicate of https://stackoverflow.com/questions/26711243/promise-resolve-vs-new-promiseresolve – Ankur Aug 09 '19 at 04:04
  • @AnkurR - not really, at least in that question there is no forever pending Promise :p – Jaromanda X Aug 09 '19 at 04:04
  • @AnkurR, this is not about a promise constructor at all. – J. Doe Aug 09 '19 at 04:05
  • You are looking for difference between them and that question's answers clarifies same. Your usage is just different. – Ankur Aug 09 '19 at 04:06

1 Answers1

4

Promise.resolve wraps an expression in a Promise. So Promise.resolve("File found"); is 'File found' wrapped in a Promise that resolves immediately.

Look at where the wrapped Promise is going in this code - you're returning it to the caller of the new Promise constructor. But the Promise constructor completely ignores a return value, if any. It's kind of like returning something when iterating in forEach - it just gets ignored.

In order to resolve a Promise constructed via the Promise constructor, you must call the first argument provided to the callback (which is conventionally named resolve, but may be named anything you want).

Also note that there's no need at all to wrap the rejection in new Error - if you just have a string message to send to the consumer, it's fine to reject with just a string.

function readFile(path) {
    return new Promise(function(resolve, reject){
        if(!fs.existsSync(path))
            reject("data.json file does not exist");
        else {
            console.log("File is actually found!");
            resolve("File found");
        }
    })
}

Which is equivalent to:

function readFile(path) {
    return new Promise((fnToCallToResolveConstructedPromise, fnToCallToRejectConstructedPromise) => {
        if(!fs.existsSync(path))
            fnToCallToRejectConstructedPromise("data.json file does not exist");
        else {
            console.log("File is actually found!");
            fnToCallToResolveConstructedPromise("File found");
        }
    })
}

You can wrap it in an error object if it provides useful info for you, aside from the string describing the error, but otherwise, best to omit it, and just call reject with a string.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • Could you please elaborate - _But the Promise constructor completely ignores a return value, if any_? Isn't the whole purpose of a constructor just to construct _something_ and return it to its caller? In other words, what should a Promise constructor do, if not ignore a return value? – J. Doe Aug 09 '19 at 04:10
  • Yes, the Promise constructor ignores its return value. The only way to communicate with the consumer of the Promise is to call the `resolve` and `reject` functions (the two parameters to the constructor callback). That is what you should do in the Promise constructor - always call either `resolve` or `reject` eventually, so that whatever is using the Promise can see when the Promise resolves or rejects. – CertainPerformance Aug 09 '19 at 04:11
  • Thanks for your help. So, just to clarify, when I called `Promise.resolve()` was I doing something different than just `resolve()`? I mean, yes, I wrapped an expression in a Promise with `Promise.resolve()`, but then why was that expression not printed later on (in `then()`'s callback)? – J. Doe Aug 09 '19 at 04:17
  • When you call `Promise.resolve`, you're wrapping an expression in a Promise, and then the wrapped Promise goes unused, because, like I said, the Promise constructor ignores its return value. The way to chain something inside the Promise constructor with something outside it is to call one of the parameters provided to the callback - anything else will not be connected with outside the callback, by default. `resolve()` resolves the constructed Promise. `Promise.resolve('foo')` creates *another* Promise which goes unused, so it doesn't do anything. – CertainPerformance Aug 09 '19 at 04:26
  • Ah, now I get it. Perfect. Thanks for your help! – J. Doe Aug 09 '19 at 04:28