JavaScript教程:一次性搞懂promise、then

学网页设计很久了,但是之前一直都没搞明白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