在Deferred对象中使用$.grep报错:Cannot read property 'value' of undefined
问题分析与解决方案
嘿,这个问题我太熟了——你这明显是异步操作的时序坑在搞鬼!虽然console.log看起来能输出正确值,但那只是浏览器控制台的小把戏(当你展开对象时才会读取最新状态),实际代码执行时,你用来过滤的JSON变量还没被异步请求赋值,所以才会报错。
核心问题拆解
你当前的代码逻辑大概是这样的(简化版):
let targetDateData; // 第一步:获取大量原始数据 $.get('/your-large-data-url', function(rawResponse) { // 第二步:用Deferred异步加载目标JSON文件 const deferred = $.get('/your-date-json-url'); deferred.done(function(data) { targetDateData = data; // 这里是异步赋值,不会立刻完成 }); // 第三步:直接遍历原始数据并过滤,但此时targetDateData可能还是undefined! rawResponse.forEach(item => { const result = $.grep(targetDateData, obj => obj.date === item.date); console.log(result); // 控制台延迟显示,让你误以为值是对的 }); });
问题就出在第二步的异步赋值还没完成,第三步的过滤逻辑就已经跑起来了,这时候targetDateData要么是undefined,要么还没拿到完整数据,自然会报错。
两种靠谱的解决办法
办法1:把过滤逻辑放进Deferred的回调里
确保等目标JSON数据完全加载完成后,再执行遍历和过滤:
$.get('/your-large-data-url', function(rawResponse) { // 先等目标JSON加载完成 $.get('/your-date-json-url') .done(function(targetDateData) { // 现在数据肯定准备好了,放心过滤 rawResponse.forEach(item => { const filteredResult = $.grep(targetDateData, obj => obj.date === item.date); console.log(filteredResult); // 这里绝对不会报错 }); }) .fail(function() { // 别忘了处理JSON加载失败的情况 console.error('加载日期JSON文件失败了!'); }); });
办法2:用Promise.all统一等待所有异步请求
如果你的jQuery版本在1.8以上(支持Promise),用链式调用会更优雅,还能同时处理多个异步请求:
// 同时发起两个异步请求,等它们都完成再继续 Promise.all([ $.get('/your-large-data-url'), $.get('/your-date-json-url') ]) .then(function([rawResponse, targetDateData]) { // 两个请求都成功返回了,开始过滤 rawResponse.forEach(item => { const filteredResult = $.grep(targetDateData, obj => obj.date === item.date); console.log(filteredResult); }); }) .catch(function(error) { // 任何一个请求失败都会走到这里 console.error('请求出错了:', error); });
额外提醒
- 先看报错信息:如果是
Cannot read property 'date' of undefined这类,那百分百是时序问题,不用怀疑。 - 别用全局变量存异步数据:尽量通过回调参数或者Promise返回值传递数据,减少时序混乱的概率。
- 加调试日志:可以在
targetDateData赋值后加console.log('数据加载完成:', targetDateData),确认数据真的准备好了再执行后续逻辑。
内容的提问来源于stack exchange,提问作者Peter Griffin
相关产品推荐
相关产品推荐

