笔记整理

1. 闭包

1、函数里面包含的子函数,子函数访问父函数的局部变量
2、通过return将子函数暴露在全局作用域,子函数就形成闭包
3、通过闭包,父函数的局部变量没有被销毁,可通过闭包去调用 ,但同时,这个局部变量也不会被全局变量污染

概念:

闭包就是能够读取其他函数内部变量的函数,由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

简单来说: 内部函数访问外部函数的变量,这种函数嵌套函数的形式,叫做闭包
优点:

避免全局变量的污染,同时,局部变量没有被销毁,驻留在内存中,还可以被访问

缺点:

1、占内存 ,会引起内存泄漏(不能及时释放内存)
2、对捕获的变量是引用,不是复制
3、父函数每调用一次,会产生不同的闭包

注意:

引用的变量可能发生变化
this指向问题
内存泄露问题

用闭包解决递归调用问题
用闭包模仿块级作用域

2. 作用域

一段代码起作用的范围 分为全局作用域和局部作用域

局部变量:在程序中,只在特定的过程或函数中可以访问的变量,是相对与全局变量而言的。

全局变量也称为外部变量,是在函数的外部定义的,它的作用域为从变量定义处开始,到本程序文件的末尾。全局变量全部存放在静态存储区,在程序开始执行时给全局变量分配存储区,程序行完毕就释放。

局部变量可以和全局变量重名,但是局部变量会屏蔽全局变量。在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。

全局变量是使用相同的内存块在整个类中存储一个值.在整个函数中都适用。

3. 作用域链

函数内部使用变量,先从当前函数查找,如果找不到,则继续向父级查找,如果还找不到继续往上一级查找,最后找到window对象,如果还找不到,则报错提示变量不存在,这种链条关系就是作用域链

4. 原型

每个构造函数都有一个prototype叫显示属性
每个实例都有一个__proto__叫隐式属性
实例的隐式属性指向它构造函数的显示属性
每个prototype原型都有一个constructor属性,指向它关联的构造函数。

原型中添加属性和方法的优缺点?

优点: 函数的每个实例化对象都可以共享函数的原型属性
缺点: 原型的属性使用delete 无法删除

5. 原型链

获取对象属性时,如果对象本身没有这个属性,那就会去他的原型__proto__上去找,如果还查不到,就去找原型的原型,一直找到最顶层(Object.prototype)为止。这个链条式关系就是原型链

6. 继承

6.1 借用构造函数

在子类的构造函数中,调用父类的构造函数,这样父类构造函数中的属性就出现在了子类的构造函数中。

缺点:
  1. 子类无法继承父类原型上的方法。
  2. 破坏了复用性。因为每个实例都创建了一份副本。
6.2 原型继承

原型链是实现继承最原始的模式,即通过prototype属性实现继承。让一个引用类型继承另一个引用类型的属性和方法

缺点:
  1. 重写父级原型链的方法或者添加父级原型链不存在的方法,必须在父级原型链代码之后。
  2. 通过原型链实现继承后,不能再使用字面量的方式创建原型对象,因为会覆盖原型链。
  3. 原型链中引用类型的属性会被所有实例共享的,即所有实例对象使用的是同一份数据,会相互影响
  4. 无法向父级构造函数传参
6.3 组合继承

组合继承 = 原型链 + 借用构造函数。取其长避其短:共享的用原型链,各自的借用构造函数

使用继承的好处?

减少代码量,减少代码冗余
可以属性和方法的共用
减少了内存使用

7. 深拷贝(手写代码)

/**
 * 深拷贝
 */
const obj1 = {
    age: 20,
    name: 'xxx',
    address: {
        city: 'beijing'
    },
    arr: ['a', 'b', 'c']
}
const obj2 = deepClone(obj1)
obj2.address.city = 'shanghai'
obj2.arr[0] = 'a1'
console.log(obj1.address.city)
console.log(obj1.arr[0])

