这一周投了几个简历,挂了两家,原因是简历太空了,面试了一个也没过。本周学习的东西不多,但是发现了自身的一些问题,也算有所收获。下面是面试的一些问题的记录
一、http状态码
记过好几遍,但面试的时候该记不起来还是记不起来
- 1XX
101:服务器根据客户端的请求切换协议。只能切换到更高级的协议。在客户端请求中会有`Connection: Upgrade`和
`Upgrade: websocket`这两个属性来表示升级的目标协议。
- 2XX(成功状态码)
200:表示从客户端发来的请求在服务器端被正常处理了
204:表示请求已成功处理,但是无内容
206:表示客户端进行了范围请求,而服务器成功执行了这部分的 `GET`
请求响应报文中包含由`Content-Range`指定范围的实体内容
- 3XX(重定向状态码)
301(永久性重定向):表示请求的资源已被分配了新的 `URI`,以后的请求应使用资源现在所指的 `URI`。
302(临时性重定向):表示请求的资源已被分配了新的 `URI`,希望用户(本次)能使用新的 `URI` 访问。
但是之后还是应该使用原来的`URI`
303:`303` 状态码和 `302` 状态码有着相同的功能,但 `303` 状态码明确表示客户端应当采用
`GET` 方法获取资源,这点与 `302` 状态码有区别。
304(`Not Modified`):表示客户端发送附带条件的请求时,服务器端允许请求访问资源,
但未满足条件的情况。该状态码在协商缓存中使用,返回时表示应该从缓存中读取数据。
具体有关协商缓存和强缓存可以看看这篇文章(https://juejin.cn/post/6844903593275817998)
307:与 `302 Found` 有着相同的含义,但 `307` 会遵照浏览器标准,不会从 `POST` 变成 `GET`。
- 4XX(客户端错误状态码)
400(`Bad Request`):求报文中存在语法错误
401(`Unauthorized`):没有权限,需要用户认证
403(`Forbidden`):拒绝访问
404(`Not Found`):资源未找到
408(`Request Timeout`):请求超时
- 5XX(服务端错误状态码)
500(`Internal Server Error`):服务器端在执行请求时发生了错误
502(`Bad Gateway`):表明扮演网关或代理角色的服务器,从上游服务器中接收到的响应是无效的。
二、options请求
在跨域情况下,请求分为简单请求与复杂请求,MDN中规范了简单请求需要满足一下所有条件:
- 方法为
GET、HEAD、POST之一 - 除了被用户代理自动设置的首部字段(例如
Connection,User-Agent)和在 Fetch 规范中定义为 禁用首部名称 的其他首部,允许人为设置的字段为 Fetch 规范定义的 对 CORS 安全的首部字段集合。该集合为:AcceptAccept-LanguageContent-LanguageContent-Type(需要注意额外的限制)
Content-Type的值仅限于下列三者之一:text/plainmultipart/form-dataapplication/x-www-form-urlencoded
- 请求中的任意
XMLHttpRequestUpload对象均没有注册任何事件监听器;XMLHttpRequestUpload对象可以使用XMLHttpRequest.upload属性访问。 - 请求中没有使用
ReadableStream对象。 除此之外的请求为复杂请求,便会发起预检请求(options),预检请求请求头会带有Access-Control-Request-Method和Access-Control-Request-Headers来表示实际请求使用的方法和头部字段,服务端据此判断是否支持。同时OPTIONS预检请求的结果可以被缓存,这样可以避免多次触发预检请求。复杂请求在发送预检请求后会,如果服务端支持,则会发送真正的请求,否则不会。
三、Promise.all、Promise.race、Promise.allSettled
这三兄弟之前也看过用法和实现方法,但是都没太注意,加上平时也没什么用到,被问到的时候就只能答出基础的东西,代码实现的时候也是经过提示才完成
Promise.all
三个特点:
1、返回一个Promise
2、当所有Promise都resolve了,则会resolve,值为所有Promise的值组成的数组
3、当有Promise reject了,会reject,值为这个Promise的err值
实现:
function PromiseAll(promises) {
let anyErr = null // 是否有任何promise reject
let len = promises.length
let finishCount = 0 // 当前已经resolve的promise数
let index = 0
let result = new Array(len)
return new Promise((resolve, reject) => {
if (len === 0) {
resolve([])
} else {
for (const promise of promises) {
const currentCount = index // 获取当前promise在result数组中对应的下标
promise.then(res => {
if (anyErr) return // 如果已经有promise reject了,便退出
result[currentCount] = res
finishCount++
if (finishCount === len) { // 所有promise都已经resolve
resolve(result)
}
}).catch(err => {
if (anyErr) return // 如果已经有promise reject了,便退出
anyErr = err
reject(err)
})
index++
}
}
})
}
Promise.race
特点:返回一个Promise,当有任一传入的Promise resolve或reject,返回的Promise便resolve或reject
实现
function race(promises) {
return new Promise((resolve, reject) => {
let done = false
for (const promise of promises) {
promise.then(res => {
if (done) return
done = true
resolve(res)
}).catch(err => {
if (done) return
done = true
reject(err)
})
}
})
}
Promise.allSettled
特点:返回一个promise,该promise在所有给定的promise已被解析或被拒绝后解析,
并且每个对象都描述每个promise的结果。对象结构为:
{status: 'fulfilled', value: value} -- {status: 'rejected', reason: err}
实现
function allSettled(promises) {
let index = 0
let len = promises.length
let finishCount = 0
let result = new Array(len)
return new Promise((resolve, reject) => {
for (const promise of promises) {
const currentIndex = index
promise.then(res => {
result[currentIndex] = {
status: 'fulfilled',
value: res
}
finishCount++
if (finishCount === len) {
resolve(result)
}
}, err => {
result[currentIndex] = {
status: 'rejected',
reason: err
}
finishCount++
if (finishCount === len) {
resolve(result)
}
})
index++
}
})
}
Promise的缺点
查过资料后大家总结的缺点主要是三个:
1、promise一旦新建就会立即执行,中途无法取消
2、当处于pending状态时,无法得知当前出于那一个状态,是刚开始还是刚结束
3、如果不设置回调函数,promise内部的错误就无法反映到外部
对于第一点
下面代码会输出then1、then2、finally,无法在第一个then执行后停止
let a = new Promise((resolve) => resolve(1))
.then(() => console.log('then1')) // 需要在这终止,不执行下面的内容
.then(() => console.log('then2'))
.catch(()=> console.log('catch'))
.finally(() => console.log('finally'))
如果需要,下面代码可以实现中断Promise
function withAbort(promise) {
let abort
let abortBtn = new Promise((resolve, reject) => (abort = reject))
let res = Promise.race([promise, abortBtn])
res.abort = abort
return res
}
let a = withAbort(getData)
a.then(res => console.log('res'))
setTimeout(() => {
a.abort // 模拟用户手动中断
}, 1000)
上述代码返回了一个新的Promise,并可以手动中断,但是对原本的promise是没有影响的,
只不过用Promise.race进行控制罢了
对于第三点,可以用下面代码来表示
const a = new Promise(function(resolve, reject) {
// 下面一行会报错,因为x没有声明
resolve(x + 2);
});
a.then(res => console.log(res))
setTimeout(() => { console.log(123) }, 2000);
上述代码会在控制台上输出
// Uncaught (in promise) ReferenceError: x is not defined
// 123
虽然可以检测到Promise内有错误,但是并不会终止脚本进行,2秒后还是会输出123。
在Node.js中,有一个unhandledRejection事件,专门监听未捕获的reject错误,可以
在监听函数中抛出错误,不过Node未来可能会废除该事件,如果Promise内部有未捕获的
错误,就会直接终止进程。
process.on('unhandledRejection', function (err, p) {
throw err;
});
另外,在一下代码中,错误被放到了下一轮事件循环中抛出,这时候Promise已经运行完毕,
所以相当于在Promise函数体外抛出,便会冒泡到最外层,成为未捕获的错误
const promise = new Promise(function (resolve, reject) {
resolve('ok');
setTimeout(function () { throw new Error('test') }, 0)
});
promise.then(function (value) { console.log(value) });
// ok
// Uncaught Error: test
还有一种情况是在resolve完之后抛出错误,这时候Promise的状态已经变成了fulfilled,
这时候抛出错误已经是无效的了
const promise = new Promise(function(resolve, reject) {
resolve('ok');
throw new Error('test');
});
promise
.then(function(value) { console.log(value) })
.catch(function(error) { console.log(error) });
// ok
本周总结: 面试后发现自己之前的学习方法存在比较大的问题,像node,微信小程序,react这些都有去学过,但是都没有深入进去,也不好写在简历上,加上刚入职没多久,项目上也没有多少东西,就导致简历上的内容并没有实质性的增加。接下来打算先回顾一阵子数据结构和算法,然后深入学习一下typescript。还有就是学了忘这个问题,也只能多回顾多复习了,希望以后能有所改善。