函数调用后异步AJAX调用完成。解决没有观察

时间:2016-06-23 14:39:53

标签: javascript ajax

我需要一个AJAX API调用才能在它包​​含函数之前完成。我查找过的所有解决方案都使用jQuery,我不想仅仅为了进行单个REST调用而添加为依赖...

我一直在阅读以下问题How do I return the response from an asynchronous call?,我仍在努力让它发挥作用。同样,我不想将jQuery添加为依赖项。

现在,如果输入的邮政编码值失败,当用户点击Submit时,如果没有"Mismatch in State and Zip."错误,则会显示其他失败的业务规则。登录到控制台时,我看到已进行REST调用并收到成功的响应,但在异步REST调用完成之前调用alert(error)并附加error的值。

JS

function checkForm(form){
  var state = form.state;
  var zip = form.zip;
  var error = '';
  var flag = 0;

  var ckZip = checkZip(state, zip);
  if (ckZip.flag == 1){
    flag = 1;
  }
  error += ckZip.error;

  // show error and disable form submit if flag == 1
  if (flag == 1){
    alert(error);
    return false;
  }
}

function checkZip(state, zip){
  var state = form.state;
  var zip = form.zip;
  var error = '';
  var flag = 0;

  // check if value entered
  if (zip == ''){
    error += "Please provide a zip/postal code.\r\n";
    flag = 1;
  }

  // business rule: cannot enter - in a ZIP
  if (zip.search(/\x2d/) != -1){
    error += "Please remove dash from zip or postal code.\r\n";
    flag = 1;
  }

  // check if state and zip match
  // IMPORTANT: Fill in your client key
  var clientKey = "this-is-a-valid-key";
  var zipcode = zip.substring(0, 5);
  var url = "https://www.zipcodeapi.com/rest/"+clientKey+"/info.json/" + zipcode + "/radians";
  // Make AJAX request
  var request = new XMLHttpRequest();
  request.open('GET', url, true);

  request.onreadystatechange = function() {
    if (this.readyState === 4) {
      if (this.status >= 200 && this.status < 400) {alert("Got it");
        // Success!
        var data = JSON.parse(this.responseText);alert(data.state);
        if (data.state != state){
          error += "Mismatch in State and Zip.\r\n";
      flag = 1;
        }
      } else {
        // Error :(
        var response = JSON.parse(this.responseText);
        error += "error: " + response.error_msg;
      }
    }
  };

  request.send();
  request = null;

  return {flag: flag, error: error};
}

HTML

<form>
  <select id="state" name="state">
      <option value="" selected=""></option>
      <option value="AA">APO AA</option>                
      <option value="AE">APO AE</option>                
      <option value="AP">APO AP</option>                
      <option value="AL">Alabama</option>               
      <option value="AK">Alaska</option>                
      <option value="AZ">Arizona</option>               
      <option value="AR">Arkansas</option>                
      <option value="CA">California</option>                
      <option value="CO">Colorado</option>                
      <option value="CT">Connecticut</option> 
      <!-- ... -->              
  </select>

  <input type="text" id="zip" name="zip" value="">   
  <input type="Submit" id="Submit" name="Submit" value="Continue" onclick="return checkForm(this.form)">
</form>

2 个答案:

答案 0 :(得分:0)

使函数实际从ajax调用返回信息的唯一方法是使ajax调用同步。我强烈建议您不要这样做。它会在通话期间锁定浏览器标签的UI(至少),从而导致糟糕的用户体验,而且不需要

相反,接受异步调用并学习如何处理函数不能将信息作为返回值返回的事实;请参阅this question and its answers了解如何执行此操作。它真的不像人们有时想的那么困难。 : - )

以下是如何使checkZip异步工作:

首先,将调用从提交按钮移动到表单本身:

<form onsubmit="return checkZip(this)">

现在,让checkZip 总是通过返回false来阻止表单提交,并在ajax完成后让它提交表单:

function checkZip(form) {

    // ...

    request.onreadystatechange = function() {
        // ...
        if (/* it's okay to submit the form*/) {
            form.submit(); // Does NOT call the handler again
        } else {
            // show error to user
        }
    };

    // Stop the initial form submission
    return false;
}

注意:表单不会包含值为Submit的{​​{1}}字段,因为当它真正提交时,该按钮未被按下。如果需要,请从提交按钮中删除Continue,然后包含隐藏字段:

name

但为了完整性,可能使ajax调用同步:open的第三个参数是<input type="hidden" name="Submit" value="Continue"> =异步和{{1}的标志} =同步,所以:

true

但是,我强烈建议您不要这样做。

答案 1 :(得分:-2)

您可以将var request = new XMLHttpRequest(); request.open('GET', url, false); 同步:

alert

虽然其他人已经指出这不推荐。

另一个选择是将你的setTimeout(function() { // show error and disable form submit if flag == 1 if (flag == 1){ alert(error); return false; } }, 1000); 包裹在一个超时时间内,这个超时会延迟执行一段时间,足以让你的请求有时间处理:

$ brew install mysql