分类 前端 下的文章

这篇文章的背景就是在公司的一个项目,使用的技术栈是vue + vuecli3 + antdesign,由于早期的API接口有坑,antdesign的upload组件上传满足不了业务需求就用了iview的组件,所以当时是ant是全量引入,iview是按需引入了一个upload模块,当我们的打包出来的时候发现chunkjs很大,足足有近8m多,导致首屏加载时间很长,所以针对这一个问题通过几个方面来分析和优化。

分析模块

分析模块使用的是webpack-bundle-analyzer这个插件,按照说明的配置在plugins中即可,由于插件使用过于简单,我推荐的参考文章是
打包分析插件webpack-bundle-analyzer简介

像我所说的antdesign和iview技术栈混用这样的方式,本身就是不提倡的,所以大家在使用这个分析插件的时候,看看js文件的大小哪个是最大的,比如chunk vendors很大那就要看我们下面的配置说明来进行一步一步优化了

webpack4的splitchunks和runtimechunks (剖析被引用的js次数来缓存js)

我在看这方面的知识的时候,仅仅凭着以前一点点笔记来实践,总知踩了不少坑的;
首先来了解一下splitchunks的默认配置,这些配置讲真话不会用到全部的,很多的配置还存在着一知半解的状态下

optimization: {
    splitChunks: { // 如果这是一个空对象,那么分割的代码则是按照默认配置进行
    chunks: "all", // 只对异步或者同步或者全部的模块引入方式进行分割,all / async / initial
    minSize: 30000, // 引入的模块最小体积如果在值之类进行分割,否则不分割,这个是字节,计算/1000是kb
    // 同理还有maxSize,如果代码超出,将再次分割
    minChunks: 1, // 模块最小引入数量
    maxAsyncRequests: 5, // 最大异步并行最大请求数量,用途:控制分割的代码数量(默认是5)轻易不要更改
    maxInitialRequests: 3, // 入口并行最大请求数量,轻易不要更改
    automaticNameDelimiter: '~', // 分割代码连接字符串
    name: true, // 开启分割代码的文件名可定义(filename)
    cacheGroups: { // 缓存分组,此分组配置和chunks配置项必须是搭配,在判断引入的模块是异步还是同步之后需要走这个配置项进行分组,可以配置vendors为false
// 缓存组:顾名思义,将分割的代码暂时缓存起来,把所有匹配成功的分割代码进行整合打包在一个文件中
vendors: {
    test: /[\\/]node_modules[\\/]/,
    priority: -10, // 优先级:越小优先级越高,如果模块分别匹配条件和default成功,将通过此参数决定具体分配到哪个模块
    filename: "ventor.js" // 分割代码分组之后一起打包到哪个文件,这里设置文件名
},
default: { // 如果满足不了上面的缓存组,将执行下面的配置
    minChunks: 2, // 模块引入数量
    priority: -20,
    reuseExistingChunk: true // 如果开启了此配置,将分割代码中引入的模块(分割过的)直接引入分割后的地址,不再进行分割
    }
}
}
}

我们可以将工程中的vue,lodash,moment等等js(分析出来的比较大的js)进行分割
在缓存组可以这样写

vue: {
    test: /vue/,
    chunks: "initial",
    name: "vuw",
    enforce: true,
}

依次类推,我们的lodash和moment将会被提炼出来;

微信截图_20200607004425.png
那么从分割文件之后,我们的chunks vendors肯定会小,我们也可以加入runtimechunks来进行小文件的优化,将webpack的运行时文件进行打包,那么多个js文件将会共享这个运行时文件 runtimechunks文档

图片压缩

这一块图片压缩算是一个小小的技巧,也是通过tinypng进行的,这一节我们只讨论压缩,不讨论CDN之类的
首先tinypng有一个官网,它可以提供在线压缩免费服务的,一天也是50张压缩图片的额度且单张图片不能超过5m,一般来讲开发过程中也够用了,如果要在web服务中加入tingpng,那么需要获取key,再去npm安装相关tingpng依赖

我们来看一下无损压缩图片的压缩率和质量
微信截图_20200607002606.png

微信截图_20200607002802.png

另外说一句tinypng是提供ps插件的,价格也还算便宜,60刀,另外也有额外热心网友提供的tinypng无限制的API和压缩服务破解版tinypng

gzip服务

作为一个靠谱的前端从业者,gzip压缩技术一定要知晓并且最好会用,我们都知道在前端工程中js,css等资源在webpack的生产环境下会压缩,那么gzip技术会在这个的基础上再压缩至少百分之50以上,对webpack进行一些配置,就可以打包出来如下图的js

微信截图_20200607232243.png

并不是每个浏览器都支持gzip的,所以服务端会根据浏览器的请求头

Accept-Encoding: gzip, deflate;
这个是谷歌浏览器的支持程度,如果服务端解析请求体收到了gzip的兼容请求后会返回对应的gzip文件,反之如果不支持将会返回普通的js资源
npm i compression-webpack-plugin -d

vue.config.js配置代码:
plugins: [
  new CompressionWebpackPlugin({
    algorithm: 'gzip',
    test: /\.js$|\.html$|\.json$|\.css/,
    threshold: 10240,
    minRatio: 0.8
   })
]

后端nginx只需要简单的配置即可开启,开启方法

这里有一个小坑,vuecli2是可以支持productionGzip只需要配置true或者false即可,不需要在脚手架配置额外其他内容,但是vuecli3是需要配置的

