Eugene V Eugene V - 1 month ago 12
Node.js Question

Method returning promise is not fully executed despite using await keyword?

I'm new to JavaScript and actively learning. I am calling a method that returns a promise from within an async method of a ES2016 class, using the await keyword:

export default class MyClass extends Model {
async getReport() {
const value = await xlsx.save(await this._getReportFileName());
console.log('await keyword returned method value');
console.log(`The value is: ${value}`);
return true;
}
}


Can anyone spot the reason why the method executes before it has a chance to execute its logic and before resolve is called. The await keyword does not seem to wait for the promise to actually be returned, and the value being output to console is aways undefined.

Object xlsx is an instance of class File that has a method save:

export default class File {
save(filename, options) {
writer.save(this, filename, options);
}
}


Here is the code for save helper method being called:

function save(xlsx, filename, options) {
return new Promise((resolve, reject) => {
try {
const stream = fs.createWriteStream(filename, options);
const zip = archiver('zip');

stream.on('close', () => {
console.log('Resolving promise');
resolve();
});

stream.on('error', (err) => {
console.log('Rejecting promise');
reject(err);
});

zip.pipe(stream);

const file1 = 'fixtures/file1.txt';
const file2 = 'fixtures/file2.txt';

zip
.append(fs.createReadStream(file1), {
name: 'file1.txt'
})
.append(fs.createReadStream(file2), {
name: 'file2.txt'
})
.finalize();
} catch (error) {
console.log('Error when saving');
reject(error);
}
});
}


Could it be that resolve() is not even accessible/available in the scope of listening on the stream event? If so, how can one resolve a promise properly while listening on a stream event?

Answer

Your save(filename, options) pass-through method is not asynchronous, and it's not returning the promise from the save(xlsx, filename, options) method.

Try this:

export default class File {
    async save(filename, options) {
        await writer.save(this, filename, options);
    }
}

Or this:

export default class File {
    save(filename, options) {
        return writer.save(this, filename, options);
    }
}