面试增加增加

HTML文档结构
一个完整的HTML文档结构通常包括以下几个部分:

1、文档类型声明(DOCTYPE)
        文档类型声明位于HTML文档的最顶部,它告诉浏览器这是一个HTML5文档。文档类型声明的语法是<!DOCTYPE html>,这行代码是必需的,因为它确保了浏览器以正确的模式来解析和渲染页面。

2、html元素
<html>元素是HTML文档的根元素,它包含了整个网页的内容。所有的其他HTML元素都嵌套在<html>元素内部。

3、head元素
<head>元素包含了文档的元数据(metadata),这些元数据不会直接展示给用户,但对于网页的渲染和搜索引擎的索引非常重要。<head>元素中通常包含<title>、<meta>、<link>、<style>等标签。
<title>标签定义了网页的标题,它显示在浏览器的标题栏或标签页上,同时也是搜索引擎搜索结果中显示的标题。
<meta>标签用于提供关于HTML文档的元信息,如字符集设置、页面描述、关键词等。这些信息对于搜索引擎优化(SEO)非常重要。
<link>标签用于链接外部资源,如CSS样式表、图标等。
<style>标签用于直接嵌入CSS样式代码,但通常推荐将样式代码放在单独的CSS文件中,以保持结构和样式的分离。
4、body元素
<body>元素包含了网页的可见内容,如标题、段落、图片、链接等。所有的内容都应该放在<body>元素内部,以便正确地展示给用户。

下面是一个简单的HTML文档结构的示例:

<!DOCTYPE html>  
<html>  
<head>  
    <meta charset="UTF-8">  
    <title>我的第一个网页</title>  
    <link rel="stylesheet" href="styles.css">  
</head>  
<body>  
    <h1>欢迎来到我的网页</h1>  
    <p>这是一个段落。</p>  
    <img src="image.jpg" alt="我的图片">  
    <a href="https://www.example.com">点击这里访问示例网站</a>  
</body>  
</html>

script 标签放置位置

<script>标签放在HTML文档的底部(即在<body>标签的末尾)是一种推荐的做法。这种放置方式有助于优化页面加载速度,因为它可以避免因脚本加载而阻塞页面的渲染。当脚本位于文档的底部时,页面内容可以首先被加载和显示,然后才是脚本的执行,从而提高了页面的初始加载性能。此外,将脚本放在文档底部还可以减少因脚本执行而导致的页面重新布局或样式变化,从而提升用户体验。

尽管将<script>标签放在<head>中是一种常见的做法,尤其是在需要立即执行脚本或引入外部JavaScript文件时,但这种方式可能会导致页面渲染被阻塞,尤其是在脚本较大或需要较多处理时间时。因此,为了优化页面加载速度和提升用户体验,建议将脚本放在<body>标签的底部,除非有特定的需求需要将脚本放在<head>中。

此外,对于异步加载脚本的需求,可以使用HTML5提供的asyncdefer性来实现。这些属性允许脚本在页面加载过程中异步加载和执行,而不阻塞页面的其他部分。其中,async属性表示脚本会异步加载并在加载完成后立即执行,而defer属性则表示脚本会按照文档顺序执行。选择使用哪个属性取决于具体的需求和对脚本执行时间的要求‌1

css优化

‌避免使用@import‌:@import会导致额外的HTTP请求,可以将CSS文件合并成一个文件,避免使用@import‌1。
‌使用CSS缓存‌:将CSS文件设置为长期缓存,可以减少服务器的压力,提高网页加载速度‌1。

异步加载CSS

CSS文件请求、下载、解析完成之前,CSS会阻塞渲染,浏览器将不会渲染任何已处理的内容前面加载内联代码后,后面的外部引用css则没必要阻塞浏览器渲染。这时候就可以采取异步加载的方案,主要有如下:

  • 使用javascript将link标签插到head标签最后