vue路由懒加载

曾经在做路由懒加载的时候有一段时间疑惑,既然是懒加载,为什么在打包出全部js后,浏览器还需要加载全部的js呢,如图:

微信截图_20200607235625.png

那么懒加载是不是就失去了它存在的意义,当我细细研究的时候,发现在加载第一次的时候,那些原本懒加载的js都打不开
微信截图_20200607235949.png

那么继续往下研究,通过和群友的探讨,他找到了关键性的代码(真心惭愧)

  1. 首先他找到的是一句追加script的代码

微信图片_20200608000935.png

  1. 我这边找到的是每一句js都会把当前路由写入到webpackJsonp这个数组中

    (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[12]) //这里的12代表模块ID
    然后在控制台中打印webpackJsonp这个全局变量会发现

微信截图_20200608000752.png

对应的数组中不仅仅有模块ID还有对应需要加载的模块,那么如果细细看每个被懒加载的js文件就会发现其中的require函数内部其实都做了一层优化,当第二次访问此模块就从这个数组拿取上次的缓存;

__webpack_require__.e和webpackJsonp

那么对代码分割的内部异步加载模块的源码解读可以看这篇文章,这也是我在总结这篇文章的时候给我很大帮助的资料

这篇文章中出现的CommonsChunkPlugin等等概念是webpack老版本出现,新版本则是spiltchunks

IgnorePlugin忽略指定的打包模块

使用IgnorePlugin插件可以帮助我们讲不必要的内容不进行打包

let webpack = require('webpack');
plugins: [
  // 忽略解析三方包里插件
  new webpack.IgnorePlugin(/\.\/locale/, /moment/)
]

场景: moment中只引入了中文的包,可以通过这个配置进行把非中文的包去掉

OSS对象存储

这里说一下,OSS也是我近两年知道的,几年前在搭建这个博客的时候,阿里云有一些类似的活动套餐才让我了解这个东西,但是今年做开发的时候却第一次实际用到了OSS作为文件的存储服务,目前我的博客也采用了OSS作为附件资源的存储,价格也非常便宜,一年40G只需要9元

因为OSS经过了淘宝双十一的多年考验,同时OSS采用了高可用的架构设计,OSS的多重冗余架构设计,为数据持久存储提供可靠保障。
对比自建服务器存储,原始的存储方式基于硬件的影响,可能会出现各种突发问题,且人工数据的恢复有成本

安全方面oss为企业提供了很多的基础建设,加密相关

在我们这篇博客的主题,从10s到1s有很大一部分的功劳都是归于OSS

HTTP2

HTTP2在这次实践没有使用到,这块也和大家一起复习,因为在筹备这次的资料的时候,也补充了相关很多东西,在以前的HTTP1时代,前端如果被问到优化相关内容时候,一般通常会说雪碧图,内联样式,合并代码之类的,通过这些手端来达到HTTP的优化

HTTP1的一个概念叫做线头阻塞,会同时发起多个TCP请求,而这些请求都是线性流程的,一个资源下载完毕之后才能下载下一个资源,所以我们之前的优化手端“合并代码”才会非常流行,把所有的资源放在一个连接下去请求,但是在HTTP2看来,这些做法都不推荐。

微信图片_20200613223716.jpg

那么HTTP2主要有以下几个特性关乎到我们的优化

  1. 多路复用
    HTTP2允许我们将多个HTTP请求放在一个TCP连接中,避免了HTTP1中的建立多个TCP连接的开销,HTTP将会并行这些HTTP请求
  2. 头部压缩
    HTTP2减少了多个HTTP请求的开销,因为每一次的http2的请求都少于没压缩的http1的请求
  3. 流的优先级
    HTTP2可以浏览器指定接受资源的顺序,我们可以将较为重要的文件优先安排在前面
  4. 服务端推送
    服务端也可以主动推送额外的资源到客户端

那么HTTP1的优化观念是需要我们转变的呢?

【1】 不需要合并文件
不需要合并文件了,通常我们会把css放在一个文件中,js也是如此,webpack打包出来的chunk.js,合并过的css,多个图片合成的雪碧图,这样的作法太老套,如果现在这个时代还有人热衷于雪碧图,我会对此前端开发者的技术打一个大大的问号,必经这个玩意流行的时间是我入行之前都流行的(狗头)

微信图片_20200613223720.jpg

HTTP2中,合并文件虽然能压缩更多的文件体积,但是却增加了缓存的开销,一个被合并过的js,其中的内容被改变,那么浏览器承担的确是重新缓存整个合并的js,这样代价很大,而http2提倡的是【颗粒化】的传输,将多个文件的缓存利用到极致,这就是比http1好处的地方,还有一个关键的点就是在http1中你的网站可能没有全部使用合并的css和js,这样也无所谓,但是http2中加载这些没有使用过的资源,字节,是会缓慢首次加载的。

微信图片_20200613223724.jpg

我们可以将经常改动的内容js和不经常改动内容的js做一个区分,比如nodemodules打出来的chunk则是不经常改动的js,我们可以把这一块的资源进行CDN。

【2】不需要样式内联

在http1中,样式内联比如

<body style="color: red"></body>

这样单个的css不会产出新的css,浏览器不会去重新请求一个css,而是直接读取html,这样做的确可以达到优化目的在http1

微信图片_20200613223727.jpg

