再撸一梭子渐渐你该懂得知识

typeof原理

JS底层存储变量会在机器码低位1-3位存储类型信息,typeof也是据此判断的,巧合的是null和object的这三位都是000,因此typeof null == typeof {} == ‘object’。

Chrome80对SameSite的使用

之前写过Chrome80更新,很重要的一点改动就是对sameSite的改动,之前samesite默认是使用none的,Chrome80之后,这个默认值改为了lax(宽松),也就是说,之前设置为None时,无论是否跨站,默认请求都会携带cookie,但是修改之后,跨站是不会携带cookie的。

跨站与同源(跨域)不同,只需要判断顶级域名和二级域名,如http://a.t.com和https://b.t.com,我们可以认为它是同站。而设置为Lax之后,除去get 方法提交表单况或者a 标签发送 get 请求之外,很多跨站方式并不会携带请求。

Promise封装Ajax

之前被问道一次,也没让写,这里贴出来:

function Ajax(url) {
  return new Promise((resolve, reject) => {
    let xhr = new XMLHttpRequest();
    xhr.open("get", url, true);
    xhr.responseType = "JSON";
    xhr.onreadystatechange = function() {
      if (xhr.readyState === 4 && /^[23]\d{2}$/.test(xhr.status)) {
        let res = xhr.responseText;
        resolve(JSON.parse(res));
      }
    };
    xhr.onerror = function(err) {
      reject(err);
    };
    xhr.send();
  });
}

很可能会忘了parse,那样的出来的是字符串。

JSONP

原理很简单,利用了script便签不受同源协定的约束,把要返回的值序列化放到callback后面拼成一个立函数执行形式,然后在客户端window对象添加一个对应的函数,在这儿函数种对服务端返回的响应包裹的数据进行处理:

function jsonp({url,params,callback}){
  return new Promise((resolve, reject) => {
    let script = document.body.createElement('script')
    params = JSON.parse(JSON.stringify(params))
    let arr = []
    for(let key in params){
      arr.push(`${key}=${params[key]}`)
    }
    arr.push(`callback=${callback}`)
    script.src = `${url}?${arr.join("&")}`;
    document.appendChild(script)
    window[callback]=function(data){
      if(!data) reject('failed')
      resolve(data) 
      document.body.removeChild(script) 
    }
  })
}

简单认识websocket

之前对webSocket的简单了解就是实现了服务器主动推送,毕竟在此之前,我们实现推送都是通过轮询的方式实现的。

首先,WebSocket建立在 TCP 协议之上,与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP协议,同时它的数据格式比较轻量,性能开销小,通信高效。可以发送文本,也可以发送二进制数据。
还有一点它不受没有同源限制,客户端可以与任意服务器通信。协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

HTTP握手后,WebSocket基于HTTP协议进行升级,服务端返回101状态码标识协议切换,后序的数据交互都按照新的协议进行。建立连接后,后续的操作都是基于数据帧的传递。

两种解决Effect错误依赖的方法

看个Demo:

export default function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const id = setInterval(() => {
      console.log("in");
      setCount(count + 1);
    }, 1000);
    return () => {
      console.log("out");
      clearInterval(id);
    };
  }, []);
  return <h1>{count}</h1>;
}

这里,我们依赖为空,只会渲染一次,setInterval导致"in"每隔1秒会输出,而UseEffect并不会重复执行,因此每次我们的count为0,+1,返回的总是1。

解决1:

export default function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const id = setInterval(() => {
      console.log("in");
      setCount(count + 1);
    }, 1000);
    return () => {
      console.log("out");
      clearInterval(id);
    };
  }, [count]);

  return <h1>{count}</h1>;
}

但是这样只会使得我们每次都要删除定时器再添加,不符合我们的需求。

解决2:

export default function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const id = setInterval(() => {
      console.log("in");
      setCount(c=c+ 1);
    }, 1000);
    return () => {
      console.log("out");
      clearInterval(id);
    };
  }, []);

  return <h1>{count}</h1>;
}

使用函数式更新state是最好的解决方法。

关于函数依赖,我们可以使用三个方式:

  1. 把函数写在useEffect种,确保它不依赖组件其他状态。
  2. 把函数写在组件外
  3. 使用useCallback包裹。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章