导航


HTML

CSS

JavaScript

浏览器 & 网络

版本管理

框架

构建工具

TypeScript

性能优化

软实力

算法

UI、组件库

Node

冷门技能

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    var $ = (function() {
      var o = window.XMLHttpRequest 
                ? new XMLHttpRequest() 
                : new ActiveXObject('Microsoft.XMLHTTP');

      if (!o) {
        throw new Error('您的浏览器不支持异步发起HTTP请求');
      }

      function _doAjax(opt) {
        var opt = opt || {},
            type = (opt.type || 'GET').toUpperCase(),
            async = opt.async || true,
            url = opt.url,
            data = opt.data || null,
            error = opt.error || function() {},
            success = opt.success || function() {},
            complete = opt.complete || function() {};

        if (!url) {
          throw new Error("您没有填写URL");
        }

        o.open(type, url, async);
        type === 'POST' && o.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        o.send(type === 'GET' ? null : formatData(data));
        o.onreadystatechange = function() {
          if (o.readyState === 4 && o.status === 200) {
            success(JSON.parse(o.responseText));
          }
          if (o.status === 404) {
            error();
          }
          complete();
        }
      }

      function formatData(obj) {
        var str = '';

        for (var key in obj) {
          str += key + '=' + obj[key] + '&';
        }

        return str.replace(/&$/, '');
      }

      return {
        ajax: function(opt) {
          _doAjax(opt);
        },
        get: function(url, callback) {
          _doAjax({
            type: 'GET',
            url,
            success: callback
          })
        },
        post: function(url, data, callback) {
          _doAjax({
            type: 'POST',
            url,
            data,
            success: callback
          });
        }
      }
    })();

    $.ajax({
      url: '<https://api.publicapis.org/entries>',
      success: function(data) {
        console.log(data);
      }
    });

    $.post('<https://jsonplaceholder.typicode.com/posts>', { name: 'nathaniel' }, function(data) {
      console.log(data);
    });

    $.get('<https://api.nationalize.io/?name=nathaniel>', function(data) {
      console.log(data);
    });
  </script>
</body>
</html>

AJAX 版本

Untitled

Untitled

⭐️ 状态码与状态提示

Untitled

再次封装 AJAX

核心修改

o.onreadystatechange = function() {
  if (o.readyState === 4) {
    if ((o.status >= 200 && o.status < 300) || o.status === 304) {
      success(JSON.parse(o.responseText));
    }
  }
  if (o.status === 404) {
    error();
  }
  complete();
}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    var $ = (function() {
      var o = window.XMLHttpRequest 
                ? new XMLHttpRequest() 
                : new ActiveXObject('Microsoft.XMLHTTP');

      if (!o) {
        throw new Error('您的浏览器不支持异步发起HTTP请求');
      }

      function _doAjax(opt) {
        var opt = opt || {},
            type = (opt.type || 'GET').toUpperCase(),
            async = opt.async || true,
            url = opt.url,
            data = opt.data || null,
            error = opt.error || function() {},
            success = opt.success || function() {},
            complete = opt.complete || function() {};

        if (!url) {
          throw new Error("您没有填写URL");
        }

        o.open(type, url, async);
        type === 'POST' && o.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        o.send(type === 'GET' ? null : formatData(data));
        o.onreadystatechange = function() {
          if (o.readyState === 4) {
            if ((o.status >= 200 && o.status < 300) || o.status === 304) {
            	success(JSON.parse(o.responseText));
            }
          }
          if (o.status === 404) {
            error();
          }
          complete();
        }
      }

      function formatData(obj) {
        var str = '';

        for (var key in obj) {
          str += key + '=' + obj[key] + '&';
        }

        return str.replace(/&$/, '');
      }

      return {
        ajax: function(opt) {
          _doAjax(opt);
        },
        get: function(url, callback) {
          _doAjax({
            type: 'GET',
            url,
            success: callback
          })
        },
        post: function(url, data, callback) {
          _doAjax({
            type: 'POST',
            url,
            data,
            success: callback
          });
        }
      }
    })();

    $.ajax({
      url: '<https://api.publicapis.org/entries>',
      success: function(data) {
        console.log(data);
      }
    });

    $.post('<https://jsonplaceholder.typicode.com/posts>', { name: 'nathaniel' }, function(data) {
      console.log(data);
    });

    $.get('<https://api.nationalize.io/?name=nathaniel>', function(data) {
      console.log(data);
    });
  </script>
</body>
</html>

⭐️ 五个事件

Untitled

⭐️ 请求超时

Untitled

var xhr,
   	t;

if (window.XMLHttpRequest) {
	xhr = new XMLHttpRequest();
} else {
	xhr = new ActiveXObject('Microsoft.XMLHTTP');
}

xhr.open('GET', '<https://api.publicapis.org/entries>', false);

xhr.send(null);

xhr.onreadystatechange = function() {
	if (xhr.readyState === 4) {
  	if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
      clearTimeout(t);
      t = null;
    	console.log(JSON.parse(xhr.responseText)); 
    }
  }
}

