2021.6.23开始 前端每日学习笔记

286 阅读5分钟

当同事离职时,才发现人家每天在默默努力,将每天的学习做记录,而且每天保持学习状态; 自今天起每天记录自己学了什么~

6.23 a标签属性

今天看到同事的pr时,发现a标签的这个属性,惭愧,做前端这么久都没使用过,于是网上查了一下

在带有target="_blank"的标签中,加上rel="noopener"属性。如果使用window.open的方式打开页面,将opener对象置为空。这样的副作用是:在某些低版本浏览器中,新页面中拿不到referer信息

参考链接 juejin.cn/post/684490…

6.24 git stash使用

git stash使用 参考 blog.csdn.net/daguanjia11…

git stash

保存当前工作进度,会把暂存区和工作区的改动保存起来。执行完这个命令后,在运行git status命令,就会发现当前是一个干净的工作区,没有任何改动。使用git stash save 'message...'可以添加一些注释

git stash pop [–index] [stash_id]

git stash pop 恢复最新的进度到工作区。git默认会把工作区和暂存区的改动都恢复到工作区。

git stash pop --index 恢复最新的进度到工作区和暂存区。(尝试将原来暂存区的改动还恢复到暂存区)

git stash pop stash@{1}恢复指定的进度到工作区。stash_id是通过git stash list命令得到的

通过git stash pop命令恢复进度后,会删除当前进度。

6.25 函数防抖,函数节流 及px、em、rem、%、vw、vh、vm这些单位的区别

函数防抖,函数节流

函数防抖: 在事件被触发n秒后再执行,如果在n秒内再次被出发,则重新计时。

函数节流: 每隔一段时间,只执行一次函数。

参考连接 segmentfault.com/a/119000001…

px、em、rem、%、vw、vh、vm这些单位的区别

参考连接 www.jianshu.com/p/82f02af17…

6.29 字节题:用JS实现Ajax并发请求控制

参考链接(segmentfault.com/a/119000003…)

实现一个批量请求函数 multiRequest(urls, maxNum),

要求如下: • 要求最大并发数 maxNum

• 每当有一个请求返回,就留下一个空位,可以增加新的请求

• 所有请求完成后,结果按照 urls 里面的顺序依次打出

场景

假设现在有这么一种场景:现有 30 个异步请求需要发送,但由于某些原因,我们必须将同一时刻并发请求数量控制在 5 个以内,同时还要尽可能快速的拿到响应结果。

应该怎么做?

首先我们来了解一下 Ajax的串行和并行。

基于 Promise.all 实现 Ajax 的串行和并行 我们平时都是基于promise来封装异步请求的,这里也主要是针对异步请求来展开。

串行:一个异步请求完了之后在进行下一个请求 并行:多个异步请求同时进行 通过定义一些promise实例来具体演示串行/并行。

串行

  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      console.log("1000");
      resolve();
    }, 1000);
  });
};
var p1 = function () {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      console.log("2000");
      resolve();
    }, 2000);
  });
};
var p2 = function () {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      console.log("3000");
      resolve();
    }, 3000);
  });
};

p()
  .then(() => {
    return p1();
  })
  .then(() => {
    return p2();
  })
  .then(() => {
    console.log("end");
  });

如示例,串行会从上到下依次执行对应接口请求。

并行

通常,我们在需要保证代码在多个异步处理之后执行,会用到:

Promise.all((promises: [])).then((fun: function));

Promise.all可以保证,promises数组中所有promise对象都达到resolve状态,才执行then回调。

var promises = function () {
  return [1000, 2000, 3000].map((current) => {
    return new Promise(function (resolve, reject) {
      setTimeout(() => {
        console.log(current);
      }, current);
    });
  });
};

Promise.all(promises()).then(() => {
  console.log("end");
});

Promise.all 并发限制

这时候考虑一个场景:如果你的promises数组中每个对象都是http请求,而这样的对象有几十万个。

那么会出现的情况是,你在瞬间发出几十万个http请求,这样很有可能导致堆积了无数调用栈导致内存溢出。

这时候,我们就需要考虑对Promise.all做并发限制。

Promise.all并发限制指的是,每个时刻并发执行的promise数量是固定的,最终的执行结果还是保持与原来的Promise.all一致。

思路分析 整体采用递归调用来实现:最初发送的请求数量上限为允许的最大值,并且这些请求中的每一个都应该在完成时继续递归发送,通过传入的索引来确定了urls里面具体是那个URL,保证最后输出的顺序不会乱,而是依次输出。

