找回密码
 立即注册
搜索

技术分享 如何优雅处理「快应用」数据请求

3
回复
2711
查看
[复制链接]

10

主题

18

帖子

1363

积分

 楼主| 2019-7-16 11:27:47 显示全部楼层 |阅读模式
本帖最后由 open 于 2019-7-16 12:10 编辑
查阅快应用开发文档,可以知道官方提供了数据请求接口;对于如何使用,文档中也给出了简单的说明和代码示例,但很显然,这在实际项目中,不够优雅且更不高效,所以需要对其进行再封装,使得可以大幅提升开发效率,同时也令整个代码优雅,以便于维护。所以在此篇文章的存在,旨在于讨论下如何优雅处理「快应用」数据请求。
备注: 本文最先发布于,基于 Ghost 构建的最新博客: 静轩之别苑
为保证文中的代码,是直接拷贝就可以运行的,特有引用网络开源接口;需要备注说明的是,在快应用使用接口,需要在 manifest.json 中,对所使用的接口进行声明;使用数据请求,就需要注入下面的声明:
  1. { "name": "system.fetch" }
复制代码
默认的低效率写法
  1. import $fetch from '@system.fetch'
  2. $fetch.fetch({
  3. url: 'https://api.apiopen.top/singlePoetry',
  4. responseType: 'text',
  5. success: function (response) {
  6. const result = response.data
  7. console.log(`success response, code: ${result.code}, data: ${result.data}`)
  8. },
  9. fail: function (data, code) {
  10. console.log(`fetch handling fail, code = ${code}`)
  11. },
  12. complete: funtion (data, code) {
  13. console.log(`fetch handling complete, code = ${code}`)
  14. }
  15. })
复制代码
以上就是官方文档提供的上古 jQuery 时代的写法,冗长的代码,古老的回调式操作,以及对请求没有做任何必要的处理,如果这在项目中使用,对代码复用度无疑是零,从长期维护角度看,这样的代码就是导致痛苦的根源。虽然,示例代码这样写道,也无可厚非;但先入为主的模范作用,将对于诸多经验不够充足的开发者,起到错误的误导性引领。
改进后的用法
其实,快应用对部分接口方法调用,返回了 Promise 优化,其中就包括数据请求接口;所以,使用如上这种方式,至少代码显得不那么冗长而古老。但,数据请求相关代码,却依然没有得到复用,这就需要对其进行封装处理。
优化处理数据请求
如果每次调用接口,都需要 import,外加指定 url,method 等参数,这无异是变相的浪费生命;大道至简,优秀的开发流程,一定是便于编写和维护!所以有必要将其统一封装,如下面所封装的代码(可放置在 helpera/ajax.js路径下):
  1. function requestHandle(params) {
  2. return new Promise((resolve, reject) => {
  3. $fetch.fetch({
  4. url: params.url,
  5. method: params.method,
  6. data: params.data
  7. }).then(response => {
  8. const result = response.data
  9. const content = JSON.parse(result.data)
  10. /* @desc: 可跟具体不同业务接口数据,返回你所需要的部分,使得使用尽可能便捷 */
  11. content.code === 200 ? resolve(content.result) : resolve(content.message)
  12. }).catch((error, code) => {
  13. console.log(` request fail, code = ${code}`)
  14. reject(error)
  15. })
  16. })
  17. }
  18. /* 此处只是处于示例代码的可运行性,实际项目中,此方法最好予以封装 & 提取 */
  19. function queryString(url, query) {
  20. let str = []
  21. for (let key in query) {
  22. if (typeof query[key] === 'object') {
  23. query[key] = JSON.stringify(query[key])
  24. }
  25. str.push(key + '=' + query[key])
  26. }
  27. let paramStr = str.join('&')
  28. return paramStr ? `${url}?${paramStr}` : url
  29. }
  30. export default {
  31. post: function(url, params) {
  32. return requestHandle({
  33. method: 'post',
  34. url: url,
  35. data: params
  36. })
  37. },
  38. get: function(url, params) {
  39. return requestHandle({
  40. method: 'get',
  41. url: queryString(url, params)
  42. })
  43. }
  44. }
复制代码
这 $fetch.fetch 返回本就是一个 Promise,这里为何额外要包裹的一层处理呢?这样做的好处不仅在于使其依旧可以链式调用,同时对返回数据统一处理,精简返回内容,使得在获取到最终结果处,可以尽可能简单,更加有利于后期做维护,调用方式就可以成为如下这样(涉及某类模块,可统一在相应模块文件下,如:helper/apis/poetry.js ):
  1. import $ajax from './../ajax'
  2. const baseUrl = 'https://api.apiopen.top/'
  3. export default {
  4. getSinglePoetry(data) {
  5. return $ajax.get(`${baseUrl}singlePoetry`, data)
  6. },
  7. getOtherApi(data) {
  8. // other api ....
  9. }
  10. }