t = setTimeout(function() {
	xhr.abort();
  clearTimeout(t);
  t = null;
  xhr = null;
}, 30000);

再再次封装 AJAX

核心封装

var t = null;

o.onreadystatechange = function() {
  if (o.readyState === 4) {
    if ((o.status >= 200 && o.status < 300) || o.status === 304) {
      success(JSON.parse(o.responseText));
    } else {
    	error();
    }
    
    complete();
    clearTimeout(t);
    t = null;
    o = null;
  }
  // if (o.status === 404) {
  //   error();
  // }
  // complete();
}

t = setTimeout(function() {
	o.onabort();
  clearTimeout(t);
  t = null;
  o = null;
}, 30000);
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    var $ = (function() {
      var o = window.XMLHttpRequest 
                ? new XMLHttpRequest() 
                : new ActiveXObject('Microsoft.XMLHTTP');
     

      if (!o) {
        throw new Error('您的浏览器不支持异步发起HTTP请求');
      }

      function _doAjax(opt) {
        var opt = opt || {},
            type = (opt.type || 'GET').toUpperCase(),
            async = opt.async || true,
            url = opt.url,
            data = opt.data || null,
            timeout = opt.timeout || 30000,
            error = opt.error || function() {},
            success = opt.success || function() {},
            complete = opt.complete || function() {},
         		t = null;

        if (!url) {
          throw new Error("您没有填写URL");
        }

        o.open(type, url, async);
        type === 'POST' && o.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        o.send(type === 'GET' ? null : formatData(data));
        
        t = setTimeout(function() {
        	o.abort();
          clearTimeout(t);
          t = null;
          o = null;
          complete();
        }, timeout);
        
        o.onreadystatechange = function() {
          if (o.readyState === 4) {
            if ((o.status >= 200 && o.status < 300) || o.status === 304) {
            	success(JSON.parse(o.responseText));
            } else {
            	error();
            }
            
            complete();
            clearTimeout(t);
            t = null;
            o = null;
          }
        }
      }

      function formatData(obj) {
        var str = '';

        for (var key in obj) {
          str += key + '=' + obj[key] + '&';
        }

        return str.replace(/&$/, '');
      }

      return {
        ajax: function(opt) {
          _doAjax(opt);
        },
        get: function(url, callback) {
          _doAjax({
            type: 'GET',
            url,
            success: callback
          })
        },
        post: function(url, data, callback) {
          _doAjax({
            type: 'POST',
            url,
            data,
            success: callback
          });
        }
      }
    })();

    $.ajax({
      url: '<https://api.publicapis.org/entries>',
      success: function(data) {
        console.log(data);
      }
    });

    $.post('<https://jsonplaceholder.typicode.com/posts>', { name: 'nathaniel' }, function(data) {
      console.log(data);
    });

    $.get('<https://api.nationalize.io/?name=nathaniel>', function(data) {
      console.log(data);
    });
  </script>
</body>
</html>

⭐️ 异步同步

Untitled

异步的时候

Untitled

同步的时候

Untitled

再再再次改造 AJAX 封装

核心修改

var opt = opt || {},
    type = (opt.type || 'GET').toUpperCase(),
    async = "" + opt.async === 'false' ? false : true,
    ...;
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    var $ = (function() {
      var o = window.XMLHttpRequest 
                ? new XMLHttpRequest() 
                : new ActiveXObject('Microsoft.XMLHTTP');
      
      var t = null;

      if (!o) {
        throw new Error('您的浏览器不支持异步发起HTTP请求');
      }

      function _doAjax(opt) {
        var opt = opt || {},
            type = (opt.type || 'GET').toUpperCase(),
            async = "" + opt.async === 'false' ? false : true,
            url = opt.url,
            data = opt.data || null,
            timeout = opt.timeout || 30000,
            error = opt.error || function() {},
            success = opt.success || function() {},
            complete = opt.complete || function() {};

        if (!url) {
          throw new Error("您没有填写URL");
        }

        o.open(type, url, async);
        type === 'POST' && o.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        o.send(type === 'GET' ? null : formatData(data));
        
        t = setTimeout(function() {
        	o.abort();
          clearTimeout(t);
          t = null;
          o = null;
          complete();
        }, timeout);
        
        o.onreadystatechange = function() {
          if (o.readyState === 4) {
            if ((o.status >= 200 && o.status < 300) || o.status === 304) {
            	success(JSON.parse(o.responseText));
            } else {
            	error();
            }
            
            complete();
            clearTimeout(t);
            t = null;
            o = null;
          }
        }
      }

      function formatData(obj) {
        var str = '';

        for (var key in obj) {
          str += key + '=' + obj[key] + '&';
        }

        return str.replace(/&$/, '');
      }

      return {
        ajax: function(opt) {
          _doAjax(opt);
        },
        get: function(url, callback) {
          _doAjax({
            type: 'GET',
            url,
            success: callback
          })
        },
        post: function(url, data, callback) {
          _doAjax({
            type: 'POST',
            url,
            data,
            success: callback
          });
        }
      }
    })();

    $.ajax({
      url: '<https://api.publicapis.org/entries>',
      success: function(data) {
        console.log(data);
      }
    });

    $.post('<https://jsonplaceholder.typicode.com/posts>', { name: 'nathaniel' }, function(data) {
      console.log(data);
    });

    $.get('<https://api.nationalize.io/?name=nathaniel>', function(data) {
      console.log(data);
    });
  </script>
