使用异步组件优化Vue应用程序的性能


Posted in Javascript onApril 28, 2019

单页应用其一个问题是首屏屏渲染速度较慢。这是因为页面首次加载时服务器将向客户端发送大量JavaScript,在屏幕上显示任何内容之前必须下载并解析。可以想象,随着应用程序规模的扩大,这个问题对用户体验的影响也会越来越突出。

现在幸运的是,当使用Vue CLI构建Vue应用程序时(使用webpack),可以采取一些措施来抵消这种情况。在本文中,我将演示如何在应用程序的初始渲染之后使用 异步组件 和webpack的代码分割功能加载到页面的某些部分。这将使初始加载时间降至最低,并为您的应用程序提供更好的用户体验。

认识异步组件

在我们开始创建异步组件之前,让我们看一下我们通常如何加载组件。为此,我们将使用一个非常简单的消息组件作为例子:

<!-- Message.vue -->
<template>
 <h1>New message!</h1>
</template>

现在我们已经创建了我们的 Message 组件,让我们将它加载到我们的文件中并显示它。我们可以导入组件并将其添加到组件选项中,以便我们可以在模板中使用它:

<!-- App.vue -->
<template>
 <div>
 <message></message>
 </div>
</template>

<script>
import Message from "./Message";
export default {
 components: {
 Message
 }
};
</script>

但现在发生了什么?只要应用程序加载,就会加载 Message 组件,因此它包含在初始加载过程中。

对于一个简单的应用程序来说,这看起来可能不是一个大问题,但可以考虑像电商网站这样复杂的场景。想象一下,用户将项目添加到购物车,然后想要结帐,因此单击结帐按钮会生成一个包含所选商品的所有详细信息的框。使用上述方法,此结帐框将包含在初始包中,但我们只需在用户单击结帐按钮时使用该组件。用户甚至可以在不点击结账按钮的情况下浏览网站,这意味着在加载这个可能不会使用的组件时浪费资源是没有意义的。

为了提高应用程序的效率,我们可以结合延迟加载和代码分割技术。

Webpack提供的代码拆分功能允许您将代码拆分为各种捆绑包,然后可以按需加载或稍后并行加载。它只能在需要或使用时加载特定的代码片段。

Dynamic Imports(动态导入)

Vue使用Dynamic Imports解决这种情况。此功能引入了一种新的类似函数的导入形式,它将返回包含(Vue)组件的Promise。由于import是一个接收字符串的函数,我们可以做一些强大的事情,比如使用表达式加载模块。自版本61以来,Chrome中已提供动态导入。有关这些内容的详细信息, 请访问Google Developers网站 。

代码拆分由webpack,Rollup或Parcel等捆绑器处理,它们解析动态导入语法并为每个动态导入的模块创建单独的文件。稍后我们将在控制台的网络选项卡中看到这一点。但首先,我们来看看静态和动态导入之间的区别:

// static import
import Message from "./Message";

// dynamic import
import("./Message").then(Message => {
 // Message module is available here...
});

现在,让我们将这些知识应用到我们的 Message 组件中,我们将得到一个如下所示的组件: App.vue

<!-- App.vue -->
<template>
 <div>
 <message></message>
 </div>
</template>

<script>
import Message from "./Message";
export default {
 components: {
 Message: () => import("./Message")
 }
};
</script>

如你所见,函数import()将解析返回组件的Promise,这意味着我们已成功异步加载组件。如果您查看 devtoolsnetwork 选项卡,您会注意到一个名为 0.js 包含异步组件的文件。

使用异步组件优化Vue应用程序的性能 

根据条件加载异步组件

现在我们已经掌握了异步组件,让我们仅在真正需要时加载它们。在本文的上一节中,我解释了仅在用户点击结帐按钮时才加载的结帐框的用例。让我们把它构建出来。

项目设置

如果您没有安装 vue/cli ,首先应该安装它:

npm i -g @vue/cli

接下来,使用CLI创建新项目,在出现提示时选择默认预设即可:

vue create my-store

转到项目目录,然后安装我们将用于样式的ant-design-vue库:

cd my-store
npm i ant-design-vue

接下来,导入Ant设计库: src/main.js

import 'ant-design-vue/dist/antd.css'

最后我们在 src/comonents 里创建两个新组件 Checkout.vueItems.vue

touch src/components/{Checkout.vue,Items.vue}

写一个商店的视图层

打开 src/App.vue 并用以下代码替换文件里代码:

<template>
 <div id="app">
 <h1>{{ msg }}</h1>
 <items></items>
 </div>
</template>

<script>
import items from "./components/Items"

export default {
 components: {
 items
 },
 name: 'app',
 data () {
 return {
  msg: 'My Fancy T-Shirt Store'
 }
 }
}
</script>