/**
 * 深拷贝
 * @param {Object} obj 要拷贝的对象
 */
function deepClone(obj = {}) {
    if (typeof obj !== 'object' || obj == null) {
        // obj 是 null ,或者不是对象和数组,直接返回
        return obj
    }
    // 初始化返回结果
    let result
    if (obj instanceof Array) {
        result = []
    } else {
        result = {}
    }
    for (let key in obj) {
        // 保证 key 不是原型的属性
        if (obj.hasOwnProperty(key)) {
            // 递归调用!!!
            result[key] = deepClone(obj[key])
        }
    }
    // 返回结果
    return result
}

8. Promise(手写异步图片加载)

异步加载图片代码:

function requestImg(){
            var p = new Promise(function(resolve, reject){
            var img = new Image();
            img.onload = function(){
               resolve(img);
            }
            img.src = 'xxxxxx';
            });
            return p;
        }
        //延时函数,用于给请求计时
        function timeout(){
            var p = new Promise(function(resolve, reject){
                setTimeout(function(){
                    reject('图片请求超时');
                }, 5000);
            });
            return p;
        }
        Promise.race([requestImg(), timeout()]).then(function(results){
            console.log(results);
        }).catch(function(reason){
            console.log(reason);
        });
        //上面代码 requestImg 函数异步请求一张图片,timeout 函数是一个延时 5 秒的异步操作。我们将它们一起放在 race 中赛跑。
        //如果 5 秒内图片请求成功那么便进入 then 方法,执行正常的流程。
        //如果 5 秒钟图片还未成功返回,那么则进入 catch,报“图片请求超时”的信息。

Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
从语法上说,promise 是一个对象,从它可以获取异步操作的的最终状态(成功或失败)。
Promise是一个构造函数,对外提供统一的 API,自己身上有allrejectresolve等方法,原型上有thencatch等方法。

Promise的两个特点

\1. Promise对象的状态不受外界影响
1)pending 初始状态
2)fulfilled 成功状态
3)rejected 失败状态
Promise 有以上三种状态,只有异步操作的结果可以决定当前是哪一种状态,其他任何操作都无法改变这个状态
\2. Promise的状态一旦改变,就不会再变,任何时候都可以得到这个结果,状态不可以逆,只能由 pending变成fulfilled或者由pending变成rejected

有哪些状态和参数?如何使用?

1、主要用于异步计算
2、可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果
3、可以在对象之间传递和操作 promise,帮助我们处理队列
resolve 作用是,将 Promise 对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject 作用是,将 Promise 对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
promise 有三个状态:
1、pending[待定]初始状态
2、fulfilled[实现]操作成功
3、rejected[被否决]操作失败
promise 状态发生改变,就会触发 then()里的响应函数处理后续步骤

9. async / await

async 是“异步”的简写, async 用于申明一个异步的 function
await 可以认为是 async wait 的简写,await 用于等待一个异步方法执行完成。
特点:

  • asayc的用法,它作为一个关键字放到函数前面,这样普通函数就变为了异步函数
  • 异步async函数调用,跟普通函数的使用方式一样
  • 异步async函数返回一个promise对象
  • async函数配合await关键字使用(阻塞代码往下执行)是异步方法,但是阻塞式的

10. 数据双向绑定

vue.js是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的settergetter,在数据变动时发布消息给订阅者,触发相应的监听回调来渲染视图。
具体步骤:

第一步: 需要observer的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter
这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化

第二步: compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图

第三步: Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:
1、在自身实例化时往属性订阅器(dep)里面添加自己
2、自身必须有一个update()方法
3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。

第四步: MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。
名词解释:

1. 什么是setter、getter
答:首先,别误以为他们就是一会要说的get、set

对象有两种属性:

数据属性: 就是我们经常使用的属性
访问器属性: 也称存取器属性(存取器属性就是一组获取和设置值的函数)
2. 什么是Object.defineProperty() ?
语法:

Object.defineProperty(obj, prop, descriptor)

参数:

obj: 必需。目标对象;
prop: 必需。需定义或修改的属性的名字;
descriptor: 必需。目标属性所拥有的特性;

11. 虚拟DOM

所有浏览器的引擎工作流程都差不多,大致分5步:
创建DOM tree –> 创建Style Rules -> 构建Render tree -> 布局Layout –> 绘制Painting

第一步,用HTML分析器,分析HTML元素,构建一颗DOM树。

第二步:用CSS分析器,分析CSS文件和元素上的inline样式,生成页面的样式表。

第三步:将上面的DOM树和样式表,关联起来,构建一颗Render树。这一过程又称为Attachment。每个DOM节点都有attach方法,接受样式信息,返回一个render对象(又名renderer)。这些render对象最终会被构建成一颗Render树。

第四步:有了Render树后,浏览器开始布局,会为每个Render树上的节点确定一个在显示屏上出现的精确坐标值。

第五步:Render数有了,节点显示的位置坐标也有了,最后就是调用每个节点的paint方法,让它们显示出来。

当你用传统的源生api或jQuery去操作DOM时,浏览器会从构建DOM树开始从头到尾执行一遍流程。比如当你在一次操作时,需要更新10个DOM节点,理想状态是一次性构建完DOM树,再执行后续操作。但浏览器没这么智能,收到第一个更新DOM请求后,并不知道后续还有9次更新操作,因此会马上执行流程,最终执行10次流程。显然例如计算DOM节点的坐标值等都是白白浪费性能,可能这次计算完,紧接着的下一个DOM更新请求,这个节点的坐标值就变了,前面的一次计算是无用功。

即使计算机硬件一直在更新迭代,操作DOM的代价仍旧是昂贵的,频繁操作还是会出现页面卡顿,影响用户的体验。真实的DOM节点,哪怕一个最简单的div也包含着很多属性

虚拟DOM就是为了解决浏览器性能问题而被设计出来的。假如一次操作中有10次更新DOM的动作,虚拟DOM不会立即操作DOM,而是将这10次更新的diff内容保存到本地的一个js对象中,最终将这个js对象一次性attach到DOM树上,通知浏览器去执行绘制工作,这样可以避免大量的无谓的计算量。

用js对象模拟DOM节点的好处是,页面的更新可以先全部反映在js对象上,操作内存中的js对象的速度显然要快多了。等更新完后,再将最终的js对象映射成真实的DOM,交由浏览器去绘制。

12. 组件通信

第一种:父传子:主要通过 props

1、在父组件的子组件标签上绑定一个属性,挂载要传输的变量

2、在子组件中通过props来接受数据,props可以是数组也可以是对象,接收的数据可以直接使用 props:["属性名"] props:{属性名:数据类型}

第二种:子传父:主要通过$emit 来实现

1、在父组件的子组件标签上自定义一个事件,然后调用需要的方法

2、在子组件的方法中通过 this.$emit("事件")来触发在父组件中定义的事件,数据是以参数的形式进行传递的

第三种:兄弟之间传值有两种方法:

方法一:通过 event bus 实现

方法二:通过 vuex 实现

1、在src中新建一个Bus.js的文件,然后导出一个空的vue实例

2、在传输数据的一方引入Bus.js 然后通过Bus.$emit(“事件名”,"参数")来派发事件,数据是以$emit()的参数形式来传递

3、在接受的数据的一方 引入 Bus.js 然后通过 Bus.$on("事件名",(data)=>{data是接受的数据})

13. VUEX

vuex 是一个专为vue.js开发的状态管理器,采用集中式存储的所有组件状态

五个属性: stategettersmutationsactionsmodule

基本使用:

新建store.js文件,最后在main.js中引入,并挂载到实列上.

state属性: 存放状态,例如你要存放的数据