// 创建link标签
const myCSS = document.createElement( "link" );
myCSS.rel = "stylesheet";
myCSS.href = "mystyles.css";
// 插入到header的最后位置
document.head.insertBefore( myCSS, document.head.childNodes[ document.head.childNodes.length - 1 ].nextSibling );
  • 设置link标签media属性为noexis,浏览器会认为当前样式表不适用当前类型,会在不阻塞页面渲染的情况下再进行下载。加载完成后,将media的值设为screenall,从而让浏览器开始解析CSS
<link rel="stylesheet" href="mystyles.css" media="noexist" onload="this.media='all'">
  • 通过rel属性将link元素标记为alternate可选样式表,也能实现浏览器异步加载。同样别忘了加载完成之后,将rel设回stylesheet
<link rel="alternate stylesheet" href="mystyles.css" onload="this.rel='stylesheet'">

css样式文件有两种引入方式,一种是link元素,另一种是@import

@import影响浏览器的并行下载,使得页面在加载时增加额外的延迟,增添了额外的往返耗时

而且多个@import可能会导致下载顺序紊乱

比如一个css文件index.css包含了以下内容:@import url("reset.css")

那么浏览器就必须先把index.css下载、解析和执行后,才下载、解析和执行第二个文件reset.css

浏览器缓存

浏览器发起HTTP请求 – 服务器响应该请求。那么浏览器第一次向服务器发起该请求后拿到请求结果,会根据响应报文中HTTP头的缓存标识决定是否缓存结果,是则将请求结果和缓存标识存入浏览器缓存中 

由上图我们可以知道:

  • 浏览器每次发起请求,都会先在浏览器缓存中查找该请求的结果以及缓存标识
  • 浏览器每次拿到返回的请求结果都会将该结果和缓存标识存入浏览器缓存中

强制缓存就是向浏览器缓存查找该请求结果,并根据该结果的缓存规则来决定是否使用该缓存结果的过程。

强制缓存的情况主要有三种(暂不分析协商缓存过程),如下:

  1. 不存在该缓存结果和缓存标识,强制缓存失效,则直接向服务器发起请求(跟第一次发起请求一致),如下图:

图片

 

2存在该缓存结果和缓存标识,但该结果已失效,强制缓存失效,则使用协商缓存(暂不分析),如下图

图片

 

3.存在该缓存结果和缓存标识,且该结果尚未失效,强制缓存生效,直接返回该结果,如下图

图片

那么强制缓存的缓存规则是什么?

当浏览器向服务器发起请求时,服务器会将缓存规则放入HTTP响应报文的HTTP头中和请求结果一起返回给浏览器,控制强制缓存的字段分别是Expires和Cache-Control,其中Cache-Control优先级比Expires高。

Cache-Control

要取值为:

  • public:所有内容都将被缓存(客户端和代理服务器都可缓存)
  • private:所有内容只有客户端可以缓存,Cache-Control的默认取值
  • no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
  • no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
  • max-age=xxx (xxx is numeric):缓存内容将在xxx秒后失效
  • HTTP响应报文中expires的时间值,是一个绝对值
  • HTTP响应报文中Cache-Control为max-age=600,是相对值

 

状态码为灰色的请求则代表使用了强制缓存,请求对应的Size值则代表该缓存存放的位置,分别为from memory cache 和 from disk cache。from memory cache代表使用内存中的缓存,from disk cache则代表使用的是硬盘中的缓存,浏览器读取缓存的顺序为memory –> disk。

  • 内存缓存(from memory cache):内存缓存具有两个特点,分别是快速读取和时效性:
    • 快速读取:内存缓存会将编译解析后的文件,直接存入该进程的内存中,占据该进程一定的内存资源,以方便下次运行使用时的快速读取。
    • 时效性:一旦该进程关闭,则该进程的内存则会清空。
  • 硬盘缓存(from disk cache):硬盘缓存则是直接将缓存写入硬盘文件中,读取缓存需要对该缓存存放的硬盘文件进行I/O操作,然后重新解析该缓存内容,读取复杂,速度比内存缓存慢。

