一、axios
1.1 axios是什么
axios是基于promise封装的ajax库,用于客户端发送ajax请求;
1.2 安装axios库
npm install axios --save 或者 yarn add axios --save
1.3 axios常用的方法:
1.3.1 get请求
- axios.get(url, config)
- 返回promise对象
axios.get('/api/get_aside', {
params: {
aside_id: 1
}
}).then(({data}) => bindHTML(data));
1.3.2 post请求
- axios.post(url, data)
- 返回promise对象,可以使用.then,then回调的形参res:
- res 是一个经过axios封装过的对象,其中包含了http的响应状态,响应状态码等信息;
- 对象中的data属性值才是我们请求来的数据
- console.log(res);
- console.log(res.data);
axios.post('/api/get_aside', {aside_id: 1, name: 'xyz'}).then(function (res) {
// res 是一个经过axios封装过的对象,其中包含了http的响应状态,响应状态码等信息;
// 对象中的data属性值才是我们请求来的数据
// console.log(res);
// console.log(res.data);
bindHTML(res.data);
});
1.3.3 并发多个请求,并且要等所有请求结束之后再做处理
- axios.all([axios请求1, axios请求2, ….])
- 仍然返回then,但是then方法中要传入 axios.spread(callback)
示例:
function getUser(uid) {
return axios.get(`/api/get_user?u_id=${uid}`)
}
function getAside(aid) {
return axios.get(`/api/get_aside?a_id=${aid}`)
}
axios.all([getUser(1), getAside(1)]).then(axios.spread((user, aside) => {
console.log(user);
console.log(aside);
}))
二、ajax接口
返回静态资源文件如html、css、js、图片的服务称为静态资源服务;而ajax接口一般根据客户端的请求返回具体的内容;
2.1 Node静态资源服务器
let http = require('http');
let fs = require('fs');
let url = require('url');
let mime = require('mime');
let server = http.createServer((req, res) => {
let {method} = req;
let urlObj = url.parse(req.url, true);
let {pathname} = urlObj;
let filePath = '';
let contentType = '';
if (pathname === '/') {
filePath = __dirname + '/index.html';
contentType = 'text/html';
} else {
filePath = __dirname + pathname;
contentType = mime.getType(pathname);
}
fs.readFile(filePath, (err, data) => {
if (err) {
res.statusCode = 404;
res.end(`${pathname} You are looking for is not found`);
} else {
res.setHeader('Content-Type', contentType);
res.end(data);
}
})
});
server.listen(8000, () => console.log('port 8000 is on'));
2.2 增加ajax接口
- 如何区分ajax接口还是静态资源服务请求?
静态资源文件请求一般包含文件的扩展名,特殊的有 / ,所以如果pathname有扩展名或者是 / 就是静态资源服务,否则就是接口; - 所有的ajax接口返回json,设置内容类型为 application/json;
- 设置返回json的编码为 charset=UTF-8; 如果不设置返回的json会乱码;
let http = require('http');
let fs = require('fs');
let url = require('url');
let mime = require('mime');
let server = http.createServer((req, res) => {
let {method} = req;
let urlObj = url.parse(req.url, true);
let {pathname} = urlObj;
let filePath = '';
let contentType = '';
// 1. 静态资源服务
if (pathname === '/' || /(\.\w+)$/.test(pathname)) {
if (pathname === '/') {
filePath = __dirname + '/index.html';
contentType = 'text/html';
} else {
filePath = __dirname + pathname;
contentType = mime.getType(pathname);
}
fs.readFile(filePath, (err, data) => {
if (err) {
res.statusCode = 404;
res.end(`${pathname} You are looking for is not found`);
} else {
res.setHeader('Content-Type', contentType);
res.end(data);
}
})
} else {
// ajax 接口
res.setHeader('Content-Type', 'application/json;charset=UTF-8;');
if (pathname === '/api/get_aside') {
// 使用data和end事件获取post请求的数据
if (method.toUpperCase === 'POST') {
var postStr = '';
req.on('data', (data) => postStr += data);
req.on('end', () => {
let obj = JSON.parse(postStr);
fs.readFile(__dirname + '/aside.json', (err, data) => {
if (err) {
res.statusCode = 404;
res.end(`${pathname} You are looking for is not found`);
} else {
res.setHeader('Content-Type', 'application/json;charset=UTF-8;');
res.end(data);
}
});
});
} else {
fs.readFile(__dirname + '/aside.json', (err, data) => {
if (err) {
res.statusCode = 404;
res.end(`${pathname} You are looking for is not found`);
} else {
res.end(data);
}
});
}
}
// 获取用户的信息
if (pathname === '/api/get_user') {
let urlObj = url.parse(req.url, true);
let {u_id} = urlObj.query;
fs.readFile(__dirname + '/user.json', 'utf8', function (err, data) {
let dataArr = JSON.parse(data);
let user = dataArr.find(item => +item.id === +u_id);
if (user) {
res.end(JSON.stringify({
code: 0,
data: {
token: 'adsflkds1fldslafk'
},
msg: 'ok'
}))
} else {
res.end(JSON.stringify({
code: -1,
data: {},
msg: '用户不存在'
}))
}
})
}
}
});
server.listen(8000, () => console.log('port 8000 is on'));
三、PromiseA+
实现一个Promise
class MyPromise {
constructor (executor) {
// this 是当前类的实例
// 当resolve执行时,会把当前实例上成功的事件池中的所有函数挨个执行
// 给实例添加两个事件池,一个是装成功的事件函数,一个装失败的事件函数
// 初始化一个状态 pending
// 初始化一个值value
this.state = 'pending';
this.fulfilledEvent = [];
this.rejectedEvent = [];
this.value = undefined;
let resolve = (result) => {
// 循环事件池中的函数,让其按个执行
// 修改状态,一旦状态发生变更就不能再修改状态
if (this.state !== 'pending') return;
this.state = 'fulfilled';
this.value = result;
setTimeout(() => {
this.fulfilledEvent.forEach(fulfillCb => {
if (typeof fulfillCb === 'function') fulfillCb(this.value);
}, 0)
})
};
// 当reject时,把实例上保存失败的事件池中的函数都执行了
let reject = (reason) => {
if (this.state !== 'pending') return;
this.state = 'rejected';
this.value = reason;
let timer = setTimeout(() => {
clearTimeout(timer); // 这里为啥要清除timer???
this.rejectedEvent.forEach(rejectCb => {
if (typeof rejectCb === 'function') rejectCb(this.value);
})
})
};
// 处理Promise的异常
try {
executor(resolve, reject);
} catch (e) {
reject(e)
}
}
then (resolveFn, rejectFn) {
// 如果then方法中没有传递resolveFn或者rejectFn,要自动补全
if (!resolveFn) {
resolveFn = result => result;
}
if (!rejectFn) {
rejectFn = reason => {
throw new Error(reason)
}
}
return new MyPromise((resolve, reject) => {
// 不是直接把函数放进去,因为需要判断当前函数是否返回一个Promise实例
this.fulfilledEvent.push((result) => {
try {
let x = resolveFn(result);
x instanceof MyPromise
? x.then(resolve, reject)
: resolve(result);
} catch (e) {
reject(e)
}
});
this.rejectedEvent.push(reason => {
try {
let x = rejectFn(reason);
x instanceof MyPromise
? x.then(resolve, reject)
: resolve(x); // 如果不是Promise实例,直接执行下一个then中的resolve
} catch (e) {
reject(e);
}
})
})
}
}
使用
new MyPromise((resolve, reject) => {
console.log(1);
reject('abc');
}).then(function (res) {
console.log(2);
}, function (err) {
console.log(3)
}).then((res) => {
console.log(4)
}, function () {
console.log(5)
});
console.log(6);
【发上等愿,结中等缘,享下等福,择高处立,寻平处住,向宽处行】