<style>
#app {
 font-family: 'Avenir', Helvetica, Arial, sans-serif;
 -webkit-font-smoothing: antialiased;
 -moz-osx-font-smoothing: grayscale;
 text-align: center;
 color: #2c3e50;
 margin-top: 60px;
}

h1, h2 {
 font-weight: normal;
}

ul {
 list-style-type: none;
 padding: 0;
}

li {
 display: inline-block;
 margin: 0 10px;
}

a {
 color: #42b983;
}
</style>

这里没有什么花哨的东西。我们所做的只是显示一条消息并渲染一个 <items> 组件。

接下来,打开 src/components/Items.vue 并添加以下代码:

<template>
 <div>
 <div style="padding: 20px;">
  <Row :gutter="16">
  <Col :span="24" style="padding:5px">
   <Icon type="shopping-cart" style="margin-right:5px"/>{{shoppingList.length}} item(s)
   <Button @click="show = true" id="checkout">Checkout</Button>
  </Col>
  </Row>
 </div>
 <div v-if="show">
  <Row :gutter="16" style="margin:0 400px 50px 400px">
  <checkout v-bind:shoppingList="shoppingList"></checkout>
  </Row>
 </div>
 <div style="background-color: #ececec; padding: 20px;">
  <Row :gutter="16">
  <Col :span="6" v-for="(item, key) in items" v-bind:key="key" style="padding:5px">
   <Card v-bind:title="item.msg" v-bind:key="key">
   <Button type="primary" @click="addItem(key)">Buy ${{item.price}}</Button>
   </Card>
  </Col>
  </Row>
 </div>
 </div>
</template>

<script>
import { Card, Col, Row, Button, Icon } from 'ant-design-vue';

export default {
 methods: {
 addItem (key) {
  if(!this.shoppingList.includes(key)) {
  this.shoppingList.push(key);
  }
 }
 },
 components: {
 Card, Col, Row, Button, Icon,
 checkout: () => import('./Checkout')
 },
 data: () => ({
 items: [
  { msg: 'First Product', price: 9.99 },
  { msg: 'Second Product', price: 19.99 },
  { msg: 'Third Product', price: 15.00 },
  { msg: 'Fancy Shirt', price: 137.00 },
  { msg: 'More Fancy', price: 109.99 },
  { msg: 'Extreme', price: 3.00 },
  { msg: 'Super Shirt', price: 109.99 },
  { msg: 'Epic Shirt', price: 3.00 },
 ],
 shoppingList: [],
 show: false
 })
}
</script>
<style>
#checkout {
 background-color:#e55242;
 color:white;
 margin-left: 10px;
}
</style>

在此文件中,我们显示一个带有商品数量的购物车图标。商品是从 items 数组中提取的。如果单击项目的 Buy 按钮,将会调用 addItem 方法,该方法会将相关商品push到 shoppingList 数组中。从而增加购物车的总数。

我们还在页面中添加了一个 Checkout 按钮:

<Button @click="show = true" id="checkout">Checkout</Button>

当用户点击这个按钮,我们设置的参数 showtruetrue 是非常重要对于有通过条件地加载我们的异步组件。

在接下来的几行中,您可以找到 v-if 的声明,这个语句仅用来显示我们 checkout 组件的 <div> ,但是我们只想在用户点击 Checkout 按钮时显示结账组件,我们该怎么办?

这里我们将 checkout 组件在 components 选项里异步加载。这里 v-bind 将参数传递给组件。正如你看的的这样,创建条件异步组件是很容易的:

<div v-if="show">
 <checkout v-bind:shoppingList="shoppingList"></checkout>
</div>

让我们快速 Checkout 组件添加下面的代码在 src/components/Checkout.vue 里:

<template>
 <Card title="Checkout Items" key="checkout">
 <p v-for="(k, i) in this.shoppingList" :key="i">
  Item: {{items[Number(k)].msg}} for ${{items[Number(k)].price}}
 </p>
 </Card>
</template>

<script>
import { Card } from 'ant-design-vue';

export default {
 props: ['shoppingList'],
 components: {
 Card
 },
 data: () => ({
 items: [
  { msg: 'First Product', price: 9.99 },
  { msg: 'Second Product', price: 19.99 },
  { msg: 'Third Product', price: 15.00 },
  { msg: 'Fancy Shirt', price: 137.00 },
  { msg: 'More Fancy', price: 109.99 },
  { msg: 'Extreme', price: 3.00 },
  { msg: 'Super Shirt', price: 109.99 },
  { msg: 'Epic Shirt', price: 3.00 },
 ]
 })
}
</script>

在这里,我们将接收一个 shoppingList 并把他输出到屏幕上。

您可以使用该 npm run serve 命令运行该应用程序。然后导航到 http:// localhost:8080 。如果一切按计划进行,你应该会看到如下图所示的内容。

使用异步组件优化Vue应用程序的性能

