将额外的参数传递给jQuery getJSON成功回调函数

如何解决将额外的参数传递给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。 现在我想,只需将ѭ1传递给匿名函数
function(data,i) { }
但这似乎是不可能的。我现在不确定。     

解决方法

您需要了解什么是闭包。在javascript中,当在函数内部使用在外部上下文(外部函数或全局)中定义的变量时,将围绕该变量创建一个闭包,以使该变量实例化,并让函数每次对其进行引用时都可以继续引用该变量被调用(以及其他任何在项目上带有闭包的函数实例)。 因为原始变量仍在实例化,所以如果您在代码中的任何位置更改该变量的值,则该函数在稍后运行时将具有当前更改的值,而不是首次创建该函数时的值。 在我们让闭包正常工作之前,请注意,在循环中重复声明
title
变量是行不通的(实际上,您可以认为该变量实际上已被提升到
function
的范围内,与其他变量不同)语言,JavaScript中的“ 7”循环没有作用域,因此该变量对于该函数仅声明一次,并且不会在循环内部声明或重新声明)。在循环外声明变量应该有助于您阐明为什么代码无法按预期工作。 照原样,当回调运行时,由于它们在同一个变量
i
上有一个闭包,因此当
i
递增时它们都会受到影响,并且它们在运行时都将使用
i
的当前值(这是您发现的错误,因为回调在循环完全完成创建回调之后运行)。异步代码(例如JSON调用响应)不会并且无法运行,直到所有同步代码执行完毕-因此,可以确保在执行任何回调之前完成循环。 为了解决这个问题,您需要运行一个具有自己范围的新函数,以便在循环内部声明的回调中,每个不同的值都有一个新的闭包。您可以使用单独的函数执行此操作,或者仅在callback参数中使用调用的匿名函数。这是一个例子:
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
    );
}
为了清楚起见,我将其分解为一个单独的函数,以便您了解发生了什么:
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.
}
注意:由于您的数组显然只包含标题,因此您可以考虑使用
title
变量而不是
i
,这需要您返回
some_array
。但是无论哪种方法,您都知道想要什么。 考虑这一点的一种可能有用的方法是,通过每次引入一个具有自己作用域的新函数,回调创建函数(匿名函数或
createCallback
函数)实质上将the1ѭ变量的值转换为单独的
thisi
变量。也许可以说“参数使值脱离了闭包”。 请注意:由于对象是引用类型,因此该技术在不复制对象的情况下将不起作用。仅将它们作为参数传递将不会产生某些事后无法更改的内容。您可以随意复制街道地址,但这不会创建新房子。如果您想要一个通往其他地方的地址,则必须盖一栋新房子。     ,您可以使用返回另一个函数的立即函数(立即执行的函数)创建闭包:
for (var i = 0; i < some_array.length; i++) {
    var title = some_array[i];
    $.getJSON(\'some.url/\' + title,(function() {
        var ii = i;
        return function(data) {
           do_something_with_data(data,ii);
        };
    })());
}
    ,如果您可以在
some.url
修改服务,那么,与其对
some_array
中的每个项目进行单独的HTTP请求,而是仅在单个HTTP请求中传递数组中的每个项目,那就更好了。
$.getJSON(\'some.url\',{ items: some_array },callback);
您的数组将被JSON序列化并发布到服务器。假设“ 15”是一个字符串数组,则请求将如下所示:
POST some.url HTTP/1.1
...

{\'items\':[\'a\',\'b\',\'c\',... ]}
然后,您的服务器脚本应反序列化来自请求主体的JSON请求,并遍历
items
数组中的每个项目,并返回一个JSON序列化的响应数组。
HTTP/1.1 200 OK
...

{\'items\':[{id:0,... },{id:1,... ]}
(或者您返回的是任何数据。)如果您的响应项与请求项的顺序相同,则很容易将它们组合在一起。在您的成功回调中,只需将项目索引与
some_array
的索引匹配即可。放在一起:
$.getJSON(\'some.url\',function(data) {
    for (var i = 0; i < data.items.length; i++) {
        do_something_with_data(data.items[i],i);
    }
});
通过将请求“分包”为单个HTTP请求,您将大大提高性能。考虑一下,如果每个网络往返至少花费200毫秒(包含5个项目),则您的延迟至少为1秒。通过一次全部请求,网络延迟保持恒定的200ms。 (显然,对于更大的请求,将发挥服务器脚本执行和网络传输时间的作用,但是与为每个项目发出单独的HTTP请求相比,性能仍然要好一个数量级。)     ,创建N个闭包,并每次传入\'i \'的值,如下所示:
var i,title;
for (i = 0; i < some_array.length; i++) {
    title = some_array[i];
    $.getJSON(\'some.url/\' + title,(function(i_copy) {
        return function(data) {
            do_something_with_data(data,i_copy);
        };
    })(i));
}
    ,我认为某些浏览器无法同时进行多个异步调用,因此您可以一次进行一次:
var i;
function DoOne(data)
{
    if (i >= 0)
        do_something_with_data(data,i);
    if (++i >= some_array.length)
        return;
    var title = some_array[i];
    $.getJSON(\'some.url/\' + title,DoOne);
}

// to start the chain:
i = -1;
DoOne(null);
    ,我遇到了与OP完全相同的问题,但是以不同的方式解决了它。我用一个jQuery $替换了JavaScript \'for \'循环。每次迭代都调用一个函数,我认为这可以解决回调\'timing \'问题。然后,我将外部数据数组组合到一个JavaScript对象中,这样我既可以引用我在JSON URL上传递的参数,也可以引用该对象同一元素中的其他字段。我的对象元素来自使用PHP的mySQL数据库表。
var persons = [
 { Location: \'MK6\',Bio: \'System administrator\' },{ Location: \'LU4\',Bio: \'Project officer\' },{ Location: \'B37\',Bio: \'Renewable energy hardware installer\' },{ Location: \'S23\',Bio: \'Associate lecturer and first hardware triallist\' },{ Location: \'EH12\',Bio: \'Associate lecturer with a solar PV installation\' }
];

function initMap() {
  var map = new google.maps.Map(document.getElementById(\'map_canvas\'),{
    center: startLatLon,minZoom: 5,maxZoom: 11,zoom: 5
  });
  $.each(persons,function(x,person) {
    $.getJSON(\'http://maps.googleapis.com/maps/api/geocode/json?address=\' + person.Location,null,function (data) {
      var p = data.results[0].geometry.location;
      var latlng = new google.maps.LatLng(p.lat,p.lng);
      var image = \'images/solarenergy.png\';
      var marker = new google.maps.Marker({
        position: latlng,map: map,icon: image,title: person.Bio
      });
      google.maps.event.addListener(marker,\"click\",function (e) {
        document.getElementById(\'info\').value = person.Bio;
      });
    });
  });
}
    

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-