可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I was playing around with call backs and deferred functions in jQuery and was wondering if anyone could tell me why this works
http://jsfiddle.net/austinbv/QVujr/
get_each_total = function(callback) {
var requests;
requests = [];
var url;
url = "http://otter.topsy.com/search.js?callback=?&apikey=38A260E9D12A4908B1AF9184B691131&q=justin+bieber&window=d";
return requests.push($.getJSON(url, function(data) {
}));
return $.when.apply($, requests).then(function() {
callback();
}, function() {
return alert("There was an error communicating with a remote library, try again in a few");
});
};
get_each_total_broken = function(callback) {
var requests;
requests = [];
var url;
url = "http://otter.topsy.com/hjhkl/sehjkhhkjhkarch.js?callback=?&apikey=38A260E9D12A4908B1AF9184B691131&q=justin+bieber&window=d";
return requests.push($.getJSON(url, function(data) {
}));
return $.when.apply($, requests).then(function() {
callback();
}, function() {
return alert("There was an error communicating with a remote library, try again in a few");
});
};
$(function () {
get_each_total(alert("success"));
get_each_total_broken(alert("fail"));
});
and this does not
http://jsfiddle.net/austinbv/wzve6/
get_each_total = function(callback) {
var requests;
requests = [];
var url;
url = "http://otter.topsy.com/search.js?callback=?&apikey=38A260E9D12A4908B1AF9184B691131&q=justin+bieber&window=d";
return requests.push($.getJSON(url, function(data) {
}));
return $.when.apply($, requests).then(function() {
callback();
}, function() {
return alert("There was an error communicating with a remote library, try again in a few");
});
};
get_each_total_broken = function(callback) {
var requests;
requests = [];
var url;
url = "http://otter.topsy.com/hjhkl/sehjkhhkjhkarch.js?callback=?&apikey=38A260E9D12A4908B1AF9184B691131&q=justin+bieber&window=d";
return requests.push($.getJSON(url, function(data) {
}));
return $.when.apply($, requests).then(function() {
callback();
}, function() {
return alert("There was an error communicating with a remote library, try again in a few");
});
};
$(function () {
get_each_total(function () { alert("success")});
get_each_total_broken(function () {alert("fail")});
});
as you can see the only difference is in the last two lines, where an anonymous function wraps the callback. Any insight would be nice.
回答1:
This piece of code:
return requests.push($.getJSON(url, function(data) {
}));
exits out of your function. The callback
is never called.
P.S. When you're saying the only difference is an anonymous function wrapping the callback
, you imply that you're also passing a function in the first version of your code. That is not true; you're trying to pass in whatever alert('whatever');
is returning, which is undefined
!
Further explanation:
Both of your functions (get_each_total
, & get_each_total_broken
) expect the parameter to be a function. This is evident by you trying to call it as a function later on in your code (callback()
). However, this line:
get_each_total(alert("success"));
does not pass a function to get_each_total
. It is equivalent to the following:
var returnedFromAlert = alert("success");
get_each_total(returnedFromAlert);
So, basically, you're not passing anything into your get_each_total
function. You get a success
alert right away, before get_each_total
has been called.
回答2:
get_each_total(function () { alert("success")});
here you have the function (){ alert ....
that returns a function object
get_each_total(alert("success"));
here alert("success")
is an object of whatever type alert()
returns and it is not a function.
Edit:- in respone to the comment i'm going to further clarify.
when the browser sees
do_something(is_it_complete(arg1, arg2));
it goes throught the following steps:
- Get the function
is_it_complete
and call it arguments arg1
and arg2
.
- get the function
do_something
and call it with the result of the above as an argument.
When the browser sees:
do_something(function () { is_it_complete(arg1, arg2) });
it does:
- Create a function object that calls
is_it_complete(arg1, arg2)
- Get the function
do_something
and call it with the above object as an argument.
Edit 3:- Ok so in the first one it called the alert before running your code so it appeared to work.
you have:
get_each_total = function(callback) {
// ... *snip*
return requests.push($.getJSON(url, function(data) {}));
return $.when.apply($, requests).then(function() {
// ... *snip*
});
};
the second return is never reached.
Edit:- thought i would put a few tips after reading the code:
var requests;
requests = [];
is redundant change that style to
var requests = [];
var url = " ....";
When you do not pass any arguments to a callback do no wrap it.
.then(function(){ callback();})
it is the same as:
.then(callback);
and as mentioned in the comments your url
url = "http://otter.topsy.com/hjhkl/sehjkhhkjhkarch.js?callback=?&apikey=38A260E9D12A4908B1AF9184B691131&q=justin+bieber&window=d";
Should be
url = "http://otter.topsy.com/hjhkl/sehjkhhkjhkarch.js?callback=somevalue&apikey=38A260E9D12A4908B1AF9184B691131&q=justin+bieber&window=d";
or even:
url = "http://otter.topsy.com/hjhkl/sehjkhhkjhkarch.js"
$.getJSON(url, {
"callback": "somevalue",
"apikey": "38A260E9D12A4908B1AF9184B691131",
"q": "justin bieber",
"window": "d"
}, function(data){ alert("Got: " + data);});
回答3:
Neither example works. (Hint to reviewers: it is the last two lines of which he speaks.)
In your first example, you call alert()
, which raises the alert dialog, even before the get_each_total()
function is called. Javascript invokes it, showing the alert (and giving the illusion than something happened), and passes the result of the alert()
call to get_each_total()
(and does the same with the alert in the following function, too). The result is null. If the callback were ever called, this would raise an error.
In the second example, you're declaring a function and passing a reference to it to get_each_total()
, which can then be called via your callback()
expression. A function is something that responds to the ()
operator, meaning "do this." It would actually do something (show the alert) if your code succeeded.
But your code does not. Going to the fiddle, and looking at the console, I see this message: "Failed to load resource: the server responded with a status of 500 (Internal Server Error)." getJSON()
never triggers the callback because it never succeeds.
[EDIT] @austinbv pointed out to me that I'd missed something. The 500 code is a deliberate test on his part. But his code is still broken in get_each_total_broken()
; there is a misplaced return
in the line
return requests.push($.getJSON(url, function(data) { }));
This returns immediately from get_each_total_broken
. The when().then()
clause is never invoked, so he never sees the error handling. The immediacy of the alerts in the first example continues to give the illusion that something happened.
回答4:
There are 2 problems with your code:
1) In the last two lines of code: The first example is passing the result of an execution of the "alert" method to both the "get_each_total" and "get_each_total_broken" methods. The second example is passing a function that when executed will call "alert". The second example is the correct method to perform.
For Example:
function test(v) {
// do something
return null;
}
// executes "test" immediately and passes it's result to "someOtherFunction"
someOtherFunction(test(v));
// will pass a function to "someOtherFunction" to be executed later
someOtherFunction(function(){ test("value"); });
2) You have 2 "return" statements in both your methods. The first "return" encountered within a method will return it's value and exit the method; thus resulting in the second "return" statement to never be executed. Consiquentially, the call to "$.when.apply" in both methods will never, ever get executed.