>웹 프론트엔드 >JS 튜토리얼 >기본 JS에서 Ajax를 비동기식으로 구현하는 방법은 무엇입니까?

기본 JS에서 Ajax를 비동기식으로 구현하는 방법은 무엇입니까?

php中世界最好的语言
php中世界最好的语言원래의
2018-04-14 14:21:501888검색

이번에는 네이티브 JS에서 Ajax 비동기를 구현하는 몇 가지 방법과 네이티브 JS에서 Ajax 비동기를 구현하는 노트를 소개하겠습니다.

프런트 엔드 페이지 개발 과정에서 Ajax 요청이 자주 사용되며 비동기적으로 양식 데이터를 제출하거나 페이지를 비동기적으로 새로 고칩니다.

일반적으로 Jquery에서는 $.ajax, $.post, $.getJSON을 사용하면 매우 편리하지만 때로는 ajax 기능만 필요한 경우도 있으므로 Jquery를 도입하는 것은 비용 효율적이지 않습니다.

다음으로, 기본 JavaScrpit을 사용하여 간단한 Ajax 요청을 구현하고, Ajax 요청의 도메인 간 액세스 문제와 여러 Ajax 요청의 데이터 동기화 문제를 설명하겠습니다.

JavaScript는 Ajax 비동기 요청을 구현합니다

간단한 ajax 요청 구현
Ajax 요청의 원칙은 XMLHttpRequest 객체를 생성하고 이 객체를 사용하여 비동기적으로 요청을 보내는 것입니다. 구체적인 구현은 다음 코드를 참조하세요.

function ajax(option) {
  // 创建一个 XMLHttpRequest 对象
  var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"),
    requestData = option.data,
    requestUrl = option.url,
    requestMethod = option.method;
  // 如果是GET请求,需要将option中的参数拼接到URL后面
  if ('POST' != requestMethod && requestData) {
    var query_string = '';
    // 遍历option.data对象,构建GET查询参数
    for(var item in requestData) {
      query_string += item + '=' + requestData[item] + '&';
    }
    // 注意这儿拼接的时候,需要判断是否已经有 ?
    requestUrl.indexOf('?') > -1
      ? requestUrl = requestUrl + '&' + query_string
      : requestUrl = requestUrl + '?' + query_string;
    // GET 请求参数放在URL中,将requestData置为空
    requestData = null;
  }
  // ajax 请求成功之后的回调函数
  xhr.onreadystatechange = function () {
    // readyState=4表示接受响应完毕
    if (xhr.readyState == ("number" == typeof XMLHttpRequest.DONE ? XMLHttpRequest.DONE : 4)) {
      if (200 == xhr.status) { // 判断状态码
        var response = xhr.response || xhr.responseText || {}; // 获取返回值
        // if define success callback, call it, if response is string, convert it to json objcet
        console.log(response);
        option.success && option.success(response); // 调用回调函数处理返回数据
        // 可以判断返回数据类型,对数据进行JSON解析或者XML解析
        // option.success && option.success('string' == typeof response ? JSON.parse(response) : response);
      } else {
        // if define error callback, call it
        option.error && option.error(xhr, xhr.statusText);
      }
    }
  };
  // 发送ajax请求
  xhr.open(requestMethod, requestUrl, true);
  // 请求超时的回调
  xhr.ontimeout = function () {
    option.timeout && option.timeout(xhr, xhr.statusText);
  };
  // 定义超时时间
  xhr.timeout = option.timeout || 0;
  // 设置响应头部,这儿默认设置为json格式,可以定义为其他格式,修改头部即可
  xhr.setRequestHeader && xhr.setRequestHeader('Content-Type', 'application/json;charset=utf-8');
  xhr.withCredentials = (option.xhrFields || {}).withCredentials;
  // 这儿主要用于发送POST请求的数据
  xhr.send(requestData);
}

위 코드에는 자세한 설명이 있습니다. ajax의 원리는 일반적으로 XMLHttpRequest 객체를 사용하여 데이터를 보냅니다. 다음은 이 개체에 대한 보충 설명입니다.

