本文保证问题只增不减,使得知识面半径不断加长
webpack打包vue速度太慢怎么办?
- 配置externals
- 代码压缩用ParallelUglifyPlugin代替自带的 UglifyJsPlugin插件
- 不需要打包编译的插件库换成全局
<script>
标签引入的方式 - 使用CommonsChunkPlugin提取公共的模块,可以减少文件体积,也有助于浏览器层的文件缓存
// 提取公共模块文件
new webpack.optimize.CommonsChunkPlugin({
chunks: ['home', 'detail'],
// 开发环境下需要使用热更新替换,而此时common用chunkhash会出错,可以直接不用hash
filename: '[name].js' + (isProduction ? '?[chunkhash:8]' : ''),
name: 'common'
}),
// 切合公共模块的提取规则,有时后你需要明确指定默认放到公共文件的模块
// 文件入口配置
entry: {
home: './src/js/home',
detail: './src/js/detail',
// 提取jquery入公共文件
common: ['jquery', 'react', 'react-dom']
},
- 使用HappyPack来加速构建
HappyPack会采用多进程去打包构建,使用方式还是蛮简单的,但并不是支持所有的loader 首先引入,定义一下这个插件所开启的线程,推荐是四个,其实也可以直接使用默认的就行了
HappyPack = require('happypack'),
os = require('os'),
happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
然后在module的规则里改动一下,引入它,其中 id是一个标识符
{
test: /\.jsx?$/,
// 编译js或jsx文件,使用babel-loader转换es6为es5
exclude: /node_modules/,
loader: 'HappyPack/loader?id=js'
// use: [{
// loader: 'babel-loader',
// options: {
// }
// }]
}
然后我们调用插件,设置匹配的id,然后相关的配置可以直接把use:的规则部分套在loaders上
new HappyPack({
id: 'js',
loaders: [{
loader: 'babel-loader',
options: {
// cacheDirectory: true
}
}]
}),
要注意的第一点是,它对file-loader和url-loader支持不好,所以这两个loader就不需要换成happypack了,其他loader可以类似地换一下
要注意的第二点是,使用ExtractTextWebpackPlugin提取css文件也不是完全就能转换过来,所以需要小小的改动一下,比如
module: {
rules: [{
test: /\.css$/,
// loader: 'HappyPack/loader?id=css'
// 提取CSS文件
use: cssExtractor.extract({
// 如果配置成不提取,则此类文件使用style-loader插入到<head>标签中
fallback: 'style-loader',
use: 'HappyPack/loader?id=css'
// use: [{
// loader: 'css-loader',
// options: {
// // url: false,
// minimize: true
// }
// },
// // 'postcss-loader'
// ]
})
}, {
test: /\.scss$/,
// loader: 'HappyPack/loader?id=scss'
// 编译Sass文件 提取CSS文件
use: sassExtractor.extract({
// 如果配置成不提取,则此类文件使用style-loader插入到<head>标签中
fallback: 'style-loader',
use: 'HappyPack/loader?id=scss'
// use: [
// 'css-loader',
// // 'postcss-loader',
// {
// loader: 'sass-loader',
// options: {
// sourceMap: true,
// outputStyle: 'compressed'
// }
// }
// ]
})
}
因为它是直接函数调用的,我们就放到里层的use规则就行了,然后配置插件即可
plugins: [
new HappyPack({
id: 'css',
loaders: [{
loader: 'css-loader',
options: {
// url: false,
minimize: true
}
}]
}),
new HappyPack({
id: 'scss',
loaders: [{
'loader': 'css-loader'
}, {
loader: 'fast-sass-loader',
options: {
sourceMap: true,
outputStyle: 'compressed'
}
}]
}),
- 有些插件以模块化来引入,这样主要引入有用的代码
// 原来的引入方式
import {debounce} from 'lodash';
//按模块化的引入方式
import debounce from 'lodash/debounce';
- 使用异步的模块加载
这个算是可以减小模块的体积吧,在一定程度上也是为用户考虑的,使用require.ensure来设置哪些模块需要异步加载,webpack会将它打包到一个独立的chunk中,
在某个时刻(比如用户点击了查看)才异步地加载这个模块来执行
$('.bg-input').click(() => {
console.log('clicked, loading async.js')
require.ensure([], require => {
require('./components/async2').log();
require('./components/async1').log();
console.log('loading async.js done');
});
});
- 有时不需要解析某些模块的依赖(这些模块并没有依赖,或者并根本就没有模块化),
使用noParse,直接跳过解析
module: {
noParse: /node_modules\/(jquey\.js)/
}
- 优化构建时的搜索路径
在webpack打包时,会有各种各样的路径要去查询搜索,我们可以加上一些配置,让它搜索地更快
比如说,方便改成绝对路径的模块路径就改一下,以纯模块名来引入的可以加上一些目录路径
还可以善于用resolve alias别名 这个字段来配置
还有exclude等的配置,避免多余查找的文件,比如使用babel别忘了剔除不需要遍历的
{
test: /\.jsx?$/,
// 编译js或jsx文件,使用babel-loader转换es6为es5
exclude: /node_modules/,
use: [{
loader: 'babel-loader',
options: {
}
}]
}
- 理一下打包构建涉及的模块,分析看有哪些包是不需要打包的,只打包需要的模块
webpack编译时加上参数 --json > stat.json 后,可以上传到 webpack-analyse 、webpack-visualizer 等分析站点上,看看打包的模块信息
- 提取公共代码
如何解决vue打包vendor过大的问题?
-
减少公共包大小:vendor打包过大的原因就是引用三方插件的js太大了 ,可以直接在index的script中引用镜像解决问题;
-
模板包不会太大:vue-router按需引入,这样会拆包
Vue首页白屏是什么问题引起的?如何解决呢?
首页白屏问题:
首页加载过慢,是因为它是一个单页应用,需要将所有需要的资源都下载到浏览器端并解析。所以页面越大,加载时间越长,而且js执行的时间也长,dcl发生的时间点就更晚,所以会白屏
解决办法:
- 优化 webpack 减少模块打包体积,code-split 按需加载
- 服务端渲染,在服务端事先拼装好首页所需的 html
- 首页加 loading 或 骨架屏 (仅仅是优化体验)
- 服务端开启gzip压缩
- 打包文件分包,提取公共文件包
如何优化首页的加载速度?
- 浏览器缓存
- gzip压缩
- 内容分发网络(CDN)
- 异步脚本
<script async src=""></script>
- 优化JavaScript、HTML和CSS代码,删除所有不必要的空格和注释,从而减小文件大小
- JavaScript的延迟解析,通过延迟解析脚本,可以减少初始网站的加载时间
- 启用Keep Alive
- 不使用内联CSS
- 避免阻塞型的JavaScript和CSS
推迟加载那些不重要的JavaScript,或者采用异步加载的方式。另一种选择是将这些HTML代码内嵌到网站上,同时需要确保CSS的优化。
- 图像和文件格式
建议使用JPEG格式,而不是GIF和PNG图像,除非图像包含Alpha因子或者是透明的。
- 文件分离
网站的文件可以分为CSS、JavaScripts和图像。文件分离虽然并不能直接改善网站的加载时间。但是,这么做可以提高服务器的稳定性,特别是当网站流量突然出现了尖峰的时候。子域也可以用于托管文件,这样可以增加并行下载的数量。
- 尽量减少HTTP请求
当一个网站一下子收到太多的HTTP请求,它的访客就会有响应时间延迟的体验,这不仅增加了CPU使用率也增加了页面的加载时间。那么,又该如何减少HTTP请求?请见以下步骤。
- 减少网站上的对象数量。
- 最小化网站上的重定向数量。
- 使用CSS Sprites技术(只要你需要的那部分图片内容)。
- 结合JavaScripts和CSS。
分析下Vue项目本地开发完成后部署到服务器后报404是什么原因呢?
-
检查nginx配置,是否正确设置了资源映射条件
-
检查vue.config.js中是否配置了publicPath,若有则检查是否和项目资源文件在服务器摆放位置一致
vue部署上线前需要做哪些准备工作?
- 检查配置环境是否正确
- git版本是否正确
- 打包路劲是否正确
- ngnix配置
- 删除console
Vue开发规范有哪些?
-
强制
- 组件名为多个单词
export default { name: 'TodoItem', // ... } 反例: export default { name: 'Todo', // ... }
- 组件的data必须是一个函数
- prop定义尽量详细,包含类型、默认值、是否必须、validate
- 为for设置key
- 避免v-if和v-for同时使用
- 为组件样式设置作用域
- 用完整单词
-
建议
- 使用组件文件
components/TodoItem.vue
- 缩写指令
-
谨慎使用 (有潜在危险的模式)
- scoped使用元素选择器
- 优先通过 prop 和事件进行父子组件之间的通信,而不是 this.$parent 或改变 prop
- 没有在 v-if/v-if-else/v-else 中使用 key
如果一组 v-if + v-else 的元素类型相同,最好使用 key
父组件中使用插槽时怎么访问子组件的数据
子组件
<template>
<div>
<h2>默认插槽</h2>
<slot :toParent="childrenData" :toParent2="childrenData2">
{{childrenData.data1}}
{{childrenData2.data1}}
</slot>
<h2>头部插槽</h2>
<slot name="header" :headerData="headerData">
{{headerData.data1}}
</slot>
</div>
</template>
<script>
export default{
data(){
return{
childrenData:{
data1:'子组件数据一',
data2:'子组件数据二',
},
childrenData2:{
data1:'子组件数据三',
data2:'子组件数据四',
},
headerData:{
data1:'子组件头部数据一',
data2:'子组件头部数据二',
},
}
},
}
</script>
slotProps是代表插槽prop的集合,其命名可以随便取的。此时slotProps.toParent的值就是childrenData的值
父组件
<template>
<div>
<myComponent>
// slotProps和headerProps是代表插槽prop的集合,其命名可以随便取的
<template v-slot:default="slotProps">
{{slotProps.toParent.data2}}
{{slotProps.toParent2.data2}}
</template>
<template v-slot:header="headerProps">
{{headerProps.headerData.data2}}
</template>
//当有子组件slot上有多个插槽prop时,父组件调用时候可以ES6对象解构的方法
<template v-slot:default="{toParent,toParent2}">
{{toParent.data2}}
{{toParent2.data2}}
</template>
<template v-slot:header="{headerData}">
{{headerData.data2}}
</template>
//也可以给子组件slot上绑定的值重新命名
<template #default="{toParent:a,toParent2:b}">
{{a.data2}}
{{b.data2}}
</template>
<template #header="{headerData:c}">
{{c.data2}}
</template>
</myComponent>
</div>
</template>
对DOM选项el、template、render的理解?
- el:
提供一个在页面上已存在的DOM元素作为Vue实例的挂载目标
。可以是CSS选择器,也可以是一个HTMLElement实例。- 因为所有的挂载元素会被Vue生成的DOM替换。因此不推荐挂载Vue实例到html或者body上。
- 如果在const vm = new Vue({})中存在这个选项,实例将立即进入编译过程,否则,需要显式调用vm.$mount()手动开启编译。
vm = new Vue({})中存在el
<script>
const vm= new Vue({
el:'#app',
data:{
age:17
},
}
</script>
要显式调用vm.$mount()手动开启编译
<script>
const vm= new Vue({
data:{
age:17
},
})
vm.$mount('#app')
</script>
- template:一个字符串模板
作为Vue实例的标识使用
。如果el存在,模板将会替换挂载的元素。挂载元素的内容都将被忽略,除非模板的内容有分发插槽。- 如果值以 # 开始,则它将被用作选择符,并使用匹配元素的 innerHTML 作为模板。
<script>
const vm= new Vue({
el:'#app',
data:{
age:17
},
template:'<div>我是template的内容:小明今年{{age}}岁了</div>',
})
</script>
<script type="x-template" id="mb">
和 # 结合
<script type="x-template" id="mb">
<div>我是template的内容:小明今年{{age}}岁了</div>
</script>
<script>
const vm= new Vue({
el:'#app',
data:{
age:17
},
template:'#mb',
})
</script>
template 、id和 # 结合
<body>
<div id="app">
我是el挂载的内容:小明今年{{age}}岁了
</div>
<template id="mb">
<div>我是template的内容:小明今年{{age}}岁了</div>
</template>
</body>
<script>
const vm= new Vue({
el:'#app',
data:{
age:17
},
template:'#mb',
})
</script>
- render :
Vue 选项中的 render 函数若存在,则 Vue 构造函数不会从 template 选项或通过 el 选项指定的挂载元素中提取出的 HTML 模板编译渲染函数
。
<body>
<div id="app">
我是el挂载的内容:小明今年{{age}}岁了
</div>
</body>
<script>
const vm= new Vue({
el:'#app',
data:{
age:17
},
template:'<div>我是template的内容:小明今年{{age}}岁了</div>',
render(h){
return h('div',`我是render的内容:小明今年${this.age}岁了`)
}
})
</script>
自定义指令的生命周期(钩子函数)有哪些?如何手写一个自定义指令?
- bind:只调用一次,在指令第一次绑定到元素时调用,可以在这个钩子函数中进行初始化设置;
- inserted:被绑定元素插入父节点时调用,在bind后面调用;
- update:所在绑定的组件的VNode更新时调用,但是可能发生在其子VNode更新之前。 调用时指令的值不一定发生改变,通过比较更新前后的值来忽略不必要的模板更新;
- componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用;
- unbind:只调用一次,指令与元素解绑时调用。
Vue.directive('color', {
bind:function(){
alert('bind')
},
inserted: function (el,binding) {
alert('inserted')
el.style.color=binding.value;
},
update:function(el,binding){
alert('update')
el.style.color=binding.value;
},
componentUpdated:function(el,binding){
alert('componentUpdated')
el.style.color=binding.value;
},
unbind:function(){
alert('v-color指令解绑')
}
})
render函数有什么好处?
template也会翻译成render,只有一点,template中元素的tag_name是静态的,不可变化
,使用createEelment可以生成不同tag_name, 比如h1 ... h6, 可以通过一个number变量控制
vue挂载过程
看我的另一篇细讲:【Vue原理】$mounted源码分析
你了解什么是高阶组件吗?
高阶组件(HOC)的定义:接收一个组件作为参数,返回一个新的组件
高阶组件(HOC)的特点:
- 应该是无副作用的纯函数,且不应该修改原组件,即原组件不能有变动
- 不关心你传递的数据(props)是什么,并且新生成组件不关心数据来源
- 接收到的 props 应该透传给被包装组件即
直接将原组件prop传给包装组件
- 完全可以添加、删除、修改 props
实例1
<template>
<div>
<p @click="Click">props: {{test}}</p>
</div>
</template>
<script>
export default {
name: 'Base',
props: {
test: Number
},
methods: {
Click () {
this.$emit('Base-click')
}
}
}
</script>
实例2
export default function Console (BaseComponent) {
return {
template: '<wrapped v-on="$listeners" v-bind="$attrs"/>',
components: {
wrapped: BaseComponent
},
mounted () {
console.log('haha')
}
}
}
Vue.observable有了解过吗?
让一个对象可响应。可以作为最小化的跨组件状态存储器。有点类似于小型的Vuex
const store = Vue.observable({name:'hhy'});
const mutation = {
updateName(name){
store.name = name
}
}
store和mutaion可以分别在computed和methods中调用
怎么解决Vue中动态设置img的src不生效的问题?
因为动态添加src被当做静态资源处理了,没有进行编译,所以要加上require
component 标签和 is 特殊特性在组件上的应用
- 动态组件
<component :is="componentName"></component>
componentName可以是在本页面已经注册的局部组件名和全局组件名,也可以是一个组件的选项对象。
当控制componentName改变时就可以动态切换选择组件。
- is的用法
有些HTML元素,诸如 <ul>、<ol>、<table> 和 <select>
,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如 <li>、<tr> 和 <option>
,只能出现在其它某些特定的元素内部。
<ul>
<name-list></name-list>
</ul>
上面<name-list></name-list>
会被作为无效的内容提升到外部
,并导致最终渲染结果出错。应该这么写
<ul>
<li is="nameList"></li>
</ul>
删除对象delete和Vue.delete有什么区别?
- delete:只是被删除对象成员变为' '或undefined,其他元素键值不变;
- Vue.delete:直接删了对象成员,如果对象是响应式的,确保删除能触发更新视图,这个方法主要用于避开 Vue 不能检测到属性被删除的限制。
你有用过事件总线(EventBus)吗?说说你的理解
通过一个空的vue实例作为桥梁实现vue组件间的通信。它是实现非父子组件通信的一种解决方案。
- 创建一个vue实例,导出这个实例
import Vue from 'Vue'
export default new Vue
- 在两个需要通信的两个组件中分别引入这个bus.js
import Bus from '这里是你引入bus.js的路径' // Bus可自由更换喜欢的名字
- 传递数据的组件里通过vue实例方法$emit发送事件名称和需要传递的数据。(发送数据组件)
Bus.$emit('click',data) // 这个click是一个自定义的事件名称,data就是你要传递的数据。
- 被传递数据的组件内通过vue实例方法$on监听到事件和接受到数据。
Bus.$on('click',target => {
console.log(target) // 注意:发送和监听的事件名称必须一致,target就是获取的数据,可以不写target。只要你喜欢叫什么都可以(当然了,这一定要符合形参变量的命名规范)
})
- 在vue生命周期beforeDestroy或者destroyed中用vue实例的$off方法清除eventBus
beforeDestroy(){
bus.$off('click')
}
EventBus注册在全局上时,路由切换时会重复触发事件,如何解决呢?
在有使用$on的组件中
要在beforeDestroy钩子函数中用$off销毁。
使用Vue后怎么针对搜索引擎做SEO优化?
SEO:
- 网站结构:网站结构要清晰、要扁平
- 导航:页面应该要有简明的导航。导航可以让搜索引擎知道网站的结构,也可以让搜索引擎知道当前页面在网站结构所在的层次。
- 规范的URL: url尽量简短,尽量减少动态url中包含的变量参数。
- 提交Sitemap:Sitemap 可通知搜索引擎他们网站上有哪些可供抓取的网页,以便搜索引擎可以更加智能地抓取网站。
- 合理的HTTP返回码:不同的返回码,搜索引擎的处理逻辑是不一样的
- 合适的title:告诉搜索引擎网页的主要内容
- 合适的description
- HTML语义化
对于SEO支持比较好的项目方案是采用服务端渲染。所以如果项目有SEO需求,那么比较好的方案是服务端渲染。
Vue为什么要求组件模板只能有一个根元素?
let vm = new Vue({
el:'#app'
})
<body>
<div id='app1'></div>
<div id='app2'></div>
</body>
Vue其实并不知道哪一个才是我们的入口,因为对于一个入口来讲,这个入口就是一个‘Vue类',Vue需要把这个入口里面的所有东西拿来渲染,处理,最后再重新插入到dom中。
如果同时设置了多个入口,那么vue就不知道哪一个才是这个‘类'。
为什么template下必须有且只能有一个div呢?
template标签是HTML5出来的新标签,它有三个特性:
1.隐藏性:该标签不会显示在页面的任何地方,即便里面有多少内容,它永远都是隐藏的状态;
2.任意性:该标签可以写在页面的任何地方,甚至是head、body、sciprt标签内;
3.无效性:该标签里的任何HTML内容都是无效的,不会起任何作用;
但是呢,可以通过innerHTML来获取到里面的内容。
其实本质上,一个单文件组件,本质上会被各种各样的loader处理成为.js文件(因为当你import一个单文件组件并打印出来的时候,是一个vue实例),通过template的任意性我们知道,template包裹的HTML可以写在任何地方,那么对于一个.vue来讲,这个template里面的内容就是会被vue处理为虚拟dom并渲染的内容,导致结果又回到了开始 :既然一个.vue单文件组件是一个vue实例,那么这个实例的入口在哪里?
如果在template下有多个div,那么该如何指定这个vue实例的根入口?
为了让组件能够正常的生成一个vue实例
,那么这个div会被自然的处理成程序的入口。
通过这个‘根节点',来递归遍历整个vue‘树'下的所有节点,并处理为vdom,最后再渲染成真正的HTML,插入在正确的位置
那么这个入口,就是这个树的‘根',各个子元素,子组件,就是这个树的‘枝叶',而自然而然地,这棵‘树',就是指一个vue实例了。
你知道nextTick的原理吗?
看我的另一篇文章:【Vue原理】$nextTick源码分析
说下你对Vue的template编译的理解?
简单的说法:先转化为AST树,在得到的render函数中返回VNode(vue的虚拟DOM节点)
- 通过compile编译器对template字符串进行解析,将标签、指令、属性等编译成AST语法树(即源代码的抽象语法结构的树状表现形式),compile是creatCompiler(createCompiler是用以创建编译器的)的返回值,compile负责合并option
AST:
Node {
type: 'File',
start: 0,
end: 156,
loc:
SourceLocation {
start: Position { line: 1, column: 0 },
end: Position { line: 10, column: 0 } },
errors: [],
program:
Node {
type: 'Program',
start: 0,
end: 156,
loc: SourceLocation { start: [Object], end: [Object] },
sourceType: 'module',
interpreter: null,
body: [ [Object], [Object], [Object], [Object], [Object], [Object] ],
directives: [] },
comments: [] }
- AST会经过generate(将AST语法树转化成render function字符串的过程)得到render函数,render的返回值是VNode,VNode是Vue的虚拟DOM节点,里面包含(标签名、子节点、文本等)
template预编译是什么?
预编译:在打包阶段预编译成render函数(也就是项目的构建过程中完成)
因为如果可以的话,就可以去掉vue源码中的compile部分,进一步减小体积;同时可以让实际组件在runtime时跳过模板渲染,进而提升性能
对于Vue组件来说,vue的template是在运行时转换为render函数的,模板编译只会在组件实例化时编译一次
,生成render function不会再进行编译,因此,编译对组件的runtime是一种性能损耗。所以思考预编译。
Vue实例挂载的过程是怎样的?
实例挂载主要是 $mount
方法的实现,在 src/platforms/web/entry-runtime-with-compiler.js & src/platforms/web/runtime/index.js 等文件中都有对Vue.prototype.$mount的定义
在$mount方法中,会先判断options中 el 是否存在,再判断 render (有template存在的条件下也需要有render函数),之后再是再判断template,会对template做一定的校验,最后使用 compileToFunctions 将template转化为render 和 staticRenderFns
为何官方推荐使用axios而不用vue-resource?
- vue-resources不再更新了,vue作者尤大推荐axios。
- axios更加强大
- axios就是一个基于ES6的Promise的网络请求库,其实说干净了就是一个打包好的XMLHttpRequests,也就是说,这个也是一个ajax库。
- axios 在浏览器里建立XHR,通过nodejs进行http请求,转换或者拦截请求数据或响应数据,支持Promise的API,可以取消请求,自动转换JSON,可以防御XSRF攻击!
- vue-resources 只提供了浏览器版本
vue中 axios怎么封装?
import axios from 'axios'
axios.defaults.baseURL = ...
axios.defaults.timeout = 10000;
axios.defaults.headers.post['Content-Type'] = 'application/json';
//请求拦截
axios.interceptors.request.use(config => {
//可在此处登入
return config;
}, error => {
return Promise.reject(error);
});
//响应拦截
axios.interceptors.response.use(response => {
// 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据
if (response.status === 200) {
if (response.data.code === 900) {
Message.error(response.data.msg)
//可在此处登出
}
return Promise.resolve(response);
} else {
return Promise.reject(response);
}
}, error => {
if (error.response && error.response.status === 401) {
window.localStorage.removeItem('token');
}
});
/**
* axios封装get和post方法
*/
function get(url, params, config = {}) {
return new Promise((resolve, reject) => {
axios.get(url, {
params,
...config,
}).then(res => {
resolve(res.data);
}).catch(err => {
reject(err.data);
})
});
}
function post(url, params, config = {}) {
return new Promise((resolve, reject) => {
axios.post(url, params, {
...config,
})
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err.data);
})
});
}
Vue切换页面时碰见过中断axios请求的场景吗?如何中断?
场景:在Vue单页面开发过程中,遇到这样的情况,当我切换页面时,由于上一页面请求执行时间长,切换到该页面时,还未执行完,这时那个请求仍会继续执行直到请求结束,此时将会影响页面性能,并且可能对现在页面的数据显示造成一定影响。
所以我们应该,切换页面前中断前面所有请求
- 使用cancelToken.sourse工厂方法创建cancel token
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get('/user/12345', {
cancelToken: source.token
}).catch(function(thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// 处理错误
}
});
axios.post('/user/12345', {
name: 'new name'
}, {
cancelToken: source.token
})
// 取消请求(message 参数是可选的)
source.cancel('Operation canceled by the user.');
- 通过传递一个 executor 函数到 CancelToken 的构造函数来创建 cancel toke
const CancelToken = axios.CancelToken;
let cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
// executor 函数接收一个 cancel 函数作为参数
cancel = c;
})
});
// cancel the request
cancel();
如果将axios异步请求同步化处理?
使用 asyns/await 将 axios 异步请求同步化
async getData (params) {
try {
let res = await axios.get('url', {
params
})
this.tableData = res.data.result
} catch (err) {
console.log(err)
}
}
也可以定义new Promise,再用asyns/await使用它
function getData (data) {
return new Promise((resolve, reject) => {
axios.get('url', {
params: data
}).then((res) => {
resolve(res)
}).catch((err) => {
reject(err)
})
})
}
async function useFun(){
try {
let res = await this.getData()
console.log(res)
//拿到返回数据res后再进行处理
} catch (err) {
console.log(err)
}
}
axios的原理和源码分析?
juejin.cn/post/684490… (vue和react区别)