Javascript函数命令

时间:2015-08-10 15:22:28

标签: javascript jquery ajax

我正在创建一个jquery库来使用带有json rpc协议的应用程序,但我遇到了一个小问题。 这是显示代码的小提琴(显然它不起作用):https://jsfiddle.net/L9qkkxLe/3/

;(function($) {
  $.lib = function(options) {

    var outputHTML = [],
      plugin = this;

    var APIcall = function(api_method, api_params) {
      request = {};
      request.id = Math.floor((Math.random() * 100) + 1);
      request.jsonrpc = '2.0';
      request.method = api_method;
      request.params = (api_params) ? api_params : [];


      $.ajax({
        type: "POST",
        url: "http://localhost:8898/jsonrpc",
        data: JSON.stringify(request),
        timeout: 3000,
        beforeSend: function(xhr) {
          xhr.setRequestHeader('Authorization', window.btoa(options.username + ":" + options.password));
        },
        success: function(data) {
          handleData(data, api_method);
        },
        error: function(jqXHR, textStatus, errorThrown) {
          log("Connection time out: can't reach it. Try changing the settings.");
          isConnected = "false";
        },
        dataType: "json"
      });


    }

    var handleData = function(data, method) {


      if (method == "getgenres") {
        outputHTML = data.result.genres; //I need data.result.genres to return in getgenres function
      }

    }


    var log = function(msg) {
      if (options.debug == true) console.log(msg);
    }


    plugin.getgenres = function() {
      APIcall("getgenres");
      return outputHTML; //This is sadly empty.
    }


  };
}(jQuery));

var init = new $.lib();
console.log(init.getgenres());

我需要getgenres函数返回data.result.genres但实际上它返回一个空数组,因为首先调用getgenres并且只有在handleData函数为outputHTML提供我需要的值之后才会调用它。

2 个答案:

答案 0 :(得分:4)

您正在执行asynchronous AJAX请求,这意味着您无法立即获取数据。有两种方法可以解决您的问题:使其同步(容易但不明智)或使用回调(稍微复杂但通常被接受):

getgenres功能中,您可以再接受一个参数:callback

plugin.getgenres = function(callback) {
    /* Dont forget APIcall already took two parameters in, so callback has to be the third in line! */
    APIcall("getgenres", false, callback);
}

现在修改您的APIcall功能以接受您的回调:

var APIcall = function(api_method, api_params, callback) { ... }

从成功完成调用中调用回调 - 而不是在函数中包含处理程序方法,您可以简单地传递匿名函数。因此,请使用:

而不是success: function(data){ handle(data); }
success: callback

我们将传递给它的anonymous函数将接收您传递给处理程序的数据的第一个参数。现在您可以执行以下操作:

var myGenres = [];
var init = new $.lib();
init.getgenres(function(data){
    /* Now your data is actually loaded and available here. */
    myGenres = data;
    console.log(myGenres);
});

我想指出有很多更好的方法可以解决这个问题,包括将其转换为Constructor(更多信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain),而不是将函数和变量奇怪地合并在一起现在,以及使用JS Promises(这里:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)来简化这一过程。但基本要点应该在这里。

更新(潜在实施)

因为我提到这可以通过我认为更清楚阅读和使用的方式来完成。我不知道所有用例,但从提供的示例我将代码更改为如下所示。还请注意我不是jQuery插件的专家,因此我避免插入jQuery并将其用作简单的AJAX调用。

function getAjax(){
    if(!window.jQuery || !window.$) throw("jQuery is required for this plugin to function.");
    this.data    = [];
    this.request = '';
    return this;
}
getAjax.prototype = {
    createRequest : function(method, parameters){
        this.request             = {};
        this.request.id          = Math.floor((Math.random() * 100) + 1);
        this.request.jsonrpc     = '2.0';
        this.request.method 	 = method;
        this.request.params      = parameters || [];
        return this;
    },
    callRequest : function(options, callback, error){
        var self = this;
        // We could also `throw` here as you need to set up a request before calling it.
        if(!this.request) return this;
        else {
            $.ajax({
                // We will allow passing a type and url using the options and use sensible defaults.
                type:    options.type || "POST",
                url:     options.url || "http://localhost:8898/jsonrpc",
                // Here we use the request we made earlier.
                data:    JSON.stringify(this.request),
                timeout: options.timeout || 3000,
                beforeSend: function(xhr){
                    xhr.setRequestHeader(
                        'Authorization', 
                        window.btoa( options.username + ":" + options.password)
                    ); 
                },
                // We will also store all the made request in this object. That could be useful later, but it's not necessary. After that, we call the callback. 
                success: function(data){
                    var store = {request:self.request, data: data};
                    self.data.push(store);
                    // Call the callback and bind `this` to it so we can use `this` to access potentially pther data. Also, pass the results as arguments.
                    callback(data, self.request.id).bind(self);
                },
                // Error function!
                error:    error,
                dataType: options.dataType || "json"
            });
        }
        return this;
    }
}

// Example use

new getAjax().createRequest('getgenres').callRequest({
    username: 'myusername',
    password: 'mypassword'
}, function(data, id){
    // Success! Do with your data what you want.
    console.log(data);
}, function(e){
    // Error!
    alert('An error has occurred: ' + e.statusText);
    console.log(e);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>

答案 1 :(得分:0)

在这些场合我做的是:

您正在提供方法。所以提出一个回调函数的引用。在这种情况下plugin.getGenresFinalize。当调用handleData时,它将触发该callBack函数。这样,您可以将多个方法传递给api call以获取不同类型的数据。

    plugin.getgenres = function() {
        APIcall(this.getgenresFinalize);
    }

    plugin.getgenresFinalize = function(data) {
         console.log(data);
    }

    var handleData = function(data, method) {
          method(data);
     }