如图,多个HTML引入了同样的css内联,那么样式发生变化时,还需要请求多个html从服务端,这导致了用户在访问每一个页面都要额外的传输更多的东西。内联同样也会破坏优先级,因为我们在上面提到了http2是可以浏览器指定处理的优先级的,如果内联在html中,那么意味着这些css会和html同样的优先级,会导致http2的【流的优先级】没用,也就是说没按照偏好加载资源,但是在我查到的资料中,提到了

可以使用http2的服务端推送,告诉浏览器 “稍等,你刚请求的HTML页面过会渲染时会用到这些图像和CSS文件”,这样其实是和内联一样,还不会被破坏流的优先级,可以单独利用CDN缓存它们

【3】不需要细分域名
浏览器规定,单个域开通的tcp数量优先,原先为了浏览器能够并行的下载更多的资源,那么就开通多个域名,让浏览器有“并行”效果,但是http2出现了,多个域反而会造成多余的DNS查询和tcp连接,因为http2本来可以共享tcp进行多个http请求,同样的它也会破坏流的优先级,因为浏览器不会通过域不同比较其谁更优先

关于域名细分更多的内容都在参考文章中

还有很多http1和http2公用的优化手端

比如CDN,浏览器缓存

那么更重要的一点就是,http2的性能提升还是得看自己的业务,要是http请求很少,那我个人觉得没有必要

关于http2的服务端推送这个知识点我没有听说过和使用过,所以大家可以查询更多相关资料了解并且实践它们

结语

在以后的面试中,webpack,gulp等打包工具,浏览器性能,CDN,优化手端已经成为了高级前端的必考点,所以雪碧图,合并文件等等这些手端就尽量别说了,这篇文章从vue技术栈出发,讲解了企业实战的优化指南,从发现性能问题到解决性能问题提供了一系列的思路,那么这不是最终版,优化的方案远远不止这么多,希望大家一起学习,还有一些手写的图,字很丑多见谅

参考文章

关于入门了解splitchunks
webpack输出文件分析源码
oss相关优势-阿里云官网
http2性能优化指南

基于NPM的包或者库,项目中的package.json是对项目的描述,这个json对象中的script标签就是npm运行脚本,vue.js在这里配置了如下的内容

"build": "node build/build.js",
"build:ssr": "npm run build -- web-runtime-cjs,web-server-renderer", (**注意这一块是用逗号分割的**)
"build:weex": "npm run build -- weex"

vue当然有很多script命令,但是仅仅只有这几种是build的,build:ssr和build:weex其实和build一样,只不过提供了不同的运行参数

查找build的入口文件,vue是如何做build源码的?

打开对应的build/build.js

let builds = require('./config').getAllBuilds()
// filter builds via command line arg
if (process.argv[2]) {
  const filters = process.argv[2].split(',') (**分割出来的数组是["web-runtime-cjs","web-server-renderer"]** )
 // 通过getAllBuild函数返回的config对象对其打包模式进行了rollup的配置,包括output等设置
 // 而下面这一段代码的b则是返回的config对象,filters这个参数数组使用some来判断builds中output中的file(被resolve函数定义了,这个resolve函数下面会具体讨论)
  builds = builds.filter(b => {
    return filters.some(f => b.output.file.indexOf(f) > -1 || b._name.indexOf(f) > -1)
  })
} else {
  // filter out weex builds by default
  builds = builds.filter(b => {
    return b.output.file.indexOf('weex') === -1
  })
}

这一段代码其实非常简单,作者也在源码中写了注释解释了这段代码的作用

通过命令行arg构建过滤器

其中引入的config 文件调用了getAllBuilds这个方法,在config.js可以看出

 exports.getAllBuilds = () => Object.keys(builds).map(genConfig)

这一句代码是导出config的关键代码,builds是预定义的一些对象

 // runtime-only build (Browser)
  'web-runtime-dev': {
    entry: resolve('web/entry-runtime.js'),
    dest: resolve('dist/vue.runtime.js'),
    format: 'umd',
    env: 'development',
    banner
  },
entry: 入口文件
dest: 输出目标文件
format: 构建的格式 umd为umd格式 cjs遵循commonJS规范 es遵循esmodule规范
env:开发模式/生产模式
banner指的是每个js的页头,比如作者,信息,开源协议等信息
还有其他的一些关于rollup(很像webpack的一些设计)别名诸如此类的配置,这边就不阐述了,因为我也忘记的差不多了,文档都很好查,想知道具体的意思也很容易

resolve函数的定义

这里的resolve函数比较简短,很容易理清

//假定一个config中使用resolve这个函数,它传递的字符串是这样的
'web-runtime-cjs': {
    entry: resolve('web/entry-runtime.js')
  }

const resolve = p => {
  const base = p.split('/')[0]
  if (aliases[base]) {
    return path.resolve(aliases[base], p.slice(base.length + 1))
  } else {
    return path.resolve(__dirname, '../', p)
  }
}

首先base则是 “web”这个字符串,
这个base并不是真实的路径,而这个web则指向了aliases的配置

module.exports = {
  web: resolve('src/platforms/web'),
}

这里的web指向的路径就是src/platforms/web
那么resolve函数返return的就是path.resolve,其中第一个参数就是web,第二个参数则是entry-runtime
所以由此得知,通过这样的一个过程找到了build的入口文件然后经过rollup的打包就会在dist目录下生成web/entry-runtime.js

