使用Pattern promise jquery将异步函数更改为同步函数

时间:2014-07-27 21:40:19

标签: javascript jquery asynchronous

我试图用Javascript最好的实践,但对我来说这很难。在这种情况下,我想使用一些功能"避免"回调。我试图使用jquery的Deferred对象来做到这一点。所以我相信我不知道如何正常工作。

我正在使用 phonegap + emberjs + cordova-sqlite-plugin

我实现了回调的后续功能。

getPuntos: function(callback)
{
    var db = window.sqlitePlugin.openDatabase("Rondas", "1.0", "Dev", -1);

    var ret ={data:false};
    db.transaction(function(tx)
    {
        tx.executeSql("SELECT * from Punto;",[], function(tx, res)
        {
            if( res.rows.length !== 0)
            {
                var puntos =  [];
                for( var i=0; i<res.rows.length; i++)
                {
                    var descripcion = res.rows.item(i).descripcion;
                    var id = res.rows.item(i).id;
                    //console.log( descripcion );
                    var punto = App.Punto.create( { index: i, id:id, descripcion: descripcion});
                    puntos.push( punto );
                }
                ret.data = puntos;
                callback(ret.data);
            }

        });
    },function(tx,err){
        console.log('Error SQL'+err);
    },function(){
        console.log( 'Base de datos abierta' );
    });     
}

我也使用它:

this.getPuntos(function(puntos){
   for( var i=0; i<puntos.length; i++){
     console.log( puntos[i] );
   }
});

好吧,但我尝试实现一些非常简单明了的东西:

//whitout use a callback.
var puntos = this.getPuntos();
for( var i=0; i<puntos.length; i++){
     console.log( puntos[i] );
}

然后我尝试这样做:

  1. 将函数getPuntos更改为_getPuntos,此函数具有延迟的对象。
  2. 函数getPuntos是包装器,用于处理方法_getPuntos中的promise的结果并尝试返回。(但不起作用)
  3. _getPuntos: function()
    {
        var db = window.sqlitePlugin.openDatabase("Rondas", "1.0", "Dev", -1);
        var deferred = jQuery.Deferred();   
        var ret ={data:false};
        db.transaction(function(tx)
        {
            tx.executeSql("SELECT * from Punto;",[], function(tx, res)
            {
                if( res.rows.length !== 0)
                {
                    var puntos =  [];
                    for( var i=0; i<res.rows.length; i++)
                    {
                        var descripcion = res.rows.item(i).descripcion;
                        var id = res.rows.item(i).id;
                        //console.log( descripcion );
                        var punto = App.Punto.create( { index: i, id:id, descripcion: descripcion});
                        puntos.push( punto );
                    }
                    //ret.data = puntos;
                    //callback(ret.data);
                    deferred.resolve(puntos);
                }
    
            });
        },function(tx,err){
            console.log('Error SQL'+err);
        },function(){
            console.log( 'Base de datos abierta' );
        });
        return deferred.promise(); 
    },
    

    包装器:

    getPuntos: function()
    {
        var promise  = this._getPuntos();
        var ret = {data:false};
        promise.done(function(result)
        {
            ret.data = result;
            return ret.data;
        }); 
        while(ret.data ===false ){} //wait for the result until it's available
        return ret.data;        
    },
    

    在主要功能中我称之为:

    var puntos = this.getPuntos();
    console.log( puntos+"--shoulbe [object]"); //I get Undefined or false, but no my array.
    

    那么,有没有办法做到这一点我想要同步转换异步函数 功能?

    感谢您的所有答案。

2 个答案:

答案 0 :(得分:2)

这里的主要问题是第二个示例中的getPuntos()函数不返回任何内容,因此返回null / false值。

getPuntos: function() 
{
    var promise  = this._getPuntos();
    var ret = {data:false};
    promise.done(function(result)
    {
         // This happens in the future
         ret.data = result;
         return ret.data;
    });    
// This happens now and there is nothing returned 
},

当你的诺言完成后(promise.done),它会返回ret.data,但会返回到promise并被忽略。它的范围是错误的。你在思考传统的“拉动”。模型,数据被拉向您,程序阻塞,直到数据可用。 Javascript使用回调功能,而且更像是一种推送功能。模型,当数据可用且没有阻塞时,数据被推送到回调函数。

你需要重新安排事情。例如,getPuntos函数应返回promise。

getPuntos: function() 
{
    var promise  = this._getPuntos();
    return promise;
},

主要功能应该在履行承诺时添加回调。

var puntos = this.getPuntos();
puntos.done(function(result) {
    console.log( result+"--shoulbe [object]");
});

尽管getPuntos()函数在这里有点多余,因为它只返回_getPuntos()的值。

答案 1 :(得分:1)

问题是您的getPuntos()函数设置了promise.done操作,但返回的值永远不会传递给您的程序的其余部分。正如NoxHarmonium所说,您的getPuntos()方法是多余的,应与_getPuntos()结合使用,但您可能需要以下内容(正如您在 this jsFiddle中看到的那样)

PuntosPromise = function() {
    this.result = null;
    this._getPuntos = function() {
        var deferred = $.Deferred();
        setTimeout(function(scope) {
            scope.result = "It works."
            deferred.resolve();
        }, 500, this);
        return deferred.promise();
    }
    this.getPuntos = function()
    {
        var promise  = this._getPuntos();
        return promise;        
    }
    this.getResults = function() {
        return this.result;
    };
}
$("#tester").click(function() {
    var test = new PuntosPromise();
    $.when(test.getPuntos()).then(function() {
        alert(test.getResults());
    });
});

编辑:

请参阅下面给出的@ Bergi的修改。虽然这段代码有效,但他的解决方案更清晰。