将参数传递给回调函数与回调的调用者冲突时该怎么办

Posted

技术标签:

【中文标题】将参数传递给回调函数与回调的调用者冲突时该怎么办【英文标题】:What to do when passing a parameter into a callback function conflicts with the callback's caller 【发布时间】:2013-06-13 06:57:43 【问题描述】:

我正在使用 ID3 阅读器脚本从音频文件中检索数据。基本用法是:

ID3.loadTags(file,function()

  var attr = ID3.getAllTags(file).attribute;
);

其中匿名函数是回调函数。这只是为了提供上下文,但是,我完全不确定我遇到的问题是特定于该特定脚本的。

通常,在回调函数中,您可以提取所需的信息,然后使用 DOM 将任何元素的 innerhtml 属性设置为等于您提取的信息。

有时您会提取一堆信息并将所有信息连接在一起形成一个长字符串,而我试图将其划分得更多一些,以便我的调用函数会更简洁一些。我想做的是这样的:

function callingFunction()

  var file = "whatever.mp3";
  var info = getInfo(file);


function calledFunction(file)

  var info = data: 0;

  ID3.loadTags(file, function(passedVar)
  
    var dataobj = ID3.getAllTags(file);
    passedVar.data = dataobj.title+etc+dataobj.album+....(it can get long);
  (info));

  return info;

创建具有属性的对象是因为它是在 JS 中模拟通过引用传递的唯一方法之一——将对象传递给回调函数,将适当的数据分配给对象中的属性,然后在callFunction,将对象返回给callingFunction。

但它不起作用。现在,在上面的代码中,如果我说 passVar.data = "teststring" 而不是从 dataobj 分配数据,那将起作用,因此将对象传递到回调函数是正常工作的。但是,如果从 ID3 函数返回的数据对象中为对象分配数据,则它不起作用。它返回未定义,此外,Chrome 的 JS 调试器说 ID3 函数返回的对象为空。当我这样做时,这一点得到了进一步证实:

function calledFunction(file)

  var info = data: 0;

  ID3.loadTags(file, function(passedVar)
  
    alert(ID3.getAllTags(file).(any attribute));
  (info));

  return info;

并且根本没有出现警报框。但是,如果在上面的代码中删除传递给回调函数的参数,并保持其他所有内容不变,那么警报框就会像预期的那样出现。

所以,总而言之,当我将参数传递给回调函数时,由于某种原因,调用回调函数的对象的另一个函数停止正常工作。

是否有可能将参数传递给回调函数在某种程度上与 ID3.loadTags 函数传递给回调函数的任何内容发生冲突或覆盖,这就是 getAllTags 函数失败的原因?因为由于某种原因,当一个参数被传递给回调函数时,getAllTags 函数不再获取它正常运行所需的所有信息?这是我能想到的唯一解释。

如果是这种情况,有没有办法解决它?如果不是这样,那又是怎么回事?

我想出了一种解决方案,但我觉得它很老套。我基本上创建了从回调函数调用的第三个函数(它本身不接收参数),它将 getAllTags 方法返回的对象作为参数,从该对象中提取数据,并将其分配给其他函数可以的全局变量使用权。所以,这个:

var globalVar;

function calledFunction(file)

  //var info = data: 0;

  ID3.loadTags(file, function()
  
    thirdFunction(ID3.getAllTags(file));
  );

  //return info;


function thirdFunction(dataobj)

  globalVar = dataobj.title+etc;

但我不太喜欢这种解决方案,我觉得它违背了我一开始就追求的划分精神。

我将不胜感激。

【问题讨论】:

【参考方案1】:

这不起作用的原因:

function calledFunction(file)

  var info = data: 0;

  ID3.loadTags(file, function(passedVar)
  
    var dataobj = ID3.getAllTags(file);
    passedVar.data = dataobj.title+etc+dataobj.album+....(it can get long);
    (info));
  // ^^^^^^ --- calls the function immediately

  return info;

...是您调用您的匿名函数并将该调用的结果 (undefined) 传递给ID3.loadTags。您根本不再向其中传递函数。

但根本的问题是您试图在 loadTags 调用其回调并将数据放在对象上之前使用数据对象。

我建议,由于它的输出依赖于异步操作,而不是依赖于函数返回值,你将calledFunction 更改为采用回调函数。它应该是这样的:

function callingFunction() 
  getInfo('whatever.mp3', function(info)  // pass a callback function
    // info.data is here now
  );


function getInfo(file, cb)  // accept a callback function as the 2nd param
  ID3.loadTags(file, function() 
    var tags = ID3.getAllTags(file);
    // once your async operation is done, call cb and pass back the return value
    cb(
      data: tags.title+etc+tags.album+....(it can get long);
    );
  );

这种方法避免了您试图通过使用可以通过引用传递的对象来解决的问题,并且它确保您只有在异步操作 (ID3.getAllTags) 完成后才能继续。

【讨论】:

是的,我真的应该说它是异步的。还没喝我的咖啡! :-) 由于我的回答错过了重点,所以我删除了它并冒昧地将相关部分放入您的。 是的,我曾认为异步可能与它有关,但我也认为,因为有一个回调函数被传递到 ID3 函数中,所以不是这样。如果我更彻底地研究这个角度,本可以为自己节省很多时间。感谢您提供的漂亮、优雅的解决方案。 :)

以上是关于将参数传递给回调函数与回调的调用者冲突时该怎么办的主要内容,如果未能解决你的问题,请参考以下文章

回调函数到底是怎么一回事?

Prettyphoto - 如何将唯一参数传递给回调函数

将额外的参数传递给回调函数

如何将回调作为参数传递给另一个函数

将参数传递给 UIcontrol 回调函数

回调函数和钩子函数