在浏览器中,浏览器会在js和图片等文件解析执行后直接存入内存缓存中,那么当刷新页面时只需直接从内存缓存中读取(from memory cache);而css文件则会存入硬盘文件中,所以每次渲染页面都需要从硬盘读取缓存(from disk cache)。

协商缓存 

协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程

协商缓存生效,返回304,如下

图片

304

协商缓存失效,返回200和请求结果结果,如下

图片

200

协商缓存的标识也是在响应报文的HTTP头中和请求结果一起返回给浏览器的,控制协商缓存的字段分别有:Last-Modified / If-Modified-Since和Etag / If-None-Match,其中Etag / If-None-Match的优先级比Last-Modified / If-Modified-Since高。

Last-Modified / If-Modified-Since

Last-Modified是服务器响应请求时,返回该资源文件在服务器最后被修改的时间,如下。

图片

If-Modified-Since则是客户端再次发起该请求时,携带上次请求返回的Last-Modified值,通过此字段值告诉服务器该资源上次请求返回的最后被修改时间 

服务器收到该请求,发现请求头含有If-Modified-Since字段,则会根据If-Modified-Since的字段值与该资源在服务器的最后被修改时间做对比,若服务器的资源最后被修改时间大于If-Modified-Since的字段值,则重新返回资源,状态码为200;否则则返回304,代表资源无更新,可继续使用缓存文件,如下。

Etag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成),如下。 

客户端不必了解指纹码是如何生成的,只需要在下一个请求中将其发送给服务器(浏览器默认会添加):如果指纹码仍然一致,说明资源未被修改,服务器会返回304 Not Modified,这样我们就可以跳过下载,利用已经缓存了的资源,并且该资源会继续缓存120s。

If-None-Match是客户端再次发起该请求时,携带上次请求返回的唯一标识Etag值,通过此字段值告诉服务器该资源上次请求返回的唯一标识值。 

Etag / If-None-Match优先级高于Last-Modified / If-Modified-Since,同时存在则只有Etag / If-None-Match生效。 

总结

浏览器缓存分为强制缓存协商缓存,强制缓存优先于协商缓存进行。

  • 若强制缓存(Expires和Cache-Control,Cache-Control优先级高于Expires)生效则直接使用缓存
  • 若不生效则进行协商缓存(Last-Modified / If-Modified-Since和Etag / If-None-Match,其中Etag / If-None-Match的优先级比Last-Modified / If-Modified-Since高),协商缓存由服务器决定是否使用缓存
  • 若协商缓存失效,那么代表该请求的缓存失效,重新获取请求结果,再存入浏览器缓存中;生效则返回304,继续使用缓存

作者:Gaby
链接:https://juejin.cn/post/6992843117963509791
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

作者:Gaby
链接:https://juejin.cn/post/6992843117963509791
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

作者:Gaby
链接:https://juejin.cn/post/6992843117963509791
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

作者:Gaby
链接:https://juejin.cn/post/6992843117963509791
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

 

作者:Gaby
链接:https://juejin.cn/post/6992843117963509791
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

数组遍历后找到合适的元素后怎么跳出循环

在JavaScript中,遍历数组并找到特定元素后跳出循环的方法主要有以下几种:

1‌.使用for循环和break语句‌:在for循环中,当找到合适的元素时,可以使用break语句来立即终止循环‌1。

2‌.使用while循环和break语句‌:与for循环类似,while循环也可以在找到合适元素时使用break语句跳出循环‌1。