XMLHttpRequest 객체의 기본 속성

ReadyState 속성에는 5개의 상태 값이 있습니다:

0: 초기화되지 않음: 초기화되지 않았습니다. XMLHttpRequest 객체가 생성되었지만 초기화되지 않았습니다.
1: 로딩 중: 전송할 준비가 되었습니다.
2: 로드되었습니다.: 전송했지만 아직 응답을 받지 못했습니다.
3: 대화형입니다. 응답이 수신되고 있지만 아직 수신되지 않았습니다.
4: 예 완료됨: 응답이 수락되었습니다.
responseText: 서버가 반환한 응답 텍스트입니다. ReadyState>=3인 경우에만 값을 갖습니다. ReadyState=3인 경우 반환된 응답 텍스트가 불완전합니다. ReadyState=4인 경우에만 전체 응답 텍스트가 수신됩니다.

responseXML: 응답 정보는 xml이며 Dom 객체로 구문 분석될 수 있습니다.

상태: 서버의 Http 상태 코드 200이면 OK, 404는 찾을 수 없음을 의미합니다.

statusText: 서버 http 상태 코드의 텍스트입니다. 예를 들어 확인, 찾을 수 없음입니다.

XMLHttpRequest 객체의 기본 메서드

open(method, url, asyn): XMLHttpRequest 객체를 엽니다. 메소드에는 get, post, delete 및 put이 포함됩니다. url은 요청된 리소스의 주소입니다. 세 번째 매개변수는 비동기식 사용 여부를 나타냅니다. Ajax의 특성은 비동기 전송이기 때문에 기본값은 true입니다. 동기화가 사용되는 경우 거짓입니다.

send(body): 요청 Ajax를 보냅니다. 전송되는 내용은 필수 매개변수일 수 있습니다. 매개변수가 없으면 (null)을 직접 전송하세요

사용방법

위에 정의된 ajax 함수를 호출하고 해당 옵션과 매개변수를 전달하면 됩니다.

rreee

교차 도메인 요청 문제

Ajax 요청을 사용할 때 한 가지 문제, 즉 도메인 간 요청에 주의해야 합니다.

특별한 수단을 사용하지 않고 크로스 도메인 요청: 다른 도메인 이름 및 포트에서 URL 리소스를 요청할 때 Access-Control-Allow-Origin 관련 오류가 보고됩니다. 주된 이유는 크로스 도메인 리소스 요청이 이루어질 수 없도록 규정하는 브라우저의 동일 출처 정책 제한 때문입니다.

솔루션

다음은 간략하게 언급된 몇 가지 솔루션입니다.

ajax 헤더에 도메인 간 요청을 허용하는 헤더를 추가하려면 서버가 도메인 간 요청을 허용하는 헤더 추가에 협조해야 합니다. 다음은 POST 요청에 Allow cross-domain 헤더를 추가하는 PHP 예제입니다.

ajax({
  url: '/post.php',
  data: {
    name: 'uusama',
    desc: 'smart'
  },
  method: 'GET',
  success: function(ret) {
    console.log(ret);
  }
});

동적 scrpit 태그를 사용하여 scrpit 태그를 동적으로 생성하고 요청한 주소를 가리키는 방식, 즉 JSONP 방식은 태그가 성공적으로 로드된 후 콜백 함수를 호출해야 합니다.

rreee

콜백 함수는 global function:

으로 설정되어야 합니다. window['jsonpCallback'] = function jsonpCallback(ret) {}

다중 Ajax 요청 데이터 동기화 문제

단일 ajax 반환 데이터는 비동기적으로 처리됩니다.
여러 ajax 요청은 서로 관련이 없습니다. 요청이 성공한 후에는 서로 영향을 주지 않고 자체 콜백 메서드를 호출합니다.

因为ajax请求异步的特性,所有一些依赖于请求完成之后的操作我们都需要放在回调函数内部,否则的话,你在回调函数外面读取到的值是空。看下面的例子:

var result = null;
ajax({
  url: '/get.php?id=1',
  method: 'GET',
  success: function(ret) {
    result = ret;
  }
});
console.log(result); // 输出 null

虽然我们在回调函数里面设置了result的值,但是在最后一行 console.log(result); 输出为空。

因为ajax请求是异步的,程序执行到最后一行的时候,请求并没有完成,值并没有来得及修改。

这儿我们应该把 console.log(result) 相关的处理,放在 success 回调函数中才可以。

多个ajax返回数据问题

如果有多个ajax请求,情况会变得有些复杂。

如果多个ajax请求是按照顺序执行的,其中一个完成之后,才能进行下一个,则可以把后面一个请求放在前一后请求的回调中。

比如有两个ajax请求,其中一个请求的数据依赖于另外一个,则可以在第一个请求的回调里面再进行ajax请求:

// 首先请求第一个ajax
ajax({
  url: '/get1.php?id=1',
  success: function(ret1) {
    // 第一个请求成功回调以后,再请求第二个
    if (ret1) {
      ajax({
        url: '/get2.php?id=4',
        success:function(ret2) {
          console.log(ret1);
          console.log(ret2)
        }
      })
    }
  }
});
// 也可以写成下面的形式
// 将第二个ajax请求定义为一个函数,然后调用
var ajax2 = function(ret1) {
  ajax({
    url: '/get2.php?id=4',
    success:function(ret2) {
      console.log(ret1);
      console.log(ret2)
    }
  });
};
ajax({
  url: '/get1.php?id=1',
  success: function(ret1) {
    if(ret1){
      ajax2(ret1); // 调用第二个ajax请求
    }
  }
});

如果不关心不同的ajax请求的顺序,而只是关心所有请求都完成,才能进行下一步。

一种方法是可以在每个请求完成以后都调用同一个回调函数,只有次数减少到0才执行下一步。

var count = 3, all_ret = []; // 调用3次
ajax({
  url: '/get1.php?id=1',
  success:function(ret) {
    callback(ret); // 请求成功后调用统一回调,次数减1
  }
});
ajax({
  url: '/get2.php?id=1',
  success:function(ret) {
    callback(ret);
  }
});
ajax({
  url: '/get3.php?id=1',
  success:function(ret) {
    callback(ret);
  }
});
function callback(ret) {
  // 当调用3次以上以后,说明3个ajax军完成
  if (count > 0) {
    count--; // 每调用一次,次数减1
    // 可以在这儿保存 ret 到全局变量
    all_ret.push(ret);
    return;
  } else { // 调用三次以后
    // todo
    console.log(ret);
  }
}

另一种方法是设置一个定时任务去轮训是否所有ajax请求都完成,需要在每个ajax的成功回调中去设置一个标志。

这儿可以用是否获得值来判断,也可以设置标签来判断,用值来判断时,要注意设置的值和初始相同的情况。

var all_ret = {
  ret1: null, // 第一个ajax标识
  ret2: null, // 第二个ajax标识
  ret3: null, // 第三个ajax标识
};
ajax({
  url: '/get1.php?id=1',
  success:function(ret) {
    all_ret['ret1'] = ret; // 修改第一个ajax请求标识
  }
});
ajax({
  url: '/get2.php?id=1',
  success:function(ret) {
    all_ret['ret2'] = ret; // 修改第二个ajax请求标识
  }
});
ajax({
  url: '/get3.php?id=1',
  success:function(ret) {
    all_ret['ret3'] = ret; // 修改第三个ajax请求标识
  }
});
var repeat = setInterval(function(){
  // 遍历是否所有ajax请求标识都已被修改,以此判断是否所有ajax请求都已完成
  for(var item in all_ret) {
    if (all_ret[item] === null){
      return;
    }
  }
  // todo, 到这儿所有ajax请求均已完成
  clearInterval(repeat);
}, 50); // 调用次数可以适当调整,不应设的过小或者过大

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

datatable怎样实现异步加载

在IE11下里使用canvas.toDataURL兼容性问题的解决思路

위 내용은 기본 JS에서 Ajax를 비동기식으로 구현하는 방법은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.