JavaScript 如何使用 fetch() 与后端交互
fetch() 是现代 JavaScript 自带的函数, 用来实现与后端的交互。比如,用来实现不重新加载网页页面,也可以更新网页内容,这种技术过去叫做 AJAX。
目前,大部分网页浏览器都支持 fetch() 了。 过去, 可使用 XMLHttpRequest 对象, 或者 jQuery 的 $.ajax(), 现在, 则推荐使用 fetch()。为什么?是不是写起来比较方便?
理解 fetch() 难点是 Promise,以及如何实现前后端的交互。 下面给出一个叫做 Mimimalist Calendar 的 Flask 网页应用, 来理解 fetch() 的用法。

Mimimalist Calendar 包含了前端代码(templates/calendar.html)与后端代码(app.py), 不需要知道 Promise、async/await 也可以。Mimimalist Calendar 也不包括数据库的读写。

app.py 中定义了两个视图函数, calendar_home() 与 make_entry(), 分别对应路由 '/' 与 '/newentry'。 访问路由 '/', 显示 Mimimalist Calendar 的主页面,其包含了一个表单,以及初始的两条日历。 路由 '/newentry' 需要使用 POST 方法访问,接收表单提供的数据,转义,最后返回一个 JSON 对象,包括日历的日期、描述、字符数。

templates/calendar.html 使用 Jinja2 模板编写。 定义了一张表单(id 为 form01),表单中含有两个输入框,分别用来输入日历日期与日历描述,还有一个 Add 按钮, 点击按钮后把新的日历添加到已有的日历中。 日历用一个列表(ul)表示,id 是 event-list。 重点是,点击 Add 按钮后,我们不希望重新加载 calendar.html。 这时 fetch() 就派上用场了。 fetch() 在自定义的 JavaScript 函数 add_new_event() 中被调用, 见第 35 行。 fetch() 的第一个参数是后端路由,即 '/newentry'。 第二个参数是一个对象, 包含了如下信息: method 是 POST, body 是表单对象。 如果一切顺利,从后端路由 '/newentry' 返回的结果会存到 response 对象(实际是个 Promise)中。 接着,通过 response.json() 得到从后端返回的 JSON 对象, 将该对象存到 result 变量中, 供后面取用。 第 45-48 行新增了一个 <li> 标签,并将其添加到已有的日历中。 使用 elem.prepend(li), 就是在日历的最前面插入。
为了使得点击 Add 按钮后,页面不发生跳转,需要在 add_new_event() 函数的开头加入 event.preventDefault(), 这个非常重要, 见第 32 行。 另外, <form> 标签中, 不需有 action 或者 method 属性,见第 13 行。