学网页设计很久了,但是之前一直都没搞明白JavaScrip的异步处理,以及对应的fetch、promise、then、catch的使用。
前一阵子终于悟了,所以写出来也帮助一下和之前的我一样的人。
绪论
假如我们想做一个阅读器,
运行时它会在div#document_content中另外一个Html的内容。
同时,它旁边会有一个小小的div作为目录,会显示这个被显示在document_content的页面的目录(也就是提取出所有的h1、h2等显示出来,并且可以点击来滚动跳转
-
使用fetch即可通过请求获取其它网页的内容。
fetch是一共用来进行一个HTTP请求。它会返回一个Promise对象
Promise,可以理解为一个承诺,某个操作可能没法立刻有结果,但是承诺在完成后会给一个结果。由于通常用来处理一些网络连接之类的可能会失败,还会允许承诺出结果时附带一个状态:
Resolved表示操作成功,Rejected表示操作失败。加上还有一个承诺未出结果时的状态,一共三个状态。
-
就比如说,让舍友去带炒面,舍友答应了,也就是给了一个承诺帮你带饭,但是去买需要时间并不能立刻买到,他给你的只是一个承诺,不是买的结果。你需要等待这个承诺的结果。
但是去到饭堂,可能炒面已经卖完了。
那没卖完舍友就给你买了一份带回来;卖完了舍友可能就回来告诉你卖完了,或者在微信告诉你卖完了。
然后作为call了“请帮我带炒面”这个函数的人,如果承诺的结果是买到了,那你就吃就行;要是结果是没买到,你就得看看是怎么样是吃别的还是不吃了。也就是对承诺的结果进行处理。
而具体怎么判断承诺的结果、处理,则是用then。
-
我们常用的fetch等会产生Promise的方法,我们就只管使用就好;而如果是自己定义的长耗时的函数,自己创造一个promise对象,就要包含怎么样是成功,怎么样是失败了。
then是Promise对象的一个方法,用来设置如果Promise的结果是执行成功做什么,设置一个回调函数。
通常来讲,我们会这样写:
fetch(链接)
.then(respond => {
// 成功时怎么处理
})
.catch(error =>{
// 失败时怎么处理
})
实际上就是
fetch(链接).then().catch()
的意思,就是把。因为不需要把这个promise赋值给某个变量存起来,也就直接这样就好了。
而catch则是Promise对象设置如果是执行失败会做什么。
例子
function load_doc(url_doc){
fetch(url_doc)
.then(response=> response.text())
.then(html => {
document.getElementById("document_content").innerHTML = html;
})
}
像这样,就能完成我们刚刚说的把另外一个网页的内容加载到这里面去(但是注意不能跨域访问)。
接下来是详细的介绍。
-
fetch
fetch(url, options)
url为请求的URL。
options(可选)用来指定请求的方式、请求头等。默认是GET。
会返回一个Promise,若执行成功会隐式传递一个response给fetch.then()传入的回调函数
注意,fetch并不是只是用来获取数据,也可以用于向服务器post前端的数据。这种情况下,其实我们并不关心fetch的response,可以直接不then,只.catch即可。
fetch(url)
.then(response => { })
.catch(error => { })
response是一个对象,包含了status、headers,有.text()、.json()
注意,通常我们都要获得response的内容,也就是调用response.text()或response.json()。注意,这两个也是会返回一个promise,因为处理可能也要耗时较久
它的结果会隐式传递
也就是这样写,把.text()给解析了:
let testing_doc = "../docs/common/tf_card/tf_card.html";
fetch(testing_doc)
.then(response => {
response.text()
.then(html => {
console.log(html)
})
})
但是这样写会嵌套调用.then,并不好。我们可以
let testing_doc = "../docs/common/tf_card/tf_card.html";
fetch(testing_doc)
.then(response => {
return response.text()
})
.then(html => {
console.log(html)
})
注意,这样其实就是
fetch().then().then()
因为then()的返回值就是传进去的那个函数的返回值,所以他就能传到下一个
千万别忘了return,否则fetch().then()就是未定义,那再来.then()一下还是未定义。
还有一种简便写法:
let testing_doc = "../docs/common/tf_card/tf_card.html";
fetch(testing_doc) .then(
response => response.text())
.then(html => {
console.log(html)
})
利用了箭头函数如果代码一行,可以写到一行省略{},则可以省去return自动返回该行的写法。
-
Promise
看了前面讲fetch的部分,你应该对promise的应用有了基本的认识。
接下来讲点更底层的东西。
.then()和.catch()都是promise的方法。
那么为什么是fetch().then().catch()呢?
是因为,then()返回的也是一个promise!
然后,如果发生了错误,就会详细传递。
比如说
fetch() .then() // then1
.then() // then2
.then() // then3
.catch()
.then() // then4
如果是then2发生了错误,后续的then将不执行(也就是then3不执行),一路向下传递,直到catch那里。然后,catch之后,被视为错误已经被捕获了,它就不会一直累加了,catch后续的then仍然可以正常运行。也就是说,then4还是能执行的。
-
前面讲到链式解析和嵌套解析,说链式解析更好。
这是因为,链式解析的可读性更强。其次,像上面演示的这个这样链式解析,错误会一直向下传递,一个catch就可以捕获前面的所有then的错误。如果是写成嵌套解析,那么就无法这样。
async 和 await
如果不想用then,可以用async和await,让代码看起来像同步的。
async function loadData() {
let response = await fetch('data.json'); // 等待 fetch 完成
let data = await response.json(); // 等待 json() 解析
console.log("数据:", data);
}
loadData();
更多游戏资讯请关注:电玩帮游戏资讯专区
电玩帮图文攻略 www.vgover.com