复制代码
另外,开发者将接口,按照功能模块规划,分门别类以存放至统一文件夹下,如 helper/apis;如此清晰明了,方便调用,且对于多人协作开发,又不相互响应,减少不必要的冲突。类似善用配置,以表驱动法的编程手法,应该活学活用,贯穿始终。这些理念,早在更优雅的处理-Http-请求 | 开箱即用的 Vue Webpack 脚手架模版中就有阐述。
至此,就对接口进行了完美封装处理;在业务层便捷调用,也是需要优化;在快应用,最为高效的办法,就是将上面封装暴露给 global,如此就可以:
  1. import { $apis } from './helper'
  2. const hook2global = global.__proto__ || global
  3. hook2global.$apis = $apis
  4. // 在任何其他页面、组件、js 文件,接可以像如下调用
  5. const params = {}
  6. $apis.poetry.getSinglePoetry(params).then(result => {
  7. // 处理正常逻辑
  8. }).catch(error => {
  9. // 处理请求异常逻辑
  10. })
复制代码
更近一步体验优化
在业务逻辑中,发起数据请求时候,都需要添加 Loading,提示用户请求正在进行中,以免响应缓慢给用户带来不必要的疑惑;而,在请求成功或失败情形下,都需要对 Loading 进行消除,如此一来就会有下面的逻辑:
  1. $apis.poetry.getSinglePoetry(params).then(result => {
  2. this.isLoading = false
  3. // 处理正常逻辑
  4. }).catch(error => {
  5. // 处理请求异常逻辑
  6. this.isLoading = false
  7. })
复制代码
很明显,像类似不管请求成功或失败,都需要执行的业务逻辑是存在的,如果分别在对应链式后做处理,谈何优雅呢?在 ES2018 有引入 finally 标准,跟快应用中请求后 complete 回调是一样的作用:不管最后状态如何,都会执行的操作。所以上面的调用,就可以优化成如下代码:
  1. $apis.poetry.getSinglePoetry(params).then(result => {
  2. // 处理正常逻辑
  3. }).catch(error => {
  4. // 处理请求异常逻辑
  5. }).finally(() => {
  6. this.isLoading = false
  7. })
复制代码
当按照预期这样写的时候,你会发现 finally 链式并未得到调用。查阅一番,兴许你也会得到一个答案,快应用规范没有 finally,如此一来,就不得不打补丁 (polyfill) 来予以解决了,可以有的途径不少,下面介绍一种简单无依赖的法子,注入以下代码即可;那么上面关于 ajax.js 的封装则可以优化成如下代码:
  1. Promise.prototype.finally = function (callback) {
  2. const P = this.constructor
  3. return this.then(
  4. value => P.resolve(callback()).then(() => value),
  5. reason => P.resolve(callback()).then(() => { throw reason })
  6. )
  7. }
  8. function requestHandle(params) {
  9. return new Promise((resolve, reject) => {
  10. $fetch.fetch({
  11. url: params.url,
  12. method: params.method,
  13. data: params.data
  14. }).then(response => {
  15. const result = response.data
  16. const content = JSON.parse(result.data)
  17. /* @desc: 可跟具体不同业务接口数据,返回你所需要的部分,使得使用尽可能便捷 */
  18. content.code === 200 ? resolve(content.result) : resolve(content.message)
  19. }).catch((error, code) => {
  20. console.log(`request fail, code = ${code}`)
  21. reject(error)
  22. }).finally(() => {
  23. console.log(`request @${params.url} has been completed.`)
  24. resolve()
  25. })
  26. })
  27. }
复制代码
需要补充说明的是,finally 方法指定的回调函数,用于指定不管 Promise 对象最后状态如何,都会执行的操作;它是与状态无关的,不依赖于 Promise 的执行结果,所以此处 polyfill 返回跟标准一致,回调函数不接受任何参数。
关于快应用数据请求的整体代码优化设计,具体可参见 Github 项目:quickapp-boilerplate-template: 致力于构建更为优雅的「快应用」开发脚手架模板。
至此,对处理「快应用」数据请求,相比开发文档中所写到的示例,是不是优雅很多呢?如果你的项目中,涉及数据请求有超过 3 个的可能,那么你就应该做像着样。当然,这不仅仅限于此接口,其他如数据存储(storage),上传下载(request),你都应该予以封装。这也不仅仅限于快应用,其他如开发 Vue、React 等项目,亦是同理。
回复

使用道具 举报

6

主题

35

帖子

205

积分

2019-7-16 15:57:58 显示全部楼层
感谢辛苦付出 & 排版;希望些许经验,可以帮助到更多开发快应用的朋友;如在使用类似方案中,有遇到任何问题,可以在 https://www.jeffjade.com/2019/01 ... e-quickapp-request/ 原文链接下留下评论;当然,也欢迎各路朋友提出改进意见 or 建议。
悲莫悲兮生别离, 乐莫乐兮新相知。 https://nicelinks.site
回复

使用道具 举报

0

主题

5

帖子

25

积分

2019-8-15 17:37:14 显示全部楼层
flyio 了解一下
回复

使用道具 举报

6

主题

28

帖子

170

积分

2019-8-29 11:23:35 显示全部楼层
跨域能解决吗大佬? https://bbs.quickapp.cn/forum.php?mod=viewthread&tid=1954
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册