拓展阅读

Runtime Only VS Runtime + Compiler 推荐阅读

在初级和中级前端面试笔试中,函数的防抖和节流要求候选人有能力去精通或者熟悉里面的机制,不仅仅要知道基本版的防抖和节流,还要知道更完美进阶的节流防抖,比如一些lodash中的实现等等,所以这个系列也是从基础版开始,我会和大家一起补充这方面的知识


配套代码地址在线调试和编辑
参考文章

防抖

【背景故事】
某商业楼每天早上上班高峰期的电梯非常堵,通常生活来讲,一个电梯肯定是要进去很多人的直到人满为止,这对于自身和电梯都是一种节约资源的表现,不可能出现每个人一人一个电梯的情况,所以对于电梯和我们,这是一种防抖函数的表现。

电梯每当停到一个楼层,会等我们进去,人没有塞满或者没有人它才会到达指定楼层。
在web端最容易遇到的就是input搜索,用户输入一个字符,会在指定的时间中监听是否还有字符进入,如果没有,那么就执行对应的函数,这样就解决了用户频繁输入字符而前端发起请求给服务器造成压力的问题
// 防抖函数
function debounce(fn, time = 300) {
  let timer = null;
  return function() {
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, arguments);
    }, time);
  };
}

基础版的代码梳理,通过这个函数将fn传递,就能实现防抖的效果,当用户输入的第一个字符,会把timer函数赋予一个延时器,这个延时器执行了对应的fn,this是为了绑定执行的this指向,arguments则是这个函数的参数类数组对象,当用户在延时还未触发的时候再次输入字符,那么clearTimeout把上一个timer清除掉了,因为闭包的作用,timer不会被销毁,这样的一个函数就表示了,只要在延时间隔中(此时timer被赋值了),如果谁再调用此函数,会把上一个timer清空掉,重新延时,依次类推...

节流

【背景故事】
在0几年的时候包括可能现在都有,很多家庭知道水管把阀门开到最小,让水一滴一滴的掉下,是不会走水表的(不计费的),所以在我很小的时候就知道这个事情,虽然现在没有了,但是还是觉得很羞愧,节流函数就是起到的作用就是,把原本频繁的调用变得有秩序有间隔;

以监听scroll滚动为例:

// 节流函数
function throttle(fn, time = 300) {
  let canRun = true;
  return function() {
    if (!canRun) return;
    canRun = false;
    setTimeout(() => {
      fn.apply(this, arguments);
      canRun = true;
    }, time);
  };
}

$(window).on(
  "scroll",
  throttle(() => {
    console.log("触发了scroll");
  }, 300)
);

在这个函数中,canRun这个变量变化了3次,判断了一次如果为false就return掉

  1. 初始化时设置为true
  2. 判断canRun是否为false后设置了canRun为false
  3. 最终事件执行完毕之后设置canRun为true,否则就进入不了下一次的节流

其实这个函数从开始到结束的canRun形成了一次循环,这个循环唯一保证的就是只有事件结束才可以开始下一个事件

总结

节流:保证回调能在指定的时间间隔中依次有规律的执行
防抖:保证回调能在指定的时间间隔中等待是否有再次执行回调,如果没有则执行,如果有则重置继续等待;

我说我过年期间更新了3篇关于uniapp的文章,然后发布莫名消失,你们会信么?

timg.jpg

其实是真的,家里的网络非常不稳定,我连续发了2次文章,结果预览出来的效果仅仅只有一个自然段,剩余全部丢失,所以渐渐的我心态崩掉了,然后转眼就来到了4月,我仍然会每周坚持更新笔记/感悟,分享给大家。

这是一个全新的计划,关于分析vue的源码,那么我需要一个课程带着我学习,因为讲真,它有些门槛,像我第一次看底层源码,不知道从何看起,网上有太多的关于vue的实现,比如methods,computed实现,但是都太单一,所以我在youtube上找到课程,也是慕课网的金牌讲师ustbhuangyi

所以我会把这个课程参考的资料放到这个文章的顶部
他的博客,vue源码资料
正版课程,请大家看完一定要去购买支持正版,虽然我没购买
youtube免费课程,高清,可以翻墙免费看全集


这边配套的源码截止于目前文章发表的日期,版本是2.6.11,大家在学习vue源码的核心内容的时候,只要是2.0版本的最新的内容,基本上不会影响学习vue.js的灵魂。


首先来了解一下看到这个标题,这篇文章就简单的看一下vue的src源码中的目录分工,我们在写一般的vue工程时,也会分很多很多的文件进行模块化开发,这是大势所趋,比如api;common;util;components;assets;static;pages等等,那么在框架开发中,一般像我一样的初学者就很懵逼,所以我们一起来看看;

compiler

这是vue.js编译相关的代码,它包括把vue模板编译成AST抽象语法树,一般情况下,编译会在构建时进行,因为是很耗费时长的,像webpack或者vue-loader这样的插件;

core

这里的目录是vue.js的核心之处,我们所见到的2.0新特性的vdom,监听,状态,初始化,render等等都在这里

platforms

我们一般常用的vue.js是在web端,那么vue.js也支持编译成供weex这样的运行在native上的框架
这个目录就是vue.js针对不同的平台而编译的入口

server

vue.js支持服务端渲染内容,即这里的目录是在node中进行运行的,服务端运行将返回html字符串进行渲染,这里是在服务端的vue.js而不是web端的vue.js

