这里有两段代码,如何让前端代码变得具有观赏性,更加简洁
后台代码
在这里插入代码片// 静态资源托管,直接访问public/api.html
const express = require('express')
const app = express()
var cors = require('cors')
// 处理跨域请求
app.use(cors())
app.use( express.static('public') )
// 接口1:获取所有的频道
app.get('/get', (req, res) => {
res.send([{id:1, name:'体育频道'}, {id:2, name:'娱乐频道'}])
})
// 接口2:获取指定频道下的分类
app.get('/getCategory', (req, res) => {
if(req.query.id==1){ // 体育频道
res.send([{id:12, name:'NBA新闻'}, {id:13, name:'足球新闻'}])
}else {
res.send([{id:10, name:'娱乐天天笑'}])
}
})
// 接口3:获取指定新闻列表
app.get('/getNews', (req, res) => {
if(req.query.id==12){ // NBA新闻
res.send([{id:1, name:'谁能得到今年的总冠军'}, {id:2, name:'湖人已经不行了么?'}])
}else {
res.send([])
}
})
app.listen(3000)
前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
function getData({url,success}) {
const xhr = new XMLHttpRequest()
xhr.open('get', url)
xhr.onreadystatechange = function (){
if(this.readyState === 4){
// 加载完成
const d = JSON.parse(xhr.responseText);
success(d)
}
}
xhr.send()
}
getData({
url:'http://localhost:3000/get',
success: (data)=>{
getData({
url:'http://localhost:3000/getCategory?id='+data[0].id,
success: data => {
getData({
url:'http://localhost:3000/getNews?id='+data[0].id,
success: data => {
console.log(data)
}
})
}
})
}})
</script>
</body>
</html>
想要前端代码更加简洁 我们得知道promise的用法
promise的简要复习
用来优化异步代码。它的经典使用方式如下
var p1 = new Promise(function(resolve,reject){
//异步操作 resolve(obj1) 或者 reject(obj2)
});
p1.then(function(rs){
// 如果p1的状态是resolved,则then中的函数
//会执行,且obj1的值会传给rs
}).catch(function(rs){
// 如果p1的状态是reject,则catch中的函数
// 会执行,且obj2的值会传给rs
}).finally(function(){
// 一定会执行的函数
})
构造器
// const obj = new Object()
// const arr = new Array()
const p1 = new Promise(function(resolve,reject){
// 执行异步代码
// 调用resolve,或者reject
});
console.dir(p1)
要点:
● 构造器必须要给定一个参数,如果不给就是会报错。例如,new Promise() 报错的信息是: Promise resolver undefined is not a function
● 构造器的实参是一个函数,这个函数的特殊之处在于它有两个形参(resolve,reject),这两个形参也是函数。在格式上,也可以采用箭头函数来改写。例如:var p1 = new Promise((resolve,reject)=>{})。
● 在函数体的内部, 一般会执行异步代码,然后根据情况来调用resolve()或者是reject() 。调用resolve或者是reject后会产生什么样的后果,在后面小节介绍。 当然了,再次强调一下resolve和reject只是形参名,可以改写成其它的。
三种状态
初始态pending :它的意思是 “待定的,将发生的”,相当于是一个初始状态。 创建Promise对象时,且没有调用resolve或者是reject方法,相当于是初始状态。这个初始状态会随着你调用resolve,或者是reject函数而切换到另一种状态。
成功态resolved:也叫fulfilled,resolved。表示解决了,就是说这个承诺实现了
失败态rejected:rejected。拒绝,失败。表示这个承诺没有做到,失败了
promise的值: 一个promise对象除了状态之外,还有promiseValue。在构造器中,这个值在调用resolve和reject方法时传入。
var p = new Promise( (resolve,reject) => { resolve(123); } );
// 此时,prommise对象p的状态是 resolved,值是123。
console.dir(p)
状态是可转化但是状态转换是不可逆的
promise的兑现
看图更直观
● 状态从pending变成resolved,进入then中,调用函数,并传入此时的promiseValue(就是调用resolve时传入的实参)
● 状态从pending变成rejected,进入catch中,调用函数,并传入此时的promiseValue(就是调用reject时传入的实参
使用promise改造回调函数的基本套路
第一步:建立模板。这里的模板是指固定的套路:写一个空函数,在函数体中的创建一个promise对象,并返回。
function fnName(){
var p = new Promise((resolve,reject)=>{ })
return p;
}
第二步:把异步功能写入构造器中,根据实际来决定是否调用resolve,reject。
function fnName(){
var p = new Promise((resolve,reject)=>{
// 这里写具体的代码,并在某个恰当的时机去调用resolve和reject函数。
})
return p;
}
第三步:调用函数。
通过fnName().then().catch() 结构来调用这个函数。
这样就可以将前端代码改写成:
function getDataPromise (url) {
return new Promise((resolve,reject) => {
const xhr = new XMLHttpRequest()
xhr.open('get', url)
xhr.onreadystatechange = function (){
if(this.readyState === 4){
// 加载完成
const d = JSON.parse(xhr.responseText);
resolve(d)
}
}
xhr.send()
})
}
then的格式
// p 是一个promise对象
p.then(函数1[,函数2])
它的两个参数都是函数。
● 第一个参数是resolved状态的回调函数。当p的状态从pending变成了resolved,函数1会执行。
● 第二个参数是rejected状态的回调函数。 当p的状态从pending变成了rejected,函数2会执行。
其中我们常见的catch都是第二个参数的扩展写法
一般可以写成:
promise对象.then(函数1).catch(函数2)
then的返回值
then()方法的返回值也是一个promise对象,所以它支持链式写法。但是要注意的是它的返回值是一个新的promise对象,与调用then方法的并不是同一个对象。
此时代码可以优化成
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
function getDataPromise (url) {
return new Promise((resolve,reject) => {
const xhr = new XMLHttpRequest()
xhr.open('get', url)
xhr.onreadystatechange = function (){
if(this.readyState === 4){
// 加载完成
const d = JSON.parse(xhr.responseText);
resolve(d)
}
}
xhr.send()
})
}
getDataPromise('http://localhost:3000/get').then(data=>{
return getDataPromise('http://localhost:3000/getCategory?id='+data[0].id)
}).then(data => {
return getDataPromise('http://localhost:3000/getNews?id='+data[0].id)
}).then(data => {
console.log(data)
})
async function get() {
const res1 = await getDataPromise('http://localhost:3000/get')
const res2 = await getDataPromise('http://localhost:3000/getCategory?id='+res1[0].id)
const res3 = await getDataPromise('http://localhost:3000/getNews?id='+res2[0].id)
console.log(res3)
}
get()
</script>
</body>
</html>
但是这种仍然不是最好的写法,在ES7中有async和await语法,可以完美解决回调地狱的问题
async和await语法
async: 函数返回一个 Promise 对象
async函数内部return语句返回的值是Promise 对象的值
await 命令 : await的外层函数必须有一个async.
正常情况下,await命令后面是一个 Promise 对象,返回该promise的值。如果不是 Promise 对象,就直接返回对应的值。
这样 我们就可以利用 async和await语法配合ajax写出更简洁的代码了
<script src="./axios.js"></script>
<script>
async function fnAjax(){
const res =await axios.get('http://localhost:3000/get')
console.log(res)
const res1 =await axios.get('http://localhost:3000/getCategory?id='+res.data[0].id)
console.log(res1)
const res2 =await axios.get('http://localhost:3000/getCategory?id='+res1.data[0].id)
console.log(res2)
}
fnAjax()
</script>