function multiRequest(urls = [], maxNum) {
  // 请求总数量
  const len = urls.length;
  // 根据请求数量创建一个数组来保存请求的结果
  const result = new Array(len).fill(false);
  // 当前完成的数量
  let count = 0;

  return new Promise((resolve, reject) => {
    // 请求maxNum个
    while (count < maxNum) {
      next();
    }
    function next() {
      let current = count++;
      // 处理边界条件
      if (current >= len) {
        // 请求全部完成就将promise置为成功状态, 然后将result作为promise值返回
        !result.includes(false) && resolve(result);
        return;
      }
      const url = urls[current];
      console.log(`开始 ${current}`, new Date().toLocaleString());
      fetch(url)
        .then((res) => {
          // 保存请求结果
          result[current] = res;
          console.log(`完成 ${current}`, new Date().toLocaleString());
          // 请求没有全部完成, 就递归
          if (current < len) {
            next();
          }
        })
        .catch((err) => {
          console.log(`结束 ${current}`, new Date().toLocaleString());
          result[current] = err;
          // 请求没有全部完成, 就递归
          if (current < len) {
            next();
          }
        });
    }
  });
}

6.30 React中的setState是同步的还是异步的

在React中,如果是由React引发的事件处理(比如通过onClick引发的事件处理),调用setState不会同步更新this.state; 除此之外的setState调用会同步执行this.state 。所谓“除此之外”,指的是绕过React通过addEventListener直接添加的事件处理函数,还有通过setTimeout/setInterval产生的异步调用。

原因: 在React的setState函数实现中,会根据一个变量isBatchingUpdates判断是直接更新this.state还是放到队列中回头再说,而isBatchingUpdates默认是false,也就表示setState会同步更新this.state,但是,有一个函数batchedUpdates,这个函数会把isBatchingUpdates修改为true,而当React在调用事件处理函数之前就会调用这个batchedUpdates,造成的后果,就是由React控制的事件处理过程setState不会同步更新this.state。

注意: setState的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形式了所谓的“异步”,当然可以通过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果。

参考文档:github.com/Advanced-Fr…

原理:github.com/sisterAn/bl…

6.30 如何把一个字符串的大小写取反(大写变小写小写变大写),例如 ’AbC' 变成 'aBc'

 function processString(value){
     const str = value.split('')
     let newString = str.map(item =>{
      return item === item.toUpperCase() ? item.toLowerCase() : item.toUpperCase()
    })
    return newString.join('')
 }
 console.log(processString('AbC'));

6.30 怎么让一个 div 水平垂直居中

**方法1.**
div.parent {
    display: flex;
    justify-content: center;
    align-items: center;
}
**方法2: (分固定宽高,不固定宽高)**
div.parent {
    position: relative; 
}
div.child {
    position: absolute; 
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);  
}
/* 或者 */
div.child {
    width: 50px;
    height: 10px;
    position: absolute;
    top: 50%;
    left: 50%;
    //子元素相对于自身宽度的变化
    margin-left: -25px;
    margin-top: -5px;
}
/* 或 */
div.child {
    width: 50px;
    height: 10px;
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    margin: auto;
}
**方法3:**
div.parent {
    display: grid;
}
div.child {
    justify-self: center;
    align-self: center;
}
**方法4:使用table-cell**
.parent {
        display: table-cell;
        height: 200px;
        width: 200px;
        background-color: orange;
        text-align: center;
        vertical-align: middle;
}
 .child {
        display: inline-block;
        width: 100px;
        height: 100px;
        background-color: blue;
}

6.30 前端倒计时纠偏实现

参考链接:juejin.cn/post/684490…

const interval = 1000
let ms = 50000,  // 从服务器和活动开始时间计算出的时间差,这里测试用 50000 ms
let count = 0
const startTime = new Date().getTime()
let timeCounter
if( ms >= 0) {
  timeCounter = setTimeout(countDownStart, interval)
}
 
function countDownStart () {
   count++
   const offset = new Date().getTime() - (startTime + count * interval) // A
   let nextTime = interval - offset
   if (nextTime < 0) { 
       nextTime = 0 
   }
   ms -= interval
   console.log(`误差:${offset} ms,下一次执行:${nextTime} ms 后,离活动开始还有:${ms} ms`)
   if (ms < 0) {
     clearTimeout(timeCounter)
   } else {
     timeCounter = setTimeout(countDownStart, nextTime)
   }
 }

7.1 Other题顺丰

1.html mate 标签的作用

2.兼容移动端的方式

3.preload prefetch

4.浏览器优化的方式

5.http2.0

6.react 新建一个组件的过程

7.react 使用中值得一提的东西

8.css3 新增的伪类

9.获取兄弟节点的方式

10.如果用 css disable 按钮

loader,它是一个转换器,将A文件进行编译成B文件,比如:将A.less转换为A.css,单纯的文件转换过程。

plugin是一个扩展器,它丰富了webpack本身,针对是loader结束后,webpack打包的整个过程,它并不直接操作文件,而是基于事件机制工作,会监听webpack打包过程中的某些节点,执行广泛的任务