Javascript 事后如何调用回调?

Javascript 事后如何调用回调?,javascript,Javascript,在下面的代码中,我不理解为什么要调用这两个回调函数。callback01是有意义的,因为它在调用加载之前就在回调数组中。callback02另一方面,它在调用load之后才放入数组,但控制台显示它被调用 var callbacks = []; function addCallback(func) { callbacks.push(func); } function load(img_url) { var img = new Image(); img.onload = functi

在下面的代码中,我不理解为什么要调用这两个回调函数。callback01是有意义的,因为它在调用加载之前就在回调数组中。callback02另一方面,它在调用load之后才放入数组,但控制台显示它被调用

var callbacks = [];

function addCallback(func) {
  callbacks.push(func);
}

function load(img_url) {
  var img = new Image();
  img.onload = function() {
    console.log('loaded.');
    callbacks.forEach(function(func) { func(); } )
  };
  img.src = img_url;
}

addCallback(function() { console.log('callback01'); });
load('img/image01.png');
addCallback(function() { console.log('callback02'); });

第二个addCallback行可能在load()完成时已完成。如果您不希望callback02在此时可用,请将其添加到load()函数定义的末尾(如果这是一个选项)。

两个回调都会启动,因为回调会在图像加载后启动。加载映像需要几毫秒的时间,这对于代码加载和添加两个回调来说是足够的时间

这大概就是浏览器执行代码的方式:

// 1 - add first callback
addCallback(function() { console.log('callback01'); });

// 2 - tell JS to begin loading
load('img/image01.png');

// 3 - add second callback
addCallback(function() { console.log('callback02'); });

// 4 - image loads in the background
// 5 - the img.onload function fires and invokes each callback
// 5.a - callback 1 fires
// 5.b - callback 2 fires

在对运行javascript的浏览器的事件循环进行了一些研究之后,似乎发生了以下情况:

由于javascript是在单个线程中执行的,因此当代码执行时,控件不会返回到浏览器以处理事件,直到所有代码都执行完毕

img.onload回调被插入到事件队列中,callback02的addCallBack被执行并将其自身添加到数组中,此时,当调用onload回调时,控制从javascript返回到事件循环,两个回调都可用

var callbacks = [];

function addCallback(func) {
  console.log('addCallback: ' + (new Date()));
  callbacks.push(func);
}

function load(img_url) {
  var img = new Image();
  img.onload = function() {
    console.log('load:  ' + (new Date()));
    callbacks.forEach(function(func) { func(); } )
  };
  img.src = img_url;
}

function badsleep(duration) {
  var now = new Date().getTime();
  while((new Date()).getTime() < (now + duration));
}

addCallback(function() { console.log('callback01: ' + (new Date())); });
load('img/image01.png');
badsleep(2000);
addCallback(function() { console.log('callback02: ' + (new Date())); });

console.log('execution continues: ' + (new Date()));

因此,这似乎是两个回调都在数组中的原因,尽管看起来是在load函数之前和之后添加的。无论如何,我希望是这样,因为这使代码更直观。

图像还没有加载。Javascript异步运行,不像PHP这样序列化的语言。对不起,你回答的那部分完全错了。这不是“完全错”,但无可否认,这是一个过度概括。问题的关键在于,触发顺序可能与OP预期的不同,如果OP预期的是类似php的行为,那么JS将不会提供类似.onload.Well这样的东西。但是Javascript中没有本质上异步的东西,只有代码通常在其中运行的环境才能强制执行异步模式。Javascript本质上是“串行”的,就像PHP一样。同样,如果您愿意,也可以用PHP实现异步。这很公平,感谢您澄清了这个问题。我将删除该行,并对您的评论进行投票。谢谢,所以这是任意的?如果图像加载速度足够快,callback02可能不会被调用?@stewsims,没错。特别是如果它来自浏览器的缓存。正确。如果没有及时添加回调,则不会调用回调。有一些库可以为您处理这种类型的逻辑,比如jQuery的延迟,但是如果我建议您在迁移到那里之前先了解基本知识,谢谢!现在,我将确保在调用load之前将事情设置为应该的状态,并避免意外行为。
addCallback: Sat Jul 05 2014 08:56:05
addCallback: Sat Jul 05 2014 08:56:07
execution continues: Sat Jul 05 2014 08:56:07
load:  Sat Jul 05 2014 08:56:07
callback01: Sat Jul 05 2014 08:56:07
callback02: Sat Jul 05 2014 08:56:07