[Ionic 4] I can't get data from function readDataAsURL(), returning a promise instead

Context
I’m trying to receive an image file from my external storage as base64, to do this I’m using the function readAsDataURL(), that comes with the Ionic File plugin, which is based in File API. I don’t know what I’m doing wrong, because I can see the base64 string from the log inside the function, but I can’t return this string correctly, instead I’m getting what I suppose to be a Promise object (ZoneAwarePromise)


My Function

...    
let imageAsBase64 = this.uriToBase64(arrayItem2.filePath).then(() => {
    console.log("image as base64: ", imageAsBase64); // Receiving the  ZoneAwarePromise here
});
...

async uriToBase64(uri) {
    let nameFile = uri.replace(this.file.dataDirectory, '');

    await this.file.readAsDataURL(this.file.dataDirectory, nameFile).then((file64) => {
        let fileWithoutExtension = ('' + file64 + '').replace(/^data:image\/(png|jpg|jpeg);base64,/, '');
        console.log("File without extension: ", fileWithoutExtension); // Receiving the base 64 correctly here
        return fileWithoutExtension;
    })
    .catch(err => {
        console.log("Error while transforming image to base64: ", err);
    });     
}

Details

I think the way I’m using the function is correct, we can see the same usage here.

I found some related questions, but they don’t helped me much:
Problem with Ionic Capacitor, pretty similar to my problem
Ionic storage problem, returning ZoneAwarePromise too
StackOverflow similar question


Attempts

Attempt 1

Changing the first part to:

...    
this.uriToBase64(arrayItem2.filePath).then((imageAsBase64) => {
    console.log("image as base64: ", imageAsBase64); 
});
...

stops the error ZoneAwarePromise error, but I still can’t receive the data. Receiving undefined instead.

Attempt 2

While changing the async syntax to an Obsevable function I still get an ZoneAwarePromise object, but at least now the value inside (__zone_symbol__value) contain the base64 string I want. So how do I receive this data correctly and not this Promise object?

uriToBase64(uri): Observable<any> {
	let nameFile = uri.replace(this.file.dataDirectory, '');
	let output = this.file.readAsDataURL(this.file.dataDirectory, nameFile).then((file64) => {
		let fileWithoutExtension = ('' + file64 + '').replace(/^data:image\/(png|jpg|jpeg);base64,/, '');
		console.log("File without extension: ", fileWithoutExtension);
		return fileWithoutExtension;
	})
	.catch(err => {
		console.log("Error while transforming image to base64: ", err);
	});
	return of(output);		
}

Try it this way:

async uriToBase64(uri) {
    try{
		let nameFile = uri.replace(this.file.dataDirectory, '');
		let file64 = await this.file.readAsDataURL(this.file.dataDirectory, nameFile);
		let fileWithoutExtension = ('' + file64 + '').replace(/^data:image\/(png|jpg|jpeg);base64,/, '');
		console.log("File without extension: ", fileWithoutExtension); // Receiving the base 64 correctly here
		return fileWithoutExtension;
    }catch(err) {
        console.log("Error while transforming image to base64: ", err);
    }
}

Doing this way I receive the “image as base64” log as:

ZoneAwarePromise {__zone_symbol__state: null, __zone_symbol__value: Array(0)}
__zone_symbol__state: true
__zone_symbol__value: undefined
Symbol(Symbol.toStringTag): undefined
proto: Object

I recommend avoiding async/await until you are completely certain what they are actually doing (and arguably even then). If you try rewriting all of this without them, and giving proper types for every parameter and function return value, your development environment will help you understand the impossibility of what you are trying to do here.

uriToBase64 is asynchronous and going to return a Promise, no matter how much you may wish it to be synchronous and return whatever that Promise will eventually resolve to. Callers of uriToBase64 need to be adjusted to adapt to that reality.

Since I have this problem I have been trying to better understand the operation of async/await and especially the sending/receiving parameters in this function. As mentioned in OP, inside uriToBase64() everything is working fine, but I can’t understand why the response is undefined outside the function. As I understand it, when I use .then() for an asynchronous function, everything later will be related to the end/response of this function.

While waiting for some illumination regarding this problem I’m also trying to rewrite this code, but I’m find quite difficult to handle the response of readAsDataURL() function without the async syntax. Please check my updated “attempt 2” if you have time, I also tried with an Observable and received more hopeful results.

this.uriToBase64(arrayItem2.filePath).then((_result) => {
    console.log("image as base64: ", _result); // Receiving the  ZoneAwarePromise here
});

and I think… along with changing some variable names to make better sense

uriToBase64(uri) {
    let nameFile = uri.replace(this.file.dataDirectory, '');

    return this.file.readAsDataURL(this.file.dataDirectory, nameFile).then((file64) => {
        let base64String = ('' + file64 + '').replace(/^data:image\/(png|jpg|jpeg);base64,/, '');
        console.log("data: ", base64String); // Receiving the base 64 correctly here
        return base64String;
    })
    .catch(err => {
        console.log("Error while transforming image to base64: ", err);
        return err;
    });     
}
1 Like

Okay, this is it! Now I see, I was returning a Promise inside another Promise. Thank you very much!