</body>
</html>

⭐️ dateType

Untitled

再再再再次改造 AJAX 封装

核心修改

var opt = opt || {},
    type = (opt.type || 'GET').toUpperCase(),
    async = "" + opt.async === 'false' ? false : true,
    dataType = opt.dataType || 'JSON',
    url = opt.url,
    data = opt.data || null,
    timeout = opt.timeout || 30000,
    error = opt.error || function() {},
    success = opt.success || function() {},
    complete = opt.complete || function() {};

o.onreadystatechange = function() {
  if (o.readyState === 4) {
    if ((o.status >= 200 && o.status < 300) || o.status === 304) {
      switch(dataType.toUpperCase()) {
        case 'JSON':
          success(JSON.parse(o.responseText));
          break;
        case 'TEXT':
          success(o.responseText);
         	break;
        case 'XML':
          success(o.responseXML);
          break;
        default:
          success(JSON.parse(o.responseText));
      }
    } else {
      error();
    }

    complete();
    clearTimeout(t);
    t = null;
    o = null;
  }
}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    var $ = (function() {
      var o = window.XMLHttpRequest 
                ? new XMLHttpRequest() 
                : new ActiveXObject('Microsoft.XMLHTTP');
      
      var t = null;

      if (!o) {
        throw new Error('您的浏览器不支持异步发起HTTP请求');
      }

      function _doAjax(opt) {
        var opt = opt || {},
            type = (opt.type || 'GET').toUpperCase(),
            async = "" + opt.async === 'false' ? false : true,
            dataType = opt.dataType || 'JSON',
            url = opt.url,
            data = opt.data || null,
            timeout = opt.timeout || 30000,
            error = opt.error || function() {},
            success = opt.success || function() {},
            complete = opt.complete || function() {};

        if (!url) {
          throw new Error("您没有填写URL");
        }

        o.open(type, url, async);
        type === 'POST' && o.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        o.send(type === 'GET' ? null : formatData(data));
        
        t = setTimeout(function() {
        	o.abort();
          clearTimeout(t);
          t = null;
          o = null;
          complete();
        }, timeout);
        
        o.onreadystatechange = function() {
          if (o.readyState === 4) {
            if ((o.status >= 200 && o.status < 300) || o.status === 304) {
            	switch(dataType.toUpperCase()) {
                case 'JSON':
                  success(JSON.parse(o.responseText));
                  break;
                case 'TEXT':
                  success(o.responseText);
                  break;
                case 'XML':
                  success(o.responseXML);
                  break;
                default:
                  success(JSON.parse(o.responseText));
              }
            } else {
            	error();
            }
            
            complete();
            clearTimeout(t);
            t = null;
            o = null;
          }
        }
      }

      function formatData(obj) {
        var str = '';

        for (var key in obj) {
          str += key + '=' + obj[key] + '&';
        }

        return str.replace(/&$/, '');
      }

      return {
        ajax: function(opt) {
          _doAjax(opt);
        },
        get: function(url, callback) {
          _doAjax({
            type: 'GET',
            url,
            success: callback
          })
        },
        post: function(url, data, callback) {
          _doAjax({
            type: 'POST',
            url,
            data,
            success: callback
          });
        }
      }
    })();

    $.ajax({
      url: '<https://api.publicapis.org/entries>',
      success: function(data) {
        console.log(data);
      }
    });

    $.post('<https://jsonplaceholder.typicode.com/posts>', { name: 'nathaniel' }, function(data) {
      console.log(data);
    });

    $.get('<https://api.nationalize.io/?name=nathaniel>', function(data) {
      console.log(data);
    });
  </script>
</body>
</html>

最终修改

核心修改

// 覆盖问题原因:因为闭包问题,xhr对象使用的是同一个
// 解决办法:把 xhr 移到 _doAjax 中

function _doAjax(opt) {
  var o = window.XMLHttpRequest 
  ? new XMLHttpRequest() 
  : new ActiveXObject('Microsoft.XMLHTTP');

  if (!o) {
    throw new Error('您的浏览器不支持异步发起HTTP请求');
  }
  ...
}
  
// 超时报错停止请求:
// 超时中断请求,报错提醒
t = setTimeout(function() {
  o.abort();
  clearTimeout(t);
  t = null;
  o = null;
  throw new Error("This request has been timeout for" + url);
}, timeout);
  
// $.post/$.get 成功失败和完成
get: function(url, successCB, errorCB, completeCB) {
  _doAjax({
    type: 'GET',
    url,
    success: successCB,
    error: errorCB,
    complete: completeCB
  })
},
  post: function(url, data, successCB, errorCB) {
    _doAjax({
      type: 'POST',
      url,
      data,
      success: successCB,
      error: errorCB,
      complete: completeCB
    });
  }