可以尝试打开在 network 选项卡,点击Checkout按钮,可以发现 network 里将异步加载 结账组件

您还可以在GitHub上查看此演示的代码 。

为异步组件添加加载中和加载错误组件

有时异步组件加载过长或加载时。显示加载动画或错误信息可能很有用,但要支持这会再次降低应用程序的速度。异步组件应该小而且加载速度快。这是一个例子:

const Message = () => ({
 component: import("./Message"),
 loading: LoadingAnimation,
 error: ErrorComponent
});

总结

创建和实现异步组件非常简单,应该成为标准开发例程的一部分。从用户体验的角度来看,尽可能减少初始加载时间以保持用户的注意力是非常重要。希望本教程可以帮助您构建异步加载组件。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
探讨javascript是不是面向对象的语言
Nov 21 Javascript
JavaScript截取字符串的2个函数介绍
Aug 27 Javascript
jquery实现图片上传之前预览的方法
Jul 11 Javascript
angularjs创建弹出框实现拖动效果
Aug 25 Javascript
基于jQuery实现页面搜索功能
Mar 26 Javascript
js当前页面登录注册框,固定div,底层阴影的实例代码
Oct 04 Javascript
react 父组件与子组件之间的值传递的方法
Sep 14 Javascript
JS交互点击WKWebView中的图片实现预览效果
Jan 05 Javascript
Layui之table中的radio在切换分页时无法记住选中状态的解决方法
Sep 02 Javascript
通过实例解析chrome如何在mac环境中安装vue-devtools插件
Jul 10 Javascript
js实现盒子拖拽动画效果
Aug 09 Javascript
JavaScript 实现轮播图特效的示例
Nov 05 Javascript
详解微信小程序获取当前时间及日期的方法
Apr 28 #Javascript
vue自定义js图片碎片轮播图切换效果的实现代码
Apr 28 #Javascript
如何在微信小程序里面退出小程序的方法
Apr 28 #Javascript
vue实现移动端轻量日期组件不依赖第三方库的方法
Apr 28 #Javascript
详解小程序退出页面时清除定时器
Apr 28 #Javascript
详解在Javascript中进行面向切面编程
Apr 28 #Javascript
js比较两个单独的数组或对象是否相等的实例代码
Apr 28 #Javascript
You might like
Yii2主题(Theme)用法详解
2016/07/23 PHP
php微信公众号开发之简答题
2018/10/20 PHP
JCalendar 日历控件 v1.0 beta[兼容IE&amp;Firefox] 有文档和例子
2007/05/30 Javascript
IE8 引入跨站数据获取功能说明
2008/07/22 Javascript
js文件中调用js的实现方法小结
2009/10/23 Javascript
在javascript中执行任意html代码的方法示例解读
2013/12/25 Javascript
JavaScript利用正则表达式去除日期中的-
2014/06/09 Javascript
jQuery幻灯片特效代码分享--鼠标滑过按钮时切换(2)
2020/11/18 Javascript
js时间戳转为日期格式的方法
2015/12/28 Javascript
Bootstrap零基础入门教程(二)
2016/07/18 Javascript
Google Maps基础及实例解析
2016/08/06 Javascript
JS只能输入正整数的简单实例
2016/10/07 Javascript
少女风vue组件库的制作全过程
2019/05/15 Javascript
浅析Vue下的components模板使用及应用
2019/11/27 Javascript
如何基于javascript实现贪吃蛇游戏
2020/02/09 Javascript
11个Python Pandas小技巧让你的工作更高效(附代码实例)
2019/04/30 Python
使用OpenCV实现仿射变换—缩放功能
2019/08/29 Python
python 多进程并行编程 ProcessPoolExecutor的实现
2019/10/11 Python
jupyter notebook tensorflow打印device信息实例
2020/04/20 Python
什么是serialVersionUID
2016/03/04 面试题
static全局变量与普通的全局变量有什么区别
2014/05/27 面试题
2019年分享net面试的经历和题目
2016/08/07 面试题
TCP协议通讯的过程和步骤是什么
2015/10/18 面试题
linux面试题参考答案(4)
2013/01/28 面试题
园林施工员岗位职责
2013/12/11 职场文书
药品促销活动方案
2014/02/14 职场文书
公交公司毕业生求职信
2014/02/15 职场文书
我心目中的好老师活动方案
2014/08/19 职场文书
八项规定自查自纠报告及整改措施
2014/10/26 职场文书
考试作弊检讨书怎么写?
2014/12/21 职场文书
皇城相府导游词
2015/02/06 职场文书
大学生实习推荐信
2015/03/27 职场文书
2015年信息化建设工作总结
2015/07/23 职场文书
创业计划书之废品回收
2019/09/26 职场文书
python如何做代码性能分析
2021/04/26 Python
Element-ui Layout布局(Row和Col组件)的实现
2021/12/06 Vue.js