我正在创建一个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提供我需要的值之后才会调用它。
答案 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);
}