对异步操作进行排序,然后进行onResult调用

时间:2014-10-24 17:24:17

标签: javascript node.js promise q

小提琴:http://jsfiddle.net/smartdev101/eLxxpjp3/

在asyncAction函数调用中,已创建一个承诺,对两个异步操作getRecordsgetTotal进行排序,然后在成功时调用onResult(data)onFail(info)例外情况。

完成两个异步操作后如何进行onResult调用?

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

    if(!params.id) { //get master
        var 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.getRecords(data, offset, limit)
        .then(function(data){return self.getTotal(data)})
        //.fail(function(error){self.onFault(error)})
        .done(function(data){self.onResult(data)})

    } else { //get detail
        this.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 later
        data.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);
},

onFault: function(info) {
    puremvc.asyncproxy.AsyncProxy.prototype.onFault.call(this, info);
}

3 个答案:

答案 0 :(得分:0)

经过艰苦努力后,终于解决了这个问题,但是我需要做更多的事情,在任何函数中调用defer.reject都不会停止进程,甚至执行完毕

这篇文章帮了很多忙。 https://coderwall.com/p/ijy61g

编辑2-使用绑定作为建议的结果 - 问题是onResult被调用而不管失败,所以我必须做if(data)检查我不喜欢的,会有如果承诺具有某种最终.success.fail)对应函数,那就太棒了。

编辑3 - 在当时链的末尾添加了this.onResult,虽然它没有返回任何承诺,是否违反了任何规范?

编辑4 - 已宣传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 master
        var 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 detail
        this.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();
}

答案 1 :(得分:0)

似乎可以简化这一点。您似乎只希望同步执行这些异步操作。如果您退回承诺,链中的原始承诺将成为新承诺。最终的失败将抓住第一个被拒绝的承诺。

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

    if(!params.id) { //get master
        var 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.getRecords(data, offset, limit)
        .then(function(data) {
          return self.getTotal(data);
        })
        .then(this.onResult.bind(this))
        .fail(this.onFault);
    } else { //get detail
        this.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 later
        data.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);
},

答案 2 :(得分:0)

User2727195,这是我的完整版本,基于您自己的答案中发布的原始未经编辑的代码。

没有改进逻辑/流程的方法,只是为了改善语法。因此,它与你当时的答案一样好。为了使一切正常运行,您需要应用自己以后提出的想法和其他建议。

因此,这不是一个独立的答案,不应该被选中。如果它开始吸引负面投票,那么我会删除它,以便尽可能拖拽想法。

asyncAction: function(url, params) {
    if(!params.id) { //get master
        var 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 detail
        this.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 .
    return this.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 .
    return this.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');
}