getters: 类似于计算属性,可以通过this.$store.getters来获取存放在state里面的数据

mutations: 唯一能改变state的状态就是通过提交mutations来改变,this.$store.commit()

actions: 异步的mutations,可以通过dispatch来分发从而改变state.

数据持久化:

vuex里面存放的数据,页面一经刷新会丢失:

解决办法: 存放在localStorage或者sessionStorage里面,进入页面时判断是否丢失,丢失再去localStorage或者sessionStorage里面取;

app.vue根组件的created里面判断是否丢失,在进行上面的操作;

vuex-persistedstate 插件

14. keep-alive

keep-aliveVue提供给我们一个内置组件,他可以用来保存我们路由切换时组件的状态

组件使用keep-alive以后会新增两个生命周期 actived() deactived(),

我们在切换路由的时候,想保存组件的状态,比如列表页面进入详情,我们想保存列表滚动的位置,我们就可以使用keep-alive保存列表页面的滚动位置。

怎么使用keep-alive,有两种方式,1. 路由配置 2. keep-alive参数

\1. 全局保存在App.vue<keep-alive><routerView/>包裹起来

\2. 路由定义方式

1、router.js中设置要缓存的页面

{
path: '/child1',
name: 'Child1',
component: Child1,
meta:{
keepAlive:true,//保存keep-alive状态
	}
}  

2、用v-if来显示router-view是否在keep-alive中出现

<keep-alive>
     <router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive> 
     <router-view v-if="!$route.meta.keepAlive"></router-view>

\3. 使用keep-alive的标签属性, include() exclude()

include 包含标签名字被缓存 exclude 包含的标签不被缓存

缓存名字组件中有个name属性进行定义即可

15. 路由守卫

有三种分别为 全局守卫 单个路由守卫 组件内部守卫
  1. 全局守卫钩子 beforeEach
  2. 单个路由守卫 beforeEnter
  3. 组件内部守卫
    beforeRouteEnter
    beforeRouteUpdate
    beforeRouteLeave
    参数:
    to 对象 去哪儿
    from 对象 从哪来
    next 函数
    next()相当于 next()==next(true) 继续执行
    不写相当于next==next(false)终止执行
    next(path)跳转

16. 生命周期函数

​1.创建
beforeCreate() 在执行这个钩子的时候 只有一些实例本身的事件和生命周期函数 用户自定义不能使用
created() 最早开始使用 datamethods中数据的钩子
​ 2.挂载
beforeMount() 指令已经解析完毕 内存中已经生成dom
mounted()dom已经渲染完毕 页面和内存的数据已经同步
​ 3.更新
​ beforeUpdate()data的数据发生改变会执行这个钩子 内存中数据是新的 页面是旧的
updated() 内存和页面都是新的
​ 4.销毁
beforeDestroy()即将销毁 datamethods中的数据此时还是可以使用的,可以做一些释放内存的操作
destroyed()已经销毁完毕

activated(组件激活时):和上面的beforeDestroydestroyed用法差不多,但是如果我们需要一个实例,在销毁后再次出现的话,用 beforeDestroydestroyed的话,就太浪费性能了。实例被激活时使用,用于重复激活一个实例的时候

deactivated(组件未激活时):实例没有被激活时。

errorCaptured(错误调用):当捕获一个来自后代组件的错误时被调用

17. 自定义指令

自定义指令分为:全局自定义指令,局部自定义指令。

使用Vue.directive('focus',{bind(el,binding){},inserted(){}})进行全局自定义指令

参数1 :指令的名称

参数2: 是一个对象,这个对象身上,有钩子函数.

钩子函数:

一个指令定义对象可以提供如下几个钩子函数 (均为可选):

inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。

update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。

componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。

unbind:只调用一次,指令与元素解绑时调用。

18. 自定义组件

