异步JavaScript函数完成后调用函数?

时间:2012-05-19 01:48:17

标签: javascript callback

我是JavaScript的新手,我四处寻找解决问题的方法。我真的很难找到正确的答案。我想我可能不得不做一些回调,但我不确定。

基本上,我正在我的网站上实施“喜欢”按钮。在点击“喜欢”按钮时,我需要发生两个主要的后端事件:应该更新“喜欢”的数据库,并且应该向获得“喜欢”的人发送电子邮件通知。点击“喜欢”按钮后,我会渲染一个“喜欢”按钮,向用户显示它经历过。

问题是,拍摄电子邮件需要很长时间。因此,如果我更新数据库然后发送电子邮件并且然后呈现按钮,则用户将在他/她看到按钮变为“喜欢”按钮之前等待一下。所以相反,我想更新数据库,渲染类似按钮,然后拍摄电子邮件。

在我的JavaScript中,我尝试了以下操作:

function foo()
{
  xmlhttp1.onreadystatechange = liked( function() {
    xmlhttp2.open("POST", "async/async_likeEmail.php",true)
    xmlhttp2.setRequestHeader(...
    ...
    xmlhttp2.send(parameters);
  }

  xmlhttp1.open("POST", "async/async_likeUpdateDB.php", true)
  xmlhttp1.setRequestHeader(...
  ...
  xmlhttp1.send(parameters);
}

function liked(callback) {
  if (xmlhttp1.readyState == 4)
  {
    xmlhttp1.responseText;
    someElement.innerHTML = xmlhttp1.responseText; // render the "liked" button
    callback();
  }
}

这样做,异步“喜欢”功能无法被调用。出于某种原因,传入回调会破坏它。我也尝试不传入回调,而是定义一个单独的“like_notify”函数,并在异步“likes”函数内调用like_notify()也失败了。

有人能让我知道我做错了什么以及为什么这些尝试都失败了?回调不是这个问题的解决方案吗?

2 个答案:

答案 0 :(得分:2)

不是等待服务器的响应获得更新用户界面的权限,而是一种流行的技术是简单地假设可以继续并更新UI。在大多数情况下,请求通常是成功的,因此只需进行该假设,然后向服务器发出请求。

之后,当响应返回时,检查请求是否确实成功,而不是更新UI。如果是的话,太棒了!您可以做任何事情,因为您已经更新了UI,或者您可以检查以确保您的快速更新与服务器发送的内容相匹配。它应该,但如果没有,你可以解决它。

此外,您还可以检查响应中的状态代码。如果它是500,404或任何非200状态代码,表明存在异常情况,则可以通过将类似按钮恢复到之前的状态然后向用户显示一条漂亮的错误消息来对其进行操作。

这不仅会让你的用户界面变得非常活泼,而且你仍然能够在错误发生时处理它们。

这是您的代码,稍作修改以方便此技术。由于我没有您的所有代码,因此不应将其视为一个有效的示例,只是为了让您入门:

function foo()
{ 
   // call liked immediately. Don't wait for the server to respond
      // think "update the UI immediately"
   liked( function() {
       xmlhttp2.open("POST", "async/async_likeEmail.php",true)
       xmlhttp2.setRequestHeader(...
       ...
       xmlhttp2.send(parameters);
   });

  // this is a handler where you just check to make sure the request succeeded
    // if it does, great, do nothing. If it fails, change the like button back!
  xmlhttp1.onreadystatechange = function() {
      if(xmlhttp1.status == 404 || xmlhttp1.status == 503) {
          alert("problem!");
          // put the like button back to the previous state
      }
  };

  xmlhttp1.open("POST", "async/async_likeUpdateDB.php", true)
  xmlhttp1.setRequestHeader(...
  ...
  xmlhttp1.send(parameters);
}

function liked(callback) {

  /* insert code to render the liked result
   *  show what the button would look like if successful.
   */

  // you don't really need to do this part. You know what a liked button looks like
   // so just render it without waiting for the response.
    // however, leaving this here acts as a failsafe in case your  
     // code that updates it immediately does something wrong
  if (xmlhttp1.readyState == 4)
  {
    xmlhttp1.responseText;
    someElement.innerHTML = xmlhttp1.responseText; // render the "liked" button

    // call the callback to make the 2nd Ajax request
    callback();
  }
}

<强>更新

你的第一个AJAX调用未正确触发的原因是因为你将onh函数的“em”结果分配给onreadystatechange处理程序,而不是将实际的函数对象分配给onreadystatechange处理程序: / p>

xmlhttp1.onreadystatechange = liked( function() {
    xmlhttp2.open("POST", "async/async_likeEmail.php",true)
    xmlhttp2.setRequestHeader(...
    ...
    xmlhttp2.send(parameters);
}

相反,这会有效:

xmlhttp1.onreadystatechange = function() { 
    liked( function() {
        xmlhttp2.open("POST", "async/async_likeEmail.php",true)
        xmlhttp2.setRequestHeader(...
        ...
        xmlhttp2.send(parameters);
    }
}

为了更清楚,请考虑以下事项:

xmlhttp1.onreadystatechange = someFunct();   // assign the result to the handler

xmlhttp1.onreadystatechange = someFunct;    // assign the function to the handler

// also assigns function to handler, but wrapped in anonymous function
xmlhttp1.onreadystatechange = function() {   
    someFunct();
}

答案 1 :(得分:2)

//abstract the ajax 
function ajaxpost(url,callback){

    //all the xhr setup stuff

    xmlhttp.open("POST", url, true)
    xmlhttp.onreadystatechange = function(){
        if (xmlhttp1.readyState == 4){

            //execute callback when done
            callback(xmlhttp.responseText);
        }
    }
    xmlhttp.send();
}

function like(){
    //update db
    ajaxpost("async/async_likeUpdateDB.php",function(data){
        //render like button
        someElement.innerHTML = xmlhttp1.responseText
        //email
        email();
    }
}

function email(){
    //hit email
    ajaxpost("async/async_likeEmail.php",function(data){
        //everything done
    }
}