#每日一记#前端与后端交互 数据状态设计 最佳实践

每日一记 - 但并不日更

在前端页面开发中,大部分的时间都是在与后端进行数据交互:获取数据、计算并渲染。而页面上又有大量的元素状态须要维护,显示、隐藏、变化。这些均可能让咱们焦头烂额,而后在一周后看不懂本身的代码。javascript

无奈

因此项目开发的过程当中须要一个规范来约束代码的走向,让代码能按照统一的、最高效的方式运行(还有让别人阅读)。这里介绍一个前端对接后端接口数据的一个最佳实践。html

先让咱们看看反例,不知道你是否是用过这样的 app:前端

  • 点了一个按钮没有反应(???这按钮坏了),可是忽然页面像爆炸了同样不停的刷新(-,-啊救命)
  • 进入一个页面,是个纯白的(???网卡了?程序报错了?),返回再进仍是纯白,让你搞不清楚到底发生了什么。

这里的例子说明:若是前端开发中不能把异常描述清楚、涵盖全面,数据状态的糟糕反馈就会直接影响用户体验。java

问题分析

咱们先从最简单的状况入手,一个页面使用一个接口。这种状况下一般是:后端

  • 全量获取列表
  • 获取主页详情
  • 发布一张图片
  • 搜索关键词
  • ···

这样的状况又分两种,服务器

  • 进入页面时获取数据 -> 渲染页面
  • 进入页面后进行操做 -> 获得反馈 -> 渲染页面。

不管是哪种状况,咱们都只在一个页面里处理一个接口,这是最简单的状况。那么咱们来看一下下面的图片,并把它看成一个开发任务思考一下你会怎么处理。网络

老板来了个需求

若是你只想到了**「调用接口」「渲染页面」里,那你这篇文章就是为你写的(笑)。其实上面的图只向你展现了两个状态**:「初始状态」「理想结果状态」,我用了「理想结果」这个词来描述这个状态,是由于这是咱们在一切操做都完美的状况下获得的理想状态。app

而一般在项目里你只会从别人手里获得这两张图,我说的对吗?(产品经理和设计师都默认你了解他们须要的一切)。函数

若是咱们但愿作一个优秀的前端,咱们就须要马上发现这里还缺乏了三张图(三个状态)(有些交互里并不须要这么多状态,这里只讨论最全面的状况)优化

数据获取中状态 无数据状态 数据异常状态

一个接口的5个状态

需求分析

从调用一个接口到渲染页面咱们大体分为一下几部

调用接口 -> 获得数据 -> 处理数据 -> 渲染

初始状态

接下来咱们来编写一些代码,来对接接口而且管理数据和状态。为了使代码更加聚合,用一个字面量对象 SeaerchInput 来维护状态。而后咱们模拟一个接口的调用。

// 以上面搜索为例

// 建立页面对象
let SearchInput = {}

// 模拟一个接口
function API () {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      let result = [{
        name: '李三'
      }];
      resolve(result);
    })
  })
}
复制代码

理想结果状态

接下来咱们在SearchInput中用data字段保存数据,用getSearchResult()方法绑定数据,调用接口并直接绑定数据,那么咱们将获得的「理想结果状态」。

let SearchInput = {
  data: null,

  getSearchResult() {
    API.then(
      (res) => {
        this.data = res; // 绑定数据
      }
    )    
  }
}

SearchInput.getSearchResult();  // 获取数据

function API () {
  return new Promise(function (resolve, reject) {
    // ...
  })
}
复制代码
// html 的语法将使用 angular 指令去表达
<div>
  <!-- 渲染结果 -->
  <p ng-repeat="result in SearchInput.data"></p>
</div>
复制代码

这样的代码是十分脆弱的,由于咱们已经默认数据会瞬间返回而且没有任何问题。

数据获取中状态

function API () {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      let result = [{
        name: '李三'
      }];
      resolve(result);
    }, 3000)  // 为接口增长3秒的延时
  })
}
复制代码

一旦给API增长点延时,就会发现页面会在纯白状态下停留好久,由于页面没有任何提示,因此用户根本没法知道发生了什么事情,是等待仍是返回?

为此咱们须要管理从接口发起请求(request)到接收响应(response)这段时间的状态,在SearchInput中用hasDone来保存接口的响应状态,null表明这个接口还在初始化状态,false表明已经发出请求但未收到响应,true表明已经收到响应。

let SearchInput = {
  data: null,
  hasDone: null, // 初始化

  getSearchResult() {
    this.hasDone = false; // 发起请求时置为 false

    API.then(
      (res) => {
        this.hasDone = true; // 收到响应时置为 true
        this.data = res;
      }
    )    
  }
}

SearchInput.getSearchResult();

function API () {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      // ...
    }, 3000)  // 为接口增长3秒的延时
  })
}
复制代码
<!-- 数据获取中状态 -->
<div ng-if="SearchInput.hasDone === false">
  loading
</div>

<div ng-if="SearchInput.hasDone">
  <!-- 渲染结果 -->
  <p ng-repeat="result in SearchInput.data"></p>
</div>
复制代码