我用vue开发的所有项目,都是采用组件化的思想开发的。一般我在搭建项目的时候,会创建一个views目录和一个commen目录和一个feature目录,views目录中放页面级的组件,commen中放公共组件(如:head(公共头组件),foot(公共底部组件)等),feature目录内放功能组件(如:swiper(轮播功能组件),tabbar(切换功能组件)、list(上拉加载更多功能组件))

首先,组件可以提升整个项目的开发效率。能够把页面抽象成多个相对独立的模块,解决了我们传统项目开发:效率低、难维护、复用性低等问题。

使用Vue.extend方法创建一个组件,然后使用Vue.component方法注册组件。但是我们一般用脚手架开发项目,每个 .vue单文件就是一个组件。在另一组件import 导入,并在components中注册,子组件需要数据,可以在props中接受定义。而子组件修改好数据后,想把数据传递给父组件。可以采用emit方法。

19. 常见状态码

HTTP状态码表示客户端HTTP请求的返回结果、标记服务器端的处理是否正常或者是出现的错误,能够根据返回的状态码判断请求是否得到正确的处理很重要。
1xx Informational(信息性状态码) 接受的请求正在处理 >
表示请求已接收,继续处理

2xx Success(成功状态码) 请求正常处理完毕 >
表示请求已被成功接收、理解、接受

3xx Redirection(重定向) 需要进行附加操作以完成请求 >
要完成请求必须进行更进一步的操作

4xx Client error(客户端错误) 客户端请求出错,服务器无法处理请求 >
请求有语法错误或请求无法实现

5xx Server Error(服务器错误) 服务器处理请求出错 >
服务器未能实现合法的请求

各类别常见状态码:

2xx (3种)

200 OK:表示从客户端发送给服务器的请求被正常处理并返回;

204 No Content:表示客户端发送给客户端的请求得到了成功处理,但在返回的响应报文中不含实体的主体部分(没有资源可以返回);

206 Patial Content:表示客户端进行了范围请求,并且服务器成功执行了这部分的GET请求,响应报文中包含由Content-Range指定范围的实体内容。

3xx (5种)

301 Moved Permanently:永久性重定向,表示请求的资源被分配了新的URL,之后应使用更改的URL;

302 Found:临时性重定向,表示请求的资源被分配了新的URL,希望本次访问使用新的URL;

   301与302的区别:前者是永久移动,后者是临时移动(之后可能还会更改URL)

303 See Other:表示请求的资源被分配了新的URL,应使用GET方法定向获取请求的资源;

  302与303的区别:后者明确表示客户端应当采用GET方式获取资源

304 Not Modified:表示客户端发送附带条件(是指采用GET方法的请求报文中包含if-Match、If-Modified-Since、If-None-Match、If-Range、If-Unmodified-Since中任一首部)的请求时,服务器端允许访问资源,但是请求为满足条件的情况下返回改状态码;

307 Temporary Redirect:临时重定向,与303有着相同的含义,307会遵照浏览器标准不会从POST变成GET;(不同浏览器可能会出现不同的情况);

4xx (4种)

400 Bad Request:表示请求报文中存在语法错误;

401 Unauthorized:未经许可,需要通过HTTP认证;

403 Forbidden:服务器拒绝该次访问(访问权限出现问题)

404 Not Found:表示服务器上无法找到请求的资源,除此之外,也可以在服务器拒绝请求但不想给拒绝原因时使用;

5xx (2种)

500 Inter Server Error:表示服务器在执行请求时发生了错误,也有可能是web应用存在的bug或某些临时的错误时;

503 Server Unavailable:表示服务器暂时处于超负载或正在进行停机维护,无法处理请求;

20. 跨域

跨域怎么来的

出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)

什么是跨域

当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域

非同源限制

【1】无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB

【2】无法接触非同源网页的 DOM

【3】无法向非同源地址发送 AJAX 请求

解决跨域

