user12100401
user12100401

Reputation: 51

Is a "sync"-function also sync, if it's run in a promise?

I just wanted to know if a 'sync'-function, run in a promise, is synchronous (and slows down other stuff) or async, like I think?

Example:

function getFileContent(filepath){
    return new Promise((resolve, reject) => {
        fs.readFileSync("asd.txt"));
    });
}

Upvotes: 4

Views: 1345

Answers (3)

Adam Jenkins
Adam Jenkins

Reputation: 55782

Ok, I get the point that it was just an example

The thing about Promise constructors is that they execute their executor immediately.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

A function that is passed with the arguments resolve and reject. The executor function is executed immediately by the Promise implementation, passing resolve and reject functions (the executor is called before the Promise constructor even returns the created object).

Which means, in your example fs.readFileSync is executed immediately and (edited) blocks the rest of your code from running (see comment)

Upvotes: 0

freakish
freakish

Reputation: 56547

Functions are synchronous. Period.

What can be asynchronous is an (abstract) process/workflow.

When someone says a function is "async" what they actually mean is that the result will be available some time later. The result is wrapped in a Promise, which is a handle to await. But the process may still be synchronous. Have a look at this example:

function foo() {
    return new Promise((res, rej) => {
        console.log(1);
        console.log(2);
        res();
    });
};

function test() {
    foo();
    console.log(3);
};

and the output is always the same:

> test();
1
2
3

which means that each function was called one after another in a synchronous manner. And indeed if you update foo function to:

function foo() {
    return new Promise((res, rej) => {
        while (true) {}
        res();
    });
};

you will notice that console.log(3) never runs. And so our foo blocks forever!

Now have a look at this example:

function test() {
    Promise.resolve().then(function() {
        console.log(1);
        console.log(2);
    });
    console.log(3);
};

and note the different result: 3 1 2. All those functions are synchronous, so why the order is different? Because .then() postpones the execution to some later time.

All in all: sync/async is not really a property of a function, but rather a property of a workflow. And in your case it is synchronous.

Side note: this gets more complicated when exceptions are involved. Let's modify the foo function from the first example:

function foo() {
    return new Promise((res, rej) => {
        throw 'myException';
    });
};

function test() {
    foo();
    console.log(3);
};

and call test(). Oh, wow, now 3 is first (someone may think that it should not be executed at all!!!) and the uncaught exception myException second. Why? Because JavaScript engine postpones exception handling. Don't ask me why, I have no idea, but I'm sure there is a reason for this... like for everything. ;)

Conclusion: Promises don't make things automatically asynchronous and always await or use .then() with a function that returns a Promise (unless you're a ninja).

Upvotes: 5

user229044
user229044

Reputation: 239462

There are two interpretations of "async" here, and the answer to both is "no", promises don't make fs.readFileSync any kind of asynchronous.

The first interpretation would be, does new Promise behave like setTimeout. It doesn't.

Promises invoke their callback functions immediately. They do not defer execution, meaning a blocking function wrapped in a promise will still block the main thread of execution.

There is no difference between these implementations:

function getFileContent(filepath){
    return new Promise((resolve, reject) => {
        fs.readFileSync("asd.txt"));
    });
}

and

function getFileContent(filepath){
  fs.readFileSync("asd.txt"));
}

Both of these call fs.readFileSync immediately on the current callstack.

To make the function "async" (as in, to defer its execution) you need to use setTimeout. You can wrap that in a promise, but you're adding no functional change by doing so, only syntactic sugar.

The second interpretation of "async" could be whether you can prevent your program from blocking on a call to fs.readFileSync. That is impossible, fs.readFileSync will always be blocking, and if it takes 10 seconds to read that file, your program will always be unresponsive for 10 seconds, no matter how you try to defer the execution with promises or setTimeout.

The only fix is to use fs.readFile, not fs.readFileSync. This is why the non-sync versions of these functions exist: It is impossible to make fs.readFileSync not break your program on large/slow reads.

Upvotes: 0

Related Questions