sfc

这里的parser.js会把编写的.vue文件转换成js对象

shared

vue.js用到的公共的方法,它将是所有的目录公共可访问的内容


这两天会根据计划更新其他的内容,这个部分会一直进行下去,不定时更新

写在前面,很久没有整理面试,笔试题了,这次准备了2个月的题,理论来讲是一天3道,一共是180道题,我们这篇文章会自动跳过一些之前说过的题,尽量挑重要的整理

src、href、link的区别是什么?

src:指的是指向资源,比如srcipt和img标签使用src来表达资源路径
href:指的是指向路径,比如a标签,表达了跳转的路径
link:指的是css中的link,用来表达层叠样式表的资源路径

这三者都不受同源限制影响

多维数组扁平化

1. arr.toString().split(",");
2. arr.flat(Infintity); // 多维转换,参数表示正无穷,写1就是只转换一维,写2转换2维......

3. return arr.reduce((prev, current) => {
    return prev.concat(Array.isArray(current) ? 递归函数(current) : current)
},[])

有用过HTML5的webSQL和IndexedDB吗?说说你对它们的理解

没有用过,但是websql是被废弃的,现在大多数都使用indexedDB,空间大,存储多,可以异步存储,支持键值对,也支持js对象

怎样把一个div居中?怎样把一个浮动元素居中?怎样把绝对定位的div居中?

margin 0 auto
transform
margin-left clac(50% - width/2)
position: absolute left: 0 top: 0 bottom 0 top 0 ; margin 0 auto
flex
grid
table

写一个方法获取图片的原始高度和宽度

用异步,new image对象,监听onload并取naturalWidth和naturalHeight即可,记得赋值src给img

有使用过html5的拖放API吗?简单说一下

简单使用过,img标签默认可拖拽,其他标签需要开启拖拽开关drage=true
h5提供了一系列元素的监听事件,可以用拖拽事件来做出一些有趣的效果

有用过HTML5的WebWork吗?它主要解决了什么问题?

js是单线程语言,webwork允许我们注册一个服务,让这个服务在一个单独的线程进行处理,不会影响到主线程,大大提高了js的
复杂业务执行效率
但是在这个线程中,

  1. 必须是和主线程是同源
  2. 没有parent,window,document不能更改dom,navigator和location是可以用的
  3. woker和主线程必须通过消息进行传递
  4. 没有alert等,可以发送ajax请求
  5. 不能加载本地文件,资源必须来源于网络

说说你对同构和SSR的理解(理解,简单过一下)

同构,就是一套代码能在客户端允许也能在服务端允许
ssr就是为了爬虫的需要/框架初始化/单页面的卡顿,在service端把数据处理好返回给页面
优点:首页加载快,seo好,请求次数减少

ssr和spa不是相对概念
spa和mpa是相对概念,多页应用在以前非常火,有多个前端入口,路由后端控制等,比如php和jsp都是经典的mpa应用

说说position的absolute和fixed共同与不同点分别是什么?

都脱离了文档流
一个是可以相对父元素,一个是相对于浏览器

举例子说明javascript的变量声明提升和函数声明提升

var a = funtion a(){
    console.log(4)
}
funtion a(){
    console.log(5)
}

console.log(a()) // 4

html直接输入多个空格为什么只能显示一个空格?

该行为由css的white-space控制,默认值normal会把多个空格压缩成一个空格

HTML5如果不写<! DOCTYPE html> ,页面还会正常工作么?

可以,只不过浏览器会以自己默认的规则进行加载网页,每个浏览器的规则都有区别
所以会造成多个浏览器不兼容的情况

元素竖向的百分比设置时相对容器的高度吗?

不是,如果是的话,那么高度是相对高度,父元素根据子元素的高度会自动撑开,然后子元素
知道父元素撑开为了百分比要去弥补这个差距,会造成一个死循环

所以是相对容器的宽度不是高度

请写出唤醒拔打电话、发送邮件、发送短信的例子

<a href="tel: 110">拨号</a>
<a href="sms: 110">发短信</a>
<a href="emilto: 1018715564@qq.com">邮箱</a>

写个例子说明HTML5在移动端如何打开APP?

原理deeplink
使用a标签中的href="应用名称(问具体开发)://"

css和动画和js动画区别

1. 性能不差
2. 部分场景下优于js
3. 比较多的兼容问题

怎样禁止表单记住密码自动填充?

autocomplate="off"

请说说*{box-sizing: border-box;}的作用及好处有哪些?

怪异盒模型,会把border,padding算在盒子的宽,比较符合人类的认知

对base64的理解

上传图片可以用base64上传
url参数加密也可以用base64

html的a标签属性rel='nofollow'有什么作用

告诉爬虫不要爬链接中的内容了

Ajax请求中get和post方式有什么区别呢?分别在哪些场景下使用?

get参数内存小,因为是通过url传参,浏览器的url参数有限制
get请求参数会暴漏在用户表面
get请求可以被历史记录

get请求通常是获取一个仅读资源

怎么在IE8及以下实现HTML5的兼容?

使用这个插件html2shiv, 原理就是创建element

写一个字符串重复的repeat函数

repeat函数
使用array.join();
循环拼接变量,然后循环完毕返回
循环放入数组,输入变成字符串返回

在实际编写css中你有遇到过哪些浏览器兼容性的问题?怎么解决的?

低版本得IE的CSS特效等

postcss autoprefixer,browerlist

移动端点击事件为什么会有延迟?有哪些方法可以解决?

因为早期的浏览器规定的就是,点击一下,如果300ms之内又点了第二下会放大屏幕

那么解决办法就是不让他放大,设置meta标签,禁止缩放
还有就是使用fastclick这个库,原理:可以在点击的第一下上生成一个div并且触发点击事件然后把默认事件屏蔽掉

在a标签上的四个伪类执行顺序是什么?

link visited hover active 记忆法:lvha(lv好)

说说你对!important的理解,一般在哪些场景使用?

不建议使用,提高css样式的最高权重,非常不利用维护

写一个方法随机生成指定位数的字符串

Math.random().toString(36).substr(2); .// 生成一个随机字符串

请你解释下什么是浮动和它的工作原理是什么?同时浮动会引起什么问题?

浮动会脱离标准文档流, 浮动元素会互相紧贴,可能会造成高度塌陷

js中=、==、===三个的区别是什么?并说明它们各自的工作过程

=赋值操作
== 比较值,会隐式转换,简单比较
=== 不仅会比较值,还会比较内存地址,复杂比较

transition、animation、transform三者有什么区别?

1. 过渡:无非就是图像元素在做偏移/变化时,过渡动画能更好的让用户接受,不再生硬
2. 自定义动画:可以让开发者逐帧操控动画,可玩度更高
3. 图像转换移动: 2d,3d移动,放大缩小等等都是经典的场景

请写出如下代码运行的结果并解释为什么?[代码]

代码是这个:

var type = 'images';
var size = {width: 800, height: 600};
var format = ['jpg', 'png'];

function change(type, size, format){
    type = 'video';
    size = {width: 1024, height: 768};
    format.push('map');
}
change(type, size, format);
console.log(type, size, format);

change中的更改几个变量,都是更改的行参的值,而传递的format,push更改了原数据,所以只有数组增加了,其他都没变化

你在工作中有用到过websocket吗?用它来解决什么问题?

用到过,聊天的时候做过,兼容不太好,但是有解决方案,用于客户端和服务端进行互相推送的功能,解决了传统的推送传输耗费性能

遇到overflow: scroll不能平滑滚动怎么解决?

ios: -weibit-overflow-scorlling:touch;

举例说明数组和对象的迭代方法分别有哪些?

es5: for,forEach,some,reduce,reduceRight,map,for-in,every,filter
es6: for-of,find,findIndex
对象:
es5: for-in,Object.keys()
es6: Object.entries(); Object.values();

请快速答出此题的答案并解释:var x, y = 1; x + y = ?

NaN, y是等于1 ,x只是定义了没赋值 undefined+1=NaN

HTML5的应用程序缓存与浏览器缓存有什么不同?

浏览器缓存提供的就是单个文件的缓存,而HTML5的PWA中的离线缓存技术是整站缓存,即没有存在网络也可以访问网站,基于service-woker标准实现

说说你对BEM规范的理解,同时举例说明常见的CSS规范有哪些?

指的是css命名规范,bem认为所有的网页是一个一个块组成的,block,element,modifier(修饰语)
header-button-primary 类似于这样

举例说明什么是IIFEs?它有什么好处?

立即执行函数

(funtion(){
    // code something
})();

也可以这样哦!function(){}(), ~function(){}()  let a = function(){}()

节约变量,独立作用域,立即运行

简述下HTML的快捷键属性是哪个?并举例说明有什么用?

accesskey,h5支持每个元素都可以注入accesskey,搭配浏览器快捷组合键,实现快速访问的功能

这无疑推广了无障碍的发展,让更多不健全的人也能更方便使用web网页

举例说明什么是decodeURI()和encodeURI()是什么?

对内容进行解码,对内容进行加码

你有用过HTML5的Device API吗?说说它都有哪些应用场景?

没有用过,听说过,是html5的一种规范api,可以监听手机屏幕亮度,电量,振动,打电话之类的‘

js实现99乘法表

function nine(num){
for(var i = 1;i<=num;i++){//控制行
var expression = "";
for(var j = 1;j<=i;j++){//j<=i 控制每行的个数
expression +=`${j}*${i}=${i*j}`;
}
console.log(expression)
}
}
nine(9);

在新窗口打开链接的方法是什么?那怎么设置全站链接都在新窗口打开?

target="_blank";

a标签下的href =“ javascript:void(0)”实现了什么作用?说说你对javascript:void(0)的理解?

void是js的一个关键字,表示没返回值,这句代码主要是不让a链接产生跳转(默认行为)

如何理解同源策略

同源策略就是浏览器的一种安全策略,避免和不安全的资源进行通信

1. 不同协议
2. 不同域名
3. 不同端口

解决办法: cors jsonp proxy代理等

怎么让body高度自适应屏幕?为什么?

html,body{height: 100%} 把html带上是因为,如果只给body加不是真正的高自适应,因为会继承html的高度,html高度未必是100%,所以两个都要加100%
body{height: 100vh} vh不会继承父类,直接是视口的高度

js延迟加载的方式有哪些?

async defer setTimeout 动态绑定src 动态创建script标签

display有哪些值?分别说明他们的作用是什么?

table
flex
grid
inlie-block
none
block

把Script标签放在页面最底部的之前和之后有什么区别?浏览器会如何解析它们?

肯定是一个优先解析,一个等文档加载完再执行,在body前,script标签加载的js文件会阻塞html的渲染,所以一般会写在body后,或者给标签加入async 或者 defer 或者type="module"来异步加载js文件

写出几个初始化CSS的样式,并解释说明为什么要这样写

padding 0 margin 0 outline: none;
文档有默认的外边距和内边距,需要清除,还有点击按钮的时候会有点击的边框,a标签的默认样式,列表的默认样式等等

请写一个sleep(暂停)函数

function sleep(ms) {
      return new Promise((resolve, reject) => {
        setTimeout(resolve, ms);
      });
}

说说你对CSS样式覆盖规则的理解

关键词: ICE公式 特指度
有一个概念叫做特指度,也就是平时所说的权重大小,每一个选择器都有一个权重值,id=100 class=10 标签是1,这个公式叫做ICE,
通配符最小
最高权重是important,通常在项目中蛮少使用到,因为维护性很差

判断instanceof的结果并解释原因 [代码]

代码如下:

function test(){
   return test;
}
new test() instanceof test;

instanceof 的运行原理是右边的priototype去左边的原型上去找,左边的原型链找完还没有就返回false,这段代码new出来的构造函数结果就是构造函数本身,因为有继承,所以继承了所有的
test方法的属性,所以test.protype并不在test()上存在,所以返回false

CSS的overflow属性定义溢出元素内容区的内容会如何处理呢

visble 超出将会显示元素外面
scorll 超出显示滚动条
hidden超出部分不显示
auto 内容溢出时候是scroll

请描述下null和undefined的区别是什么?这两者分别运用在什么场景?

null和undefined都不是对象
null是空
undefined 变量已定义未被赋值

一般初始化变量会初始化成null,因为undefind的情况很多,而且根据代码语义,未被定义不符合标准
因为未被定义的变量就是undefined,赋值undefined是一个多此一举的事情

解释下为什么{} + [] === 0为true?

{} 是混淆项,不参与运算,+[] === 0是true  那么{}被认定为语法块
+[] === 0 是类型转换


console.log包裹{}会被解析成一个对象,不会解析成一个语法块

在不固定高度的情况下水平垂直居中的方法?

万能定位法
定位50% 通过margin或者transform移动-50%
flex

js的函数有哪几种调用形式?

fn()
fn.apply call bind
new fn();

obj.fn();

当一个元素被设置为浮动后,它的display值变为什么呢?

变为block,设置浮动看样子是inline-block,其实是block
可以通过getComputedStyle查看属性

写出js的交集并集补集差集

/** *交集 * * @param {*} arr1 * @param {*} arr2 */function intersection (arr1, arr2) {
  return arr1.filter(v => arr2.includes(v))
}


/** *差集 * * @param {*} arr1 * @param {*} arr2 */function difference (arr1, arr2) {
  return arr1.filter(v => !arr2.includes(v))
}


/** *并集 * * @param {*} arr1 * @param {*} arr2 */function union (arr1, arr2) {
  return [...arr1, ...arr2]
}


/** *补集 * * @param {*} arr1 * @param {*} arr2 */function complement (arr1, arr2) {
  return difference(union(arr1, arr2), intersection(arr1, arr2))
}

Doctype有什么作用?你知道有多少种Doctype文档类型吗?(理解)

声明文档类型,告诉浏览器以什么标准进行解析,如果不提供,浏览器将会自动根据厂商标准去补充

一般会使用
<! doctype html>

html4则有3种:

Strict,Transitional和Frameset;

写例子说明如何给li绑定事件(ul下有1000+个li)?

利用事件委托

function handleClick(event){
    if(event.target.tagName === "LI"){
        // do something
    }
}

监听ul的点击事件即可

移动端微信页面有哪些兼容性问题及解决方案是什么?

1. rem方案,需要使用reset.js
2. video标签层级最高,解决是获取了video的第一帧图片作为预览图,替换video

说说你理解的同步和异步的区别是什么?

1.    上一个任务结束才能进行下一个任务。比如alert弹窗,不点击确定永远在哪里,阻塞了下面的所有同步js代码
2.    可以按顺序开始,但是不一定按顺序返回,比如img加载图片就是典型的异步

如何让大小不同的图片等比缩放不变形显示在固定大小的div里?写个例子

object-fit这个属性非常好用
设置宽高定位

如何让大小不同的图片等比缩放不变形显示在固定大小的div里?写个例子

读分2种,一种是看,一种是读取里面的信息

看:chorme有自带的pdf预览插件,直接src
读:读pdf,二进制数据,根据pdf的规则去解析(pdf是开源格式),然后再根据解析出来的通过html或者canvas去渲染(难点),然后pdf中的图片可以使用二进制提取然后bloburl
做为链接
pdf.js的原理

行内元素、块级元素、空(void)元素分别有哪些?

    1. span a input img b strong select button em
    2. div video selection header footer article h1-h6 table form
    3. img input br hr

准确说出'1,2,3,4'.split()的结果是什么(包括类型和值)?

["1,2,3,4"] 如果split没传参数,会返回调用值为第一个数的数组

进程与线程有什么区别?JS的单线程带来哪些好处?

一个程序必定包含一个进程,一个进程必定包含一个线程
一个进程必定包含一个线程

进程之间不能共享内存,而线程可以

js最早是面向浏览器的脚本语言,开发者在对dom做处理时,如果是多个线程,引擎就不知道时哪个线程做了操作,这样的程序会很紊乱
因此js是要和用户实时交互的,所以是单线程

在一些复杂业务中,我们也可以使用web-woker来做计算处理,但是它不能操作dom

请列举出多种减少页面加载时间的方法(答案来源于github某网友)

• 缓存利用: 缓存 Ajax,使用 CDN、外部 JavaScript 和 css 文件缓存,添加 Expires 头,在服务器端配置 Etag,减少 DNS 查找等。
• 请求数量.合并样式和脚本,使用 css 图片精灵,初始首屏之外的图片资源按需加载,静态资源延迟加载。
• 请求带宽:压缩文件,开启 GZIP 。
• css 代码:避免使用 css 表达式、高级选择器、通配选择器 。
• JavaScript 代码:用散列表来优化查找,少用全局变量,用 innerHTML 代替 DOM 操作,减少 DOM 操作次数,优化 JavaScript 性能,用 setTimeout 避免页面失去响应,缓 存 DOM 节点查找的结果,避免使用 with (with 会创建自己的作用域, 增加作用域链的 长度),多个变量声明合并。
• HTML 代码:避免图片和 iFrame 等 src 属性为空 。 src 属性为空,会重新加载当前页面 , 影响速度和效率 , 尽量避免在 HTML 标签中写 Style 属性。

怎么实现移动端的边框0.5px?

伪元素+缩放,宽高是原dom的百分之200,然后缩小.5可以实现
兼容高分辨率的屏幕

border.css的原理

写个方法,找出指定字符串中重复最多的字符及其长度

const str = "啦啦啦哈哈哈哈";
let result = {}; // 存放全部的结果集的数组

function test1(box = []){
// 转换数组
let array = str.split("");
array.forEach(v => {
if(typeof result[v] === "undefined"){
// 添加对应的属性
result[v] = 1;
}else{
result[v] ++;
}
})
}

test1();
console.log(result);

网站的TDK该怎么设置?它有什么作用?

TDK: 标题 & 介绍 & 关键词
seo的最重要的三要素,网站如果设置好这三要素将会提升被蜘蛛抓到更多的内容,有更多的曝光

请描述下js的原型和原型链的理解以及它们之间的关系

js的继承就是原型的继承
每一个对象都有原型,而这个原型分为隐式原型和显式原型
比如Function的prototype,指向的就是函数的原型,而原型中的 constructor即构造函数指的就是函数本身
对象的原型是_proto_即隐式原型,指的是创建该对象的函数的原型

原型是原型链的一部分,每一个对象都有原型,都会有共同的属性,如果直到原型是null,说明是最顶层的原型,那原型链即如此

请描述下什么是原型模式?它主要运用在哪些场景?(理解)

原型模式是一种设计模式,就是创建一个共享的原型实例,通过拷贝这些原型创建新的对象,也就是创建一个对象作为另一个对象的Prototype属性。

优点:用于创建重复的对象,可以提升性能。
结合优点,可以运用在以下几种场景:
1、类初始化需要消耗很多资源
2、有多个调用者调用且每个调用者会修改其值,相当于保存一份原有的对象拷贝相同对象进行修改,即保护性拷贝
3、通过new对象时需要很多繁琐的准备或访问权限

请详细描述AJAX的工作原理(答案来源于github网友)

AJAX是用于网页和服务器进行异步通信的技术。
基本原理是,通过XMLHttpRequest向服务器发送异步请求,获得服务器返回的数据,利用js更新页面。
其核心功能在于XMLHttpRequest对象。
创建一个ajax的步骤大致可以分为以下几步

  • 创建XHMHttpRequest对象
  • 打开链接 (指定请求类型,需要请求数据在服务器的地址,是否异步i请求)
  • 向服务器发送请求(get类型直接发送请求,post类型需要设置请求头)
  • 接收服务器的响应数据(需根据XMLHttpRequest的readyState属性判定调用哪个回调函数)
  • 更新页面

HTML如何创建分区响应图?

什么是分区相应图:

一张图片,可以把它分割成多个区域,点击图片的不同区域就会跳转到不同的url,这就是分区相应图
这种功能开发中应该很常见,尤其是APP中的引导页,当只有一张整素材的时候,需要前端确定用户点击了某处的按钮,我称之为幽灵按钮
但是通过分区相应图可以很快的实现这种效果

通过map和area实现

<p><img src="blue.png" usemap="#myMap" alt="Blue Map"/>3 </p>4 
<map name="myMap">5   
 <area href="area1.html" shape="rect" coords="5,8,30,32" alt="area1" />6    
 <area href="area2.html" shape="rect" coords="34,8,50,32" alt="area2" />7   
 <area href="other.html" shape="default" alt="default"/>8 
</map>

使用js编写一个红绿灯的程序:

function sleep (t) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve()
    }, t)
  })
}


/** * 循环显示红绿灯 * @param {number} green 绿灯显示毫秒数 * @param {number} yellow 黄灯显示毫秒数 * @param         {number} red 红灯显示毫秒数 */async function light (green = 15000, yellow = 3000, red = 10000) {
  let status = 'green'
  while (true) {
    await sleep(green).then(() => {
      status = 'yellow'
      console.log(status)
    })
    await sleep(yellow).then(() => {
      status = 'red'
      console.log(status)
    })
    await sleep(red).then(() => {
      status = 'green'
      console.log(status)
    })
  }
}


light(3000, 1000, 1000)