1. 前端代码

	<!DOCTYPE html>
	<html lang="en">
	<head>
	  <meta charset="UTF-8">
	  <meta name="viewport" content="width=device-width, initial-scale=1.0">
	  <meta http-equiv="X-UA-Compatible" content="ie=edge">
	  <title>Document</title>
	  <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js"></script>
	</head>
	<body>
	  <script>
	    function showInfo123(data) {
	      console.log(data)
	    }
	  </script>
	<script src="http://127.0.0.1:3000/getscript?callback=showInfo123"></script>
	<!-- <script>
	  show()
	</script> -->
	<button id="btn">jsonp</button>
	</body>
	</html>
	<script>
	$('#btn').click(function(){
	  var frame = document.createElement('script');
	  frame.src = 'http://localhost:3000/getscript?callback=showInfo123';
	  $('body').append(frame);
	})
	</script>

2. 后端代码 node.js

		  // 导入 http 内置模块
		const http = require('http')
		// 这个核心模块,能够帮我们解析 URL地址,从而拿到  pathname  query 
		const urlModule = require('url')
		// 创建一个 http 服务器
		const server = http.createServer()
		// 监听 http 服务器的 request 请求
		server.on('request', function (req, res) {
		  // const url = req.url
		  const { pathname: url, query } = urlModule.parse(req.url, true)
		  if (url === '/getscript') {
		    // 拼接一个合法的JS脚本,这里拼接的是一个方法的调用
		    // var scriptStr = 'show()'
		    var data = {
		      name: 'xjj',
		      age: 18,
		      gender: '女孩子'
		    }
		    var scriptStr = `${query.callback}(${JSON.stringify(data)})`
		    // res.end 发送给 客户端, 客户端去把 这个 字符串,当作JS代码去解析执行
		    res.end(scriptStr)
		  } else {
		    res.end('404')
		  }
		})
		// 指定端口号并启动服务器监听
		server.listen(3000, function () {
		  console.log('server listen at http://127.0.0.1:3000')
		})

话术总结:JSONP原理
ajax 请求受同源策略影响,不允许进行跨域请求,我们利用 script 标签的 src 属性不受同源策略的约束,利用这个特性

jsonp需要以下步骤:

动态创建<script></script>(document.createElement('script'))
设置src 属性,(src总要包含参数callback=fn)进行跨域请求
将 <script></script>添加到页面中执行 (body.appendChild('script'))
页面要提前定义好callback,进行页面操作。

备注:
服务端不再返回JSON格式的数据,而是返回回调函数包裹数据(fn({name:'tom',age:18}),在src中进行了调用,这样实现了跨域。

CORS设置跨域请求

 //设置允许跨域的域名,*代表允许任意域名跨域  CORS跨域
 res.setHeader("Access-Control-Allow-Origin","http://127.0.0.1:3003");

vue-cli如何设置代理跨域
vue组件中:

 fn(){
      this.$axios.get('/api/api/v1/home').then(res=>{
           console.log(res.data);
      })
    }

config.js:

module.exports={
    devServer: {
        proxy:{
            '/api':{
                target:'http://127.0.0.1:3002/',//跨域请求资源地址
                ws:false,//是否启用websockets
                changeOrigin:true,//开启代理:在本地会创建一个虚拟服务端,然后发送请求的数据,并同时接收请求的数据,这样服务端和服务端进行数据的交互就不会有跨域问题
                pathRewrite:{
                    '^/api':''//注册全局路径
                }
            }
        }
    }
}

21. 输入 url 到页面发生了什么

1、浏览器的地址栏输入URL并按下回车。
2、浏览器查找当前URL是否存在缓存,并比较缓存是否过期。
3、DNS解析URL对应的IP。
4、根据IP建立TCP连接(三次握手)。
5、HTTP发起请求。
6、服务器处理请求,浏览器接收HTTP响应。
7、渲染页面,构建DOM树。
8、关闭TCP连接(四次挥手)。

22. 项目开发流程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值