ionic 2 SQLite manage callback with Promise

2019-09-11 19:44发布

问题:

I want to get the callback of a successful SQLite transaction with Ionic 2. I am still currently learning the HTML5 Promise, and it is still a bit confuse. And since I've heavily used jQuery Deferred before, I try to adapt what I used to do with jQuery.

Before Ionic 2, I used the following jQuery pattern to execute my async SQL:

var SqlResult = function(sqlToExecute,bracketValues){
    this.sqlToExecute = sqlToExecute;
    this.bracketValues =bracketValues;
};

SqlResult.prototype.execSqlCustomDeferred = function(){
        var execSqlCustomDeferredRes = $.Deferred();
        var execSqlCustomDeferredResProm = execSqlCustomDeferredRes.promise();  

        var sqlToExecuteForTx = this.sqlToExecute;
        var bracketValuesForTx = this.bracketValues;

        DbManagement.db.transaction(function(tx){
            tx.executeSql(sqlToExecuteForTx,bracketValuesForTx,success,error);
            function success(tx,rs){
                    execSqlCustomDeferredRes.resolve(rs);
            }
            function error(tx,error){
                execSqlCustomDeferredRes.reject(error);
            }
        });
        return execSqlCustomDeferredResProm;
};

With that pattern I was getting the async result, with SqlResult.prototype.execSqlCustomDeferred.done(function(res){...}).

Now I struggle to figure out how things should be ordered to use the Promise pattern, I thought of the following but it does not match:

This case would not work because resolve() or reject() don't exist (it doesn't transpile).

private execSqlCustom = (sqlToExecute:string,bracketValues:Array<any>) => {
    let sqlToExecuteForTx:string = sqlToExecute;
    let bracketValueForTx:Array<any> = bracketValues;

    return this.db.transaction(
        function(tx){
            tx.executeSql(sqlToExecuteForTx,bracketValueForTx,success,error);
            function success(tx,rs){
                resolve(rs);                    
            }
            function error(tx,error){
                console.log('execSqlCustom error ' + error.message);
                reject(error);
            }
        }
    );

This would not work neither because I think I'd lose the context (this) (it transpiles but at execution it tells me that:

it cannot read db of undefined

):

private execSqlCustom = (sqlToExecute:string,bracketValues:Array<any>) => {
    let sqlToExecuteForTx:string = sqlToExecute;
    let bracketValueForTx:Array<any> = bracketValues;
    return new Promise(function(resolve,reject){
       this.db.transaction(
        function(tx){
            tx.executeSql(sqlToExecuteForTx,bracketValueForTx,resolve,reject);
        }
    );

Does anyone spot what I've been doing wrong?

回答1:

I found that it could be added a .bind(this) at the end of a function to carry within that function, the exisiting context (this).

By creating a new Promise() and adding .bind(this) at the end of the function(resolve,reject){} within it, it worked and I can use .then( (...) => {...} on the async result returned.

My function looks like that:

private execSqlCustom = (sqlToExecute:string,bracketValues:Array<any>):Promise<any> => {

    return new Promise(function(resolve,reject){
        this.db.transaction(
        function(tx){
            tx.executeSql(sqlToExecute,bracketValues,success,error);
            function success(tx,rs){
                resolve(rs);                    
            }
            function error(tx,error){
                console.log('execSqlCustom error ' + error.message);
                reject(error);
            }
        }
        )}.bind(this)
    );
}