Skip to content Skip to sidebar Skip to footer

Sequencing Async Operations Followed By Onresult Call

Fiddle: http://jsfiddle.net/smartdev101/eLxxpjp3/ Inside asyncAction function call, a promise has been created to sequence two async operations, getRecords and getTotal followed b

Solution 1:

It seems like this could be simplified. It seems like you just want these async operations to be performed synchronously. If you return the promise, the original promise in the chain will become the new promise. The final fail will catch the first promise to be rejected.

asyncAction: function(url, params, resultFunction, faultFunction) {
    puremvc.asyncproxy.AsyncProxy.prototype.asyncAction.call(this, resultFunction, faultFunction);

    if(!params.id) { //get mastervar queryString = this.url.parse(url, true).query;
        var offset = queryString.offset ? Number(queryString.offset) : 0;
        var limit = queryString.limit ? Number(queryString.limit) : 20;

        vardata = {rows: null, total: null};

        var self = this;
        this.getRecords(data, offset, limit)
        .then(function(data) {
          return self.getTotal(data);
        })
        .then(this.onResult.bind(this))
        .fail(this.onFault);
    } else { //get detailthis.getDetail(params.id);
    }
},

getRecords: function(data, offset, limit) {
    console.log('get records');
    var defer = this.q.defer();
    this.connection.query("SELECT title, name, company FROM speaker LIMIT ? OFFSET ?", [limit, offset], function(error, rows, fields){
        console.log('get records done');
        data.rows = rows;
        defer.resolve(data);
        //defer.reject("earlier");
    });
    return defer.promise;
},

getTotal: function(data) {
    console.log('get total');
    var defer = this.q.defer();

    this.connection.query("SELECT * FROM speaker", function(error, rows, fields) { //SQL_CALC_FOUND_ROWS laterdata.total = rows.length;
        console.log('get total done');
        defer.resolve(data);
        //defer.reject("just like that");
    });

    return defer.promise;
},

onResult: function(data) {
    console.log('on result');
    puremvc.asyncproxy.AsyncProxy.prototype.onResult.call(this, data);
},

Solution 2:

finally after struggling a lot, here's the solution, but I need couple of more things, calling defer.reject in any function doesn't halt the process, even done is executed

this post helped a lot. https://coderwall.com/p/ijy61g

Edit 2- Used bind as a result of suggestions - the problem is onResult gets called irrespective of failure, so I had to do if(data) check which I don't like, would have been awesome if promises had some kind of final .success (counterpart of .fail) function.

Edit 3 - added this.onResult at the end of then chain though it doesn't return any promise, is it violating any specs?

Edit 4 - promisified getConnection

getConnection: function() {
    var defer = this.q.defer();

    var mysql = require("mysql");
    var pool = mysql.createPool({
        host: common.Config.mySQLHost,
        user: common.Config.mySQLUsername,
        password: common.Config.mySQLPassword,
        database: common.Config.mySQLDatabase
    });

    pool.getConnection(function(error, connection){
        if(error) { 
            defer.reject(error)
        } else {
            defer.resolve(connection);
        }
    });
    return defer.promise;
},

asyncAction: function(url, params, resultFunction, faultFunction) {

    if(!params.id) { //get mastervar queryString = this.url.parse(url, true).query;
        var offset = queryString.offset ? Number(queryString.offset) : 0;
        var limit = queryString.limit ? Number(queryString.limit) : 20;

        var data = {rows: null, total: null};

        var self = this;
        this.getConnection()
        .then(function(connection){return self.getRecords(data, offset, limit, connection)})
        .then(function(value){return self.getTotal(value.data, value.connection)})
        .then(function(value){self.onResult(value.data, value.connection)})
        .fail(function(value){self.onFault(value.error, value.connection)})
    } else { //get detailthis.getDetail(params.id);
    }
},

getRecords: function(data, offset, limit, connection) {
    var defer = this.q.defer();
    connection.query("SELECT title, name, company FROM speaker LIMIT ? OFFSET ?", [limit, offset], function(error, rows, fields){
        if(error) {
            defer.reject({error:error, connection:connection});
        } else {
            data.rows = rows;
            defer.resolve({data: data, connection:connection});
        }
    });
    return defer.promise;
},

getTotal: function(data, connection) {
    var defer = this.q.defer();
    connection.query("SELECT count(*) AS total FROM speaker", function(error, rows, fields) { 
        if(error) {
            defer.reject({error:error, connection:connection});
        } else {
            data.total = rows[0].total;
            defer.resolve({connection:connection, data:data});
        }
    });
    return defer.promise;
},

onResult: function(data, connection) {
    console.log(data);
    connection.release();
},

onFault: function(info, connection) {
     console.log(info)
    connection.release();
}

Solution 3:

User2727195, here's my version in full, based on the original, unedited code posted in your own answer.

There's no attemtpt to improve the logic/flow, just to improve the syntax. As such, it is only as good as your answer was at that time. To get everything working properly, you will need to apply your own later ideas and other suggestions offered since then.

As such, this is not an independent answer and should not be selected. If it starts to attract negative votes, then I will delete it so trawl through for ideas while you can.

asyncAction: function(url, params) {
    if(!params.id) { //get mastervar queryString = this.url.parse(url, true).query;
        this.getRecords({}, Number(queryString.offset || 0), Number(queryString.limit || 20))
            .then(this.getTotal.bind(this))
            .fail(this.onFault.bind(this))
            .done(this.onResult.bind(this));
        } else { //get detailthis.getDetail(params.id);
    }
},
connectionQueryPromisifier = function() {
    // This is a promisifying adaptor for connection.query .// In your own version, you will probably choose to rewrite connection.query rather than use an adapter.var args = Array.prototype.slice.call(arguments).concat(function(error, rows, fields) {
        if(error) { defer.reject(error); }
        else { defer.resolve({ rows:rows, fields:fields }); }
    }),
        defer = this.q.defer();
    this.connection.query.apply(this, args);
    return defer.promise;
},
getRecords: function(data, offset, limit) {
    //Here, you take advantage of having promisified connection.query .returnthis.connectionQueryPromisifier("SELECT title, name, company FROM speaker LIMIT ? OFFSET ?", [limit, offset]).then(function(obj) {
        data.rows = obj.rows;
    });
},
getTotal: function(data) {
    //Here, you take advantage of having promisified connection.query .returnthis.connectionQueryPromisifier("SELECT * FROM speaker").then(function(obj) {
        data.total = obj.rows.length;
    });
},
onResult: function(data) {
    console.log('on result');
},
onFault: function(info) {
    console.log('onFault');
}

Post a Comment for "Sequencing Async Operations Followed By Onresult Call"