异步请求
一、异步
JavaScript中主要有四种异步的实现方式。
1. 回调函数
使用回调函数的缺点是,多个回调函数嵌套的时候会造成回调函数地狱,代码耦合度高,不利于代码维护。
2. Promise
1)概念:
- Promise对象是一个构造函数,用来生成Promise实例。
- Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。
- Promise对象有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
- Promise对象的状态改变,只有两种可能:从pending变为 fulfilled 和从pending变为 rejected 。要么调用resolve函数来将promise状态改成fulfilled,要么调用reject 函数将promise的状态改为rejected。
2)用法:
// 基本
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
// 链式
promise.then(function(value) {
// success
}, function(error) {
// failure
});
promise.then(result => console.log(result));
promise.catch(error => console.log(error));
3. Generator 函数
1)概念:
Generator 函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态。
执行 Generator 函数会返回一个遍历器对象,可以是一个遍历器对象生成函数。
Generator.prototype.next()
返回一个由 yield表达式生成的值。
Generator.prototype.return()
返回给定的值并结束生成器。
Generator.prototype.throw()
向生成器抛出一个错误。
2)用法:
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
hw.next() // { value: 'hello', done: false }
hw.next() // { value: 'world', done: false }
hw.next() // { value: 'ending', done: true }
hw.next() // { value: undefined, done: true }
for (let v of helloWorldGenerator()) {
console.log(v);
}
// hello,world,ending
4. async 函数
1)概念:
- 本质上是是 Generator 函数的语法糖。
- 将 Generator 函数的星号(*)替换成async,将yield替换成await。
- 改进:拥有更好的语义,返回Promise对象,函数体内用 await 表示后面有需要等待的异步操作,await 还能接原始类型。
2)用法:
// 例一
function sleep(interval) {
return new Promise(resolve => {
setTimeout(resolve, interval);
})
}
async function one2FiveInAsync() {
for(let i = 1; i <= 5; i++) {
console.log(i);
await sleep(1000);
}
}
one2FiveInAsync();
// 例二
async function getTitle(url) {
let response = await fetch(url);
let html = await response.text();
return html.match(/<title>([\s\S]+)<\/title>/i)[1];
}
getTitle('https://tc39.github.io/ecma262/').then(console.log)
// "ECMAScript 2017 Language Specification"
二、请求
AJAX 即”Asynchronous JavaScript and XML”(异步的JavaScript与XML技术),指的是一套综合了多项技术的浏览器端网页开发技术。
1. XMLHttpRequest
xhr.readyState
- 0 - (未初始化),还没有调用send()
- 1 - (载入),已调用send(),正在发送请求
- 2 - (载入完成),send()方法执行完成,已接收到全部的响应内容
- 3 - (交互),正在解析响应内容
- 4 - (完成),响应内容解析完成,可以在客户端调用
xhr.status
- 1xx - 指示信息,表示资源已经请求,继续处理
- 2xx - 表示成功处理请求,如200
- 3xx - 需要重定向,浏览器直接跳转
- 301 - 永久重定向,每次访问A地址的时候,浏览器会自动跳到B地址
- 302 - 临时重新向,仅一次访问A地址时调到B,下次访问还是跳到A
- 304 - 资源未改变,若请求返回的资源与之前的相比没发生改变,服务器会返回304,浏览器会使用自己先前缓存的资源
- 4xx - 客户端请求错误
- 400 - 客户端请求有语法错误,不能被服务器端所理解
- 401 - 请求未经过授权,这个状态码必须和WWW-Authenticate报头域一起使用
- 403 - 服务器收到请求,但是拒绝提供该服务
- 404 - 请求的地址错误
- 5xx - 服务端错误
- 500 - 服务器发生不可预期的错误
- 503 - 服务器当前不能处理客户端的请求,一段时间后可能恢复正常
示例:
// 基本过程
new -> open() -> send(),设置监听函数,等待响应。
// get请求
const xhr = new XMLHttpRequest()
xhr.open('GET', './data/test.json', true)
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// ...
} else {
// ...
}
}
}
xhr.send(null)
// post请求
const xhr = new XMLHttpRequest()
xhr.open('POST', '/login', true)
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// ...
} else {
// ...
}
}
}
const postData = {
name: 'zhangsan',
password: '123'
}
xhr.send(JSON.stringify(postData))
2. Fetch API
一个全局 API ,可用于发送请求,返回 Promise 对象。
注意:当接收到一个代表错误的 HTTP 状态码时,从 fetch() 返回的 Promise 不会被标记为 reject, 即使响应的 HTTP 状态码是 404 或 500。相反,它会将 Promise 状态标记为 resolve (但是会将 resolve 的返回值的 ok 属性设置为 false ),仅当网络故障时或请求被阻止时,才会标记为 reject。
fetch('http://example.com/movies.json',[{options}])
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});
3. Axios
一个基于 promise 的 HTTP 库,可以用在浏览器和 Node.js 中。
$ npm install axios
主要方法:
axios.create([config])
axios.get(url[, config])
axios.post(url[, data[, config]])
import axios from 'axios'
let instance = axios.create({
baseURL: 'https://some-domain.com/api/'
...
});
// 可以直接使用引入的对象发起请求
axios.get('/user?ID=12345')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
// 可以使用实例发起请求
instance.get('/user?ID=12345')
.then(function (response) {
console.log(response);
})
// 其他请求方式同理
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
实际开发中会把函数设置为async,并在请求前加上await。
响应报文:
{
data: {}, // `data` 由服务器提供的响应
status: 200, // `status` 来自服务器响应的 HTTP 状态码
statusText: 'OK', // `statusText` 来自服务器响应的 HTTP 状态信息
headers: {}, // `headers` 服务器响应的头
config: {} // `config` 是为请求提供的配置信息
}
axios.get('/user/12345')
.then(function(response) {
console.log(response.data);
console.log(response.status);
console.log(response.statusText);
console.log(response.headers);
console.log(response.config);
});
三、URI/URL
URI: Uniform Resource Identifier 指的是统一资源标识符
URL: Uniform Resource Location 指的是统一资源定位符
URN: Universal Resource Name 指的是统一资源名称
URI 指的是统一资源标识符,用唯一的标识来确定一个资源,它是一种抽象的定义,不管使用什么方法来定义,只要能唯一的标识一个资源,就可以称为 URI。
URL 指的是统一资源定位符,URN 指的是统一资源名称。URL 和 URN 是 URI 的子集,URL 可以理解为使用地址来标识资源,URN 可以理解为使用名称来标识资源。
// 假设当前url为: https://coding.imooc.com/lesson/115.html&a=100#mid=30378
console.log(location.protocol) // 'https:'
console.log(location.host) // 'coding.imooc.com'
console.log(location.pathname) // '/lesson/115.html'
console.log(location.search) // '?a=100'
console.log(location.hash) // '#mid=30378'
四、参考
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise
https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!