将额外参数传递给jQuery getJSON()成功回调函数 [英] Pass extra parameter to jQuery getJSON() success callback function

查看:71
本文介绍了将额外参数传递给jQuery getJSON()成功回调函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我以前从未使用过回调函数,所以我可能犯了一个完全愚蠢的错误。我想我有点理解这里的问题,但不知道如何解决它。



我的代码(有点简化)是:

  for(var i = 0; i< some_array.length; i ++){
var title = some_array [i];
$ .getJSON('some.url /'+ title,function(data){
do_something_with_data(data,i);
}

据我所知,只有在getJSON()收到数据时才会调用此匿名函数。但到此为止, i 没有我需要的值。或者,就我的观察而言,它具有循环完成后它将具有的最后一个值(它不应该超出界限吗? )。



结果,如果数组的大小为6,那么 do_something_with_data()将被称为五值为5的时间。



现在我想,只需将 i 传递给匿名函数

  function(data,i){} 

但这似乎不可能。现在未定义。

解决方案

<你需要了解闭包是什么。在javascript中,当你使用的函数内部时在外部上下文(外部函数或全局)中定义的变量,您在该变量周围创建一个闭包,它保持变量实例化,并让函数在每次调用时继续引用它(以及任何其他函数)在项目上有一个闭包的实例。)



因为原始变量仍然是实例化的,所以如果你在中更改该变量的值代码,当函数稍后运行时,它将具有当前更改的值,该函数首次创建时的值。



在我们解决之前使闭包正常工作,请注意在循环中重复声明 title 变量不起作用(实际上,您可以认为该变量基本上是悬挂进入函数的范围 - 与其他一些语言不同,JavaScript中的 for 循环没有范围因此,变量仅为函数a声明一次 nd在循环中声明或重新声明 。在循环外声明变量应该有助于澄清为什么你的代码没有按照你期望的那样工作。



当回调运行时,因为它们有对同一个变量 i 的闭包,当 i 递增时它们都会受到影响,并且它们都会使用当前 i 当它们运行时(这将是你发现的错误,因为回调在循环完成后运行创建回调)。在所有同步代码完成执行之前,异步代码(例如JSON调用响应)不会运行也无法运行 - 所以在执行任何回调之前保证循环完成。



<为了解决这个问题,你需要一个新的函数来运行它有自己的范围,这样在循环内部声明的回调中,每个不同的价值。您可以使用单独的函数执行此操作,或者只在callback参数中使用调用的匿名函数。这是一个例子:

  var title,i; 
for(i = 0; i< some_array.length; i + = 1){
title = some_array [i];
$ .getJSON(
'part.url /'+ title,
(function(thisi){
return function(data){
do_something_with_data(data,thisi) );
//通过参数`thisi`打破关于`i`的闭包,
//这将从* invocation * time中保存正确的值。
};
}(i))//用当前值
)调用函数;
}

为了清楚起见,我会将其分解为单独的函数,以便您可以看到发生了什么:

  function createCallback(item){
return function(data){
do_something_with_data(数据项);
//对`item`参数的引用会在其上创建一个闭包。
//但是,其范围意味着没有调用者函数可以更改其值。
//因此,既然我们不在`createCallback`内的任何地方更改`item`,那么
//将具有createCallback函数
//时的值。调用。
};
}

var title,i,l = some_array.length;
for(i = 0; i< l; i + = 1){
title = some_array [i];
$ .getJSON('some.url /'+ title,createCallback(i));
//注意这个参数不是createCallback函数的* reference *,
//但是createCallback()的*值返回*,它本身就是一个函数。
}

注意:由于您的阵列显然只有标题,您可以考虑使用 title 变量而不是 i ,这要求你回到 some_array 。但无论哪种方式都有效,你就知道自己想要什么。



一种可能有用的方法来考虑回调创建函数(匿名或<$ c) $ c> createCallback one)实质上将 i 变量的转换为单独的 thisi 变量,每次引入一个具有自己范围的新函数。也许可以说参数打破了闭包之外的值。



