学习周记:面试篇(10.11-10.17)

327 阅读7分钟

这一周投了几个简历,挂了两家,原因是简历太空了,面试了一个也没过。本周学习的东西不多,但是发现了自身的一些问题,也算有所收获。下面是面试的一些问题的记录

一、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中规范了简单请求需要满足一下所有条件:

  • 方法为GETHEADPOST之一
  • 除了被用户代理自动设置的首部字段(例如 Connection ,User-Agent)和在 Fetch 规范中定义为 禁用首部名称 的其他首部,允许人为设置的字段为 Fetch 规范定义的 对 CORS 安全的首部字段集合。该集合为:
  • Content-Type 的值仅限于下列三者之一:
    • text/plain
    • multipart/form-data
    • application/x-www-form-urlencoded
  • 请求中的任意XMLHttpRequestUpload 对象均没有注册任何事件监听器;XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。
  • 请求中没有使用 ReadableStream 对象。 除此之外的请求为复杂请求,便会发起预检请求(options),预检请求请求头会带有Access-Control-Request-MethodAccess-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。还有就是学了忘这个问题,也只能多回顾多复习了,希望以后能有所改善。