3.使用forEachmapfilter等方法的替代方案‌:虽然forEachmap等方法无法直接通过break语句跳出循环,但可以通过其他方式实现类似的功能。例如,可以使用一个标志变量在循环内部控制是否继续执行,或者使用其他循环结构(如forwhile)代替这些方法‌

  1.  

    使用异常处理‌:虽然不推荐使用异常处理来跳出循环,但在某些情况下,可以通过抛出异常并捕获异常的方式来间接实现跳出循环的效果。这种方法虽然可以工作,但因为它改变了程序的正常流程,所以通常不推荐作为首选方法‌3。

  2.  

    使用[数组的迭代方法‌:对于特定的迭代方法,如every()some(),可以通过返回特定的值(如false对于every()true对于some())来提前结束循环。这种方法适用于这些特定的迭代方法,而不是通用的数组遍历‌3。

综上所述,最常用和推荐的方法是使用forwhile循环结合break语句来直接跳出循环。其他方法虽然可以实现类似的功能,但在使用上较为复杂,且可能引入不必要的副作用或改变程序的正常流程。JS常用的循环遍历数组的方法及跳出数组循环的方式_js数组遍历跳出循环-CSDN博客

usestate怎么拿到更改后的值 

import React, { useState } from 'react';

function ExampleComponent() {

const [count, setCount] = useState(0);

const incrementCount = () => {

setCount(count + 1);

// 使用count的下一个状态值

console.log('更新后的值:', count + 1);

};

return (

<div>

<p>Count: {count}</p>

<button onClick={incrementCount}>增加</button>

</div>

);

}

export default ExampleComponent;

在上面的代码中,当按钮被点击时,incrementCount函数会被调用,setCount会被用来更新状态。但是注意到,我们在setCount调用后立即使用count + 1来获取下一个状态值。useState的更新可能是异步的,所以你不能直接在setCount调用后立即获取更新后的值。

如果你需要在状态更新后继续使用新的值,你应该使用React提供的useEffect钩子来获取更新后的状态。这是因为useEffect会在组件渲染后执行,此时状态已经是更新过的了。




import React, { useState, useEffect } from 'react';

function ExampleComponent() {

const [count, setCount] = useState(0);

useEffect(() => {

// 使用状态更新后的值

console.log('更新后的值:', count);

}, [count]);

const incrementCount = () => {

setCount(count + 1);

};

return (

<div>

<p>Count: {count}</p>

<button onClick={incrementCount}>增加</button>

</div>

);

}

export default ExampleComponent;

在这个例子中,useEffect会在count状态变化后执行,此时你可以确信count是最新的值。

一般什么数据使用keep-alive包裹 

在Vue中,keep-alive是一个内置组件,主要用于缓存动态组件或页面,以保持其状态并避免重复渲染DOM,从而提高性能和用户体验。通常,以下几种情况的数据或组件会使用keep-alive包裹:

  1.  

    列表数据展示较为复杂,渲染速度可能较慢‌:当列表组件的渲染成本较高时,使用keep-alive可以缓存列表组件,避免在数据变化时重新渲染整个组件,从而提高性能‌1。

  2.  

    需要缓存页面或组件的状态‌:在单页面应用中,路由切换时经常需要缓存某些页面或组件的状态,以便在返回时能够迅速恢复。通过将需要缓存的路由组件包裹在keep-alive中,可以实现在路由切换时保持组件的状态和性能‌1。

  3.  

    多级导航场景‌:在具有多级导航的应用中,如从主页跳转到列表页,再从列表页跳转到详情页,使用keep-alive可以在用户从详情页返回列表页时,避免列表页组件重新渲染和重新请求数据,从而提高用户体验‌2。

  4.  

    频繁切换且需要保持状态的组件‌:对于需要频繁切换且每次切换都需要保持状态的组件,使用keep-alive可以减少不必要的渲染和性能消耗‌3。

  5.  

    动态组件‌:当页面上有多个动态组件需要频繁切换,并且每个组件的渲染成本较高时,可以使用keep-alive来缓存这些组件的实例,避免重复销毁和创建‌34。

使用keep-alive时,可以通过includeexclude属性来控制哪些组件应该被缓存。这两个属性接受组件的name作为值,而不是路由中的组件name‌2。

此外,被keep-alive包裹的组件会多出两个生命周期的钩子:activateddeactivatedactivated在组件被激活时调用,deactivated在组件被停用时调用‌23。

请注意,虽然keep-alive可以提高性能和用户体验,但过度使用也可能导致内存占用过多,因此需要根据实际情况合理使用。

作者:Gaby
链接:https://juejin.cn/post/6992843117963509791
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值