请注意:这种技术不会在没有复制它们的情况下对对象起作用,因为对象是引用类型。仅仅将它们作为参数传递将不会产生事后不能改变的东西。您可以复制街道地址,但这不会创建新房。如果你想要一个能够带来不同的地址,你必须建造一所新房子。


I've never had to use callback functions before, so I may have made a completely stupid mistake. I think I somewhat understand the problem here, but not how to solve it.

My code (a bit simplified) is:

for (var i = 0; i < some_array.length; i++) {
    var title = some_array[i];
    $.getJSON('some.url/' + title, function(data) {
        do_something_with_data(data, i);
    }

Now as far as I understand, this anonymous function will only be called if getJSON() has received the data. But by this point, i does not have the value I would require. Or, as far as my observation goes, it has the last value it would have after the loop is done (shouldn't it be out of bounds?).

As a result, if the array had a size of 6, do_something_with_data() would be called five times with the value 5.

Now I thought, just pass i to the anonymous function

function(data, i) { }

but this does not seem to be possible. i is undefined now.

解决方案

You need to understand what a closure is. In javascript, when inside a function you use a variable that was defined in an outer context (outer function or global), you create a closure around that variable, which keeps the variable instantiated and lets the function continue to refer to it each time it is invoked (as well as any other function instances with a closure on the item).

Because the original variable is still instantiated, if you change the value of that variable anywhere in the code, when the function runs later it will have the current changed value, not the value when the function was first created.

Before we address making the closure work right, note that declaring the title variable repeatedly in the loop doesn't work (in fact, you can think of the variable as essentially being hoisted into the function's scope--unlike some other languages, for loops in JavaScript have no scope, therefore the variable is declared only once for the function and is not declared or redeclared inside the loop). Declaring the variable outside the loop should help clarify for you why your code isn't working as you'd expect.

As is, when the callbacks run, because they have a closure over the same variable i, they are all affected when i increments and they will all use the current value of i when they run (which will be wrong as you discovered, because the callbacks run after the loop has completely finished creating the callbacks). Asynchronous code (such as the JSON call response) does not and cannot run until all synchronous code finishes executing--so the loop is guaranteed to complete before any callback is ever executed.

To get around this you need a new function to run that has its own scope so that in the callbacks declared inside of the loop, there is a new closure over each different value. You could do that with a separate function, or just use an invoked anonymous function in the callback parameter. Here's an example:

var title, i;
for (i = 0; i < some_array.length; i += 1) {
    title = some_array[i];
    $.getJSON(
       'some.url/' + title,
       (function(thisi) {
          return function(data) {
             do_something_with_data(data, thisi);
             // Break the closure over `i` via the parameter `thisi`,
             // which will hold the correct value from *invocation* time.
          };
       }(i)) // calling the function with the current value
    );
}

For clarity I'll break it out into a separate function so you can see what's going on:

function createCallback(item) {
   return function(data) {
      do_something_with_data(data, item);
      // This reference to the `item` parameter does create a closure on it.
      // However, its scope means that no caller function can change its value.
      // Thus, since we don't change `item` anywhere inside `createCallback`, it
      // will have the value as it was at the time the createCallback function
      // was invoked.
   };
 }

var title, i, l = some_array.length;
for (i = 0; i < l; i += 1) {
    title = some_array[i];
    $.getJSON('some.url/' + title, createCallback(i));
    // Note how this parameter is not a *reference* to the createCallback function,
    // but the *value that createCallback() returns*, which is itself a function.
}

Note: since your array apparently only has titles in it, you could consider using the title variable instead of i which requires you to go back to some_array. But either way works, you know what you want.

One potentially useful way to think about this that the callback-creating function (either the anonymous one or the createCallback one) in essence converts the value of the i variable into separate thisi variables, via each time introducing a new function with its own scope. Perhaps it could be said that "parameters break values out of closures".

Just be careful: this technique will not work on objects without copying them, since objects are reference types. Merely passing them as parameters will not yield something that cannot be changed after the fact. You can duplicate a street address all you like, but this doesn't create a new house. You must build a new house if you want an address that leads to something different.

这篇关于将额外参数传递给jQuery getJSON()成功回调函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