这下好了,若是接口很慢页面也会显示 loading,用户不会为此不知所措了。

数据异常状态

尽管如今网络和服务器已经十分稳定,不多会出现异常,可是不管是网络、服务器或代码哪个出现异常而没有考虑,那都会形成用很差的用户体验

function API () {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      let error = '服务器异常';
      reject(error);  // 接口返回了异常
    })
  })
}
复制代码

如今咱们假设咱们的API返回了异常,页面又会变为纯白了,没有任何数据显示也没有任何提示。

为此咱们须要一个状态来管理接口返回的状态,在SearchInput中用hasSuccess来保存接口的返回状态,null表明还在初始化状态,false表明接口返回失败,true表明接口成功返回数据。(你甚至能够先判断数据的格式、数量等是否知足你的要求,若是不知足要求,即便接口返回了数据,你同样能够将hasSuccess设置为false,由于这里的 success 表明了你获得了能够正确使用的数据,而不只仅是获得了数据)

let SearchInput = {
  data: null,
  hasDone: null, 
  hasSuccess: null, // 初始化

  getSearchResult() {
    this.hasDone = false;

    API.then(
      (res) => {
        this.hasDone = true;
        this.hasSuccess = true; // 获得数据置为 true
        this.data = res;
      },
      (err) => {
        this.hasDone = true; // 此时咱们也要更新 hasDone
        this.hasSuccess = false; // 发生异常置为 false
      }
    )    
  }
}

SearchInput.getSearchResult();

function API () {
  return new Promise(function (resolve, reject) {
    // ...
  })
}
复制代码
<!-- 数据获取中状态 -->
<div ng-if="SearchInput.hasDone === false">
  loading
</div>

<!-- 数据异常状态 -->
<div ng-if="SearchInput.hasDone && SearchInput.hasSuccess === false">
  数据异常
</div>

<div ng-if="SearchInput.hasDone && SearchInput.hasSuccess">
  <!-- 渲染结果 -->
  <p ng-repeat="result in SearchInput.data"></p>
</div>
复制代码

如今咱们会在hasDone === true后知道数据是否正常,而且给出了错误的提示。

无数据状态

最后一个状态也是咱们要考虑的,当用户尝试搜索一个词却什么都没返回,又变成了可恶的纯白界面,咱们还须要考虑一下当获取数据时什么都没有的状况。

function API () {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      let result = [];  // 如今没有任何结果
      resolve(result);
    })
  })
}
复制代码

咱们须要一个状态来管理数据的状态,在SearchInput中用hasData来保存数据状态,null表明还在初始化中,false表明数据为空,true表明数据不为空。

let SearchInput = {
  data: null,
  hasDone: null, 
  hasSuccess: null, 
  hasData: null, // 初始化

  getSearchResult() {
    this.hasDone = false;

    API.then(
      (res) => {
        this.hasDone = true;
        this.hasSuccess = true; 
        this.hasData = res.length > 0; // 有置为 true,没有数据置为 false
        this.data = res;
      },
      (err) => {
        this.hasDone = true;
        this.hasSuccess = false; 
        this.hasData = false; // 失败确定没有数据了
      }
    )    
  }
}

SearchInput.getSearchResult();

function API () {
  return new Promise(function (resolve, reject) {
    // ...
  })
}
复制代码
<!-- 数据获取中状态 -->
<div ng-if="SearchInput.hasDone === false">
  loading
</div>

<!-- 数据异常状态 -->
<div ng-if="SearchInput.hasDone && SearchInput.hasSuccess === false">
  数据异常
</div>

<!-- 无数据状态 -->
<div ng-if="SearchInput.hasDone && SearchInput.hasSuccess && SearchInput.hasData === false">
  数据异常
</div>

<div ng-if="SearchInput.hasDone && SearchInput.hasSuccess && SearchInput.hasData">
  <!-- 渲染结果 -->
  <p ng-repeat="result in SearchInput.data"></p>
</div>
复制代码

如今上面的代码基本上就是你所须要的了,它能够帮你应对各类状况,让页面展现的更加完美。

实践分析

这一大段代码就是对应一个简单接口五个状态的设计,也是我目前项目中使用的模式,虽然看上去比较繁琐,可是相比后期再不停的补充和修改,一次性考虑全面带来不少好处。

若是一个接口是为了实现分页加载,那么状态的数量又会有所提高,这篇文章再也不阐述。

若是一个页面使用了多个接口,数据和状态之间产生了交叉,为了使状态逻辑清晰应该合理利用字面量对象来聚合代码逻辑。

在多人协做方面,因为你们使用同一套规范,对代码的阅读速度有显著提升。

这里列出的代码以普及为主,不少实现细节方面均可以再去优化,提炼。甚至写一个构造函数也是很方便的选择。

感谢阅读

罗小黑写写文字

若是喜欢文章 请留下一个赞~ 若是喜欢文章 分享给更多人~

掘金中关注我 在简书中关注我

自由转载-非商用-非衍生-保持署名(创意共享3.0许可证) 转载时请保留原文连接 以保证可及时获取对文章的订正和修改

相关文章
相关标签/搜索