JavaScript相关
Promise常见API
Promise.all()
会在任何一个输入的Promise被拒绝时立即拒绝,并带有第一个被拒绝的原因可以想象为Array.prototype.every()
js
function myPromiseAll(array) {
return new Promise((resolve, reject) => {
if (array && typeof array[Symbol.iterator] === 'function') {
let arrayLength = array.length
let resultArray = []
array.forEach((value, index) => {
Promise.resolve(value).then((res) => {
resultArray[index] = res
if (resultArray.length === arrayLength) {
resolve(resultArray)
}
}, (err) => {
reject(err)
})
})
}
})
}
Promise.allSettled()
会等待所有的Promise完成,不管是否拒绝
js
function myPromiseAllSettled(array) {
return new Promise((resolve, reject) => {
if (array && typeof array[Symbol.iterator] === 'function') {
let arrayLength = array.length
let resultArray = []
array.forEach((value, index) => {
Promise.resolve(value).then((res) => {
resultArray[index] = res
if (resultArray.length === arrayLength) {
resolve(resultArray)
}
}, (err) => {
resultArray[index] = err
if (resultArray.length === arrayLength) {
resolve(resultArray)
}
})
})
}
})
}
Promise.any()
返回第一个兑现的值,当所有都被拒绝时,会以一个包含拒绝原因数组的 AggregateError 拒绝
js
function myPromiseAny(array) {
return new Promise((resolve, reject) => {
let arrayLength = array.length
let errList = []
if (array && typeof array[Symbol.iterator] === 'function') {
array.forEach((value, index) => {
Promise.resolve(value).then((res) => {
resolve(res)
}, (err) => {
errList[index] = new Error(err)
if (errList.length === arrayLength) {
reject(new AggregateError(errList))
}
})
})
}
})
}
Promise.race()
接受一个iterable
,返回一个随着第一个promise敲定的promise,当传入的iterable
为空时,返回的promise会一直保持在待定状态Promise.resolve()
将给定的值转换为一个Promise。如果值本身就是一个Promise,那么该Promise将被返回;如果该值是一个 thenable 对象,Promise.resolve()
将调用其then()
方法及其两个回调函数;否则,返回的 Promise 将会以该值兑现。
原型链相关问题
TypeScript相关
never,unknown,any,void区别
any:JavaScript转TypeScript的银弹
当我们将某个变量定义为any后,TypeScript将会跳过对这个变量的类型检查
typescript
let something: any = 'Hello World!'
something.notExistMethod() // ok!
something.notExistProperty.name() // ok!
something = false //ok
使用场景:
- 代码迁移:在JS向TS迁移的过程中,可以采用any来快速的推进重构,但这只是一种临时方案,千万不能写成AnyScript
- 类型确缺失或者补全困难,一般发生在使用了第三方JS编写库的时候,因为没有很好的TS适配,导致我们无法准确定义某个类型,这是可以使用any去暂时规避这类问题
unknown:any的安全替代品
any会跳过所有的TS类型检查,这会为后续代码的维护埋下巨大的安全隐患,为了解决any的问题,TS在3.0版本引入了unknown类型,可以简单理解为类型安全的any
和any一样,任何类型都可以赋值给unknown类型,但不同的是,unknown类型不可以直接赋值给其他非unknown或any类型的对象,并且不可以访问上面的任何属性
typescript
let vAny: any = 'Hello World!'
let vUnknown: unknown = 'Hello World!'
let vNumberForAny: number = vAny // ok! any可以直接赋值给其它任意类型
let vNumberForUnknown: number = vUnknown // error! unknown不可以直接赋值给其它非any和unknown类型的对象
vAny.toLocaleLowerCase() // ok! any可以访问所有的属性
vUnknown.toLocaleLowerCase() // error! unknown对象不可以直接访问上面的属性
如果想要使用unknown,那就必须先推导出unknown的类型,比如typeof
typescript
let vUnknown: unknown = 'abc'
// 使用typeof推断出vUnknown的类型是string
if (typeof vUnknown === 'string') {
vUnknown.toLocaleUpperCase() // ok! 因为能进入这个if条件体就证明了vUnknown是字符串类型!
}
let vNumberForUnknown: number = vUnknown as number // unknown类型一定要使用as关键字转换为number才可以赋值给number类型
unknown基本可以替代any,所以在使用any的场景,都应该优先使用unknown。使用了unknown后,我们既允许某个对象储存任意类型的变量,同时也要求别人在使用这个对象的时候一定要先进行类型推断。
never
never是TypeScript的底部类型,是一个不存在,不可能发生的类型
never类型只接受never类型,any都不可以赋值给never
ts
let vAny: any = 1
let vNever: never = vAny // error! never除了自己谁不都接受!
function test(a: number | string) {
if(typeof a === 'number') {
console.log(a)
} else if (typeof a === 'string') {
console.log(a)
} else {
let check: never = a //永远无法到达,因此a的类型为never
}
}
never类型可以很好的帮助我们在未来添加某一个类型时能够检查到代码的逻辑漏洞
ts
function test(a: number | string | boolean) {
if(typeof a === 'number') {
console.log(a)
} else if (typeof a === 'string') {
console.log(a)
} else {
let check: never = a // error! boolean无法赋值给never
}
}
void
void可以理解为null和undefined的联合类型,它表示空值,一般不用于声明值的类型,更常见的场景是表示某个函数没有返回值
注意与never的区别
ts
function noReturn(): void {
console.log('hello') //函数可以正常结束,无返回值
}
function Never(): never{
while(true){} //函数永远无法结束
}
function error(): never{
throw new Error('this function will crash')
}
Vue相关
Vue样式隔离scope
Vue组件之间没有做到样式隔离,Vue中的样式隔离,是通过scoped
属性来实现的。当在<style>
标签上使用scoped
属性时.基本原理概括为以下几个步骤:
- 为当前组件模板的所有DOM节点添加相同的attribute,添加的属性与其他的scope不重复,data属性(形如:data-v-123)来表示他的唯一性。
- 在每句css选择器的末尾(编译后的生成的css语句)加一个当前组件的data属性选择器(如.ipt input[data-v-123])来私有化样式
- 如果组件内部包含有其他组件,只会给其他组件的最外层标签加上当前组件的data属性
也是因为这个原因,所以在scoped中尝试选择子组件样式,会因为额外的属性选择器导致无法正确选择
:deep通过改变hash属性选择器的位置,来让vue的样式可以正确的选择到子组件,也就完成的样式穿透
Webpack相关
Webpack的几个关键概念
- Entry(入口):Webpack将从指定的入口文件开始分析和构建依赖关系树
ini
module.exports = {
entry: './path/to/my/entry/file.js',
};
- Output(输出):指定Webpack打包后的文件输出路径和文件名
lua
module.exports = {
...
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js',
},
};
- Loader(加载器):Webpack本身只能处理
JavaSript
,但通过Loader可以加载各种各样的文件处理模块 以下是一些常用的Webpack loader及其作用:
babel-loader
:将ES6+代码转换为ES5语法,以便在旧版本的浏览器中运行。style-loader
和css-loader
:用于处理CSS文件。css-loader主要负责处理样式文件中的import
和url
语句,而style-loader将转换后的CSS模块直接注入到HTML页面中。file-loader
和url-loader
:用于处理图片和其他资源文件。file-loader会为每一个文件生成一个对应的文件,而url-loader将小于设定大小的文件转换为base64编码的URL,减少HTTP请求。sass-loader
和less-loader
:用于处理Sass和Less预处理器。它们将Sass和Less代码转换为普通的CSS代码。postcss-loader
:用于为CSS代码添加浏览器兼容性前缀,以确保在不同浏览器上的一致性。html-loader
:用于处理HTML文件,将其中的图片等资源转换为Webpack可以识别的模块。
css
module.exports = {
...
module: {
rules: [{ test: /.txt$/, use: 'raw-loader' }],
},
};
- Plugin(插件):用于扩展Webpack的功能,可以在打包的不同阶段执行特定的内容。通常我们在Webpack中引入并实例化,然后加入到plugins数组
arduino
module.exports = {
plugins: [new HtmlWebpackPlugin({ template: './src/index.html' })],
};
- Mode(模式):通过选择
development
,production
或none
之中的一个,来设置mode
参数,可以启用 webpack 内置在相应环境下的优化。其默认值为production
选项 | 描述 |
---|---|
development |
会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 development . 为模块和 chunk 启用有效的名。 |
production |
会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 production 。为模块和 chunk 启用确定性的混淆名称,FlagDependencyUsagePlugin ,FlagIncludedChunksPlugin ,ModuleConcatenationPlugin ,NoEmitOnErrorsPlugin 和 TerserPlugin 。 |
none |
不使用任何默认优化选项 |
Webpack中,什么是代码分离(code splitting)和懒加载(lazy loading)
代码分离是将打包生成的代码文件拆分成多个较小的文件,而不是将所有代码打包到一个文件中
代码分离可以提高初始加载速度,并减少每个页面加载所需的数据量。通过代码分离,可以按需加载所需要的模块。
懒加载是指在需要时才加载某个模块,而不是在初始加载时就将所有代码一次性加载完毕
懒加载可以根据需要动态的加载模块,只加载当前可见的模块,随着用户与页面交互,再按需加载其他模块
区别
-
代码分离是将代码文件拆分成较小的文件,其中每个文件可能包含多个模块。这样做可以在初始加载时减少数据量,但仍然需要一次性加载所需的文件。
-
懒加载是将页面分成多个模块,在需要时才去加载相应的模块。这样做可以进一步减小初始加载时间,只加载当前可见的模块,随着用户与页面交互,再按需加载其他模块。
Webpack中的热重载是什么?
热重载(Hot Module Replacement,HMR)是Webpack提供的一项功能,它允许在开发过程中,无需刷新整个页面,即可实时更新修改的模块。
1. 在Webpack配置文件中启用热模块替换。可通过配置devServer.hot
选项为true
来启用HMR:
ini
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
...
devServer: {
hot: true,
},
};
2. 在入口文件中添加对HMR的支持。在入口文件中,需要添加HMR的逻辑以监听模块的变化,并告诉Webpack如何处理更新。
arduino
// index.js
if (module.hot) {
module.hot.accept();
}
3. 配置Webpack插件。HMR需要搭配相应的插件使用,常用的是webpack.HotModuleReplacementPlugin
。
ini
// webpack.config.js
const webpack = require('webpack');
module.exports = {
// ...
plugins: [
new webpack.HotModuleReplacementPlugin(),
// ...其他插件
],
};