Promise Ajax webpack http面试问题

249 阅读10分钟

promise

截屏2021-07-11 08.25.28.png

回调地狱

setTimeout(() => {
  console.log('first floor')

  setTimeout(() => {
    console.log('secode floor')

    setTimeout(() => {
        console.log('thrid floor')

      },1000)
  },1000)
},1000)
//Promise 方法
new Promise((resolve, reject) => {
  console.log('1')

  setTimeout(()=>{
    resolve('2')
  },1000)

}).then(res => {
  console.log(res)

  return new Promise((resolve,reject)=>{
      setTimeout(()=>{
        resolve( {msg:'3'})
      },1000)
    })

},err=>{
  console.log(err)
}).then(res=>{
  console.log(res.msg)
  }
)

静态方法: Promise.resolve() Promise.reject() Promise.all() Promise.race()

(1) Promise.resolve()

static resolve(value) {
  if (value instanceof Promise) {
    // 如果是Promise实例,直接返回
    return value;
  } else {
    // 如果不是Promise实例,返回一个新的Promise对象,状态为FULFILLED
    return new Promise((resolve, reject) => resolve(value));
  }
}

(2) Promise.reject()

static reject(reason) {
  return new Promise((resolve, reject) => {
    reject(reason);
  })
}

(3) promiss.all Promise.all是支持链式调用的,本质上就是返回了一个Promise实例,通过resolve和reject来改变实例状态。

Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。

【返回一个promise对象,只有当所有promise都成功时返回的promise状态才成功,需要注意的点是:

1所有的promise状态变为FULFILLED,返回的promise状态才变为FULFILLED。

2一个promise状态变为REJECTED,返回的promise状态就变为REJECTED。

3数组成员不一定都是promise,需要使用Promise.resolve()处理。】

Promise.myAll = function(promiseArr) {
  return new Promise((resolve, reject) => {
    const ans = [];
    let index = 0;
    for (let i = 0; i < promiseArr.length; i++) {
      promiseArr[i]
      .then(res => {
        ans[i] = res;
        index++;
        // 如果全部执行完,返回promise的状态就可以改变了
        if (index === promiseArr.length) {
          resolve(ans);
        }
      })
      .catch(err => reject(err));
    }
  })
}

(4) promiss.race Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。

Promise.race = function(promiseArr) {
  return new Promise((resolve, reject) => {
    promiseArr.forEach(p => {
      // 如果不是Promise实例需要转化为Promise实例
      Promise.resolve(p).then(
        val => resolve(val),
        err => reject(err),
      )
    })
  })
}

同步异步


async function a(cb) {
  console.log(1)//2
  let a = await cb()
  console.log(a)
  console.log(2)//6
}
function  b() {
  return new Promise((resolve,reject) => {
    console.log(3)//3
    resolve(6)//5
  })
}

console.log(4) //1
a(b)
console.log(5)//4

async| await |then

async  function log() {
  setTimeout(function () {
    console.log(1)//4
  },1000)
  await console.log(2) //1
}
log().then(() =>{
  console.log(3)//3
});
console.log(4)//2

Ajax

const getJSON = function(url) {
  return new Promise((resolve, reject) => {
    const xhr = XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Mscrosoft.XMLHttp');
    xhr.open('GET', url, false);
    xhr.setRequestHeader('Accept', 'application/json');
    xhr.onreadystatechange = function() {
      if (xhr.readyState !== 4) return;
      if (xhr.status === 200 || xhr.status === 304) {
        resolve(xhr.responseText);
      } else {
        reject(new Error(xhr.responseText));
      }
    }
    xhr.send();
  })
}

跨域

  • 1 同源策略:协议(http、https),域名,端口号(8080)必须完全一致
  • 2 跨域:违背同源策略
  • 3 解决跨域:jsonp (前端+后端),CORS(后端),服务器代理(后端)
  • jsonp 利用script标签天然可跨域的属性
//创建script标签
var script = document.createElement('script')
//设置回调函数
function getData(data) {
  //数据请求回来会被触发的函数
  console.log(data)
}
//设置script 的scr属性,设置请求地址
script.scr = 'http:///localhost:3000?callback=getData'
//让script生效,添加到document.body的appendChild
document.body.appendChild(script)
4.服务器中路由的处理
router.get("/testAJAX" , function (req , res) {
console.log("收到请求");
var callback = req.query.callback; var obj = {name:"孙悟空",
age:18 }
res.send(callback+"("+JSON.stringify(obj)+")"); });

CORS CORS 全称是 跨域资源共享(Cross-Origin Resource Sharing),是官方的跨域解决方案, CORS 是通过设置一个响应头来告诉浏览器,该请求允许跨域,主要是服务器端的设置:


router.get("/testAJAX" , function (req , res) {
//通过 res 来设置响应头,来允许跨域请求
 //res.set("Access-Control-Allow-Origin", "http://127.0.0.1:3000"); 
res.set("Access-Control-Allow-Origin","*");
res.send("testAJAX 返回的响应");
});

浏览器收到该响应 以后就会对响应放行。

1 当使用 XMLHttpRequest 发送请求时,浏览器发现该请求不符合同源策略,会给该请求加一个响应头:Origin;(浏览器无需做设置 只需发送ajax) 2 后台服务器收到请求后,会进行一系列处理,如果确定接受请求,则在返回结果中加入一个响应头:Access-Control-Allow-Origin (换言之,服务器允许的域url,会加入此响应头,相当于一个凭证); 3 浏览器判断该相应头中是否包含 Origin 的值,如果有,则浏览器会处理响应,我们就可以拿到响应数据。

webpack

webpack的loader和plugin区别

对于loader,它是一个转换器,将A文件进行编译形成B文件,这里操作的是文件,比如将A.scss转换为A.css,单纯的文件转换过程

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

webpack的loader顺序 loader的执行顺序和配置中的顺序是相反的

图片懒加载(问了好几次)

可以给img标签统一自定义属性data-src='default.png',当检测到图片出现在窗口之后再补充src属性,此时才会进行图片资源加载。

function lazyload() {
  const imgs = document.getElementsByTagName('img');
  const len = imgs.length;
  // 视口的高度
  const viewHeight = document.documentElement.clientHeight;
  // 滚动条高度
  const scrollHeight = document.documentElement.scrollTop || document.body.scrollTop;
  for (let i = 0; i < len; i++) {
    const offsetHeight = imgs[i].offsetTop;
    if (offsetHeight < viewHeight + scrollHeight) {
      const src = imgs[i].dataset.src;
      imgs[i].src = src;
    }
  }
}

// 可以使用节流优化一下
window.addEventListener('scroll', lazyload);

HTTP

tcp为什么可以按序到达 请求头(请求方式的请求头 缓存的请求头)

HTTP缓存

截屏2021-04-13 20.58.32.png

浏览器解析渲染页面

url到页面渲染完成过程: 1.DNS 解析:将域名地址解析为ip地址

浏览器DNS缓存->系统DNS缓存->路由器DNS缓存->网络运营商DNS缓存

->递归搜索(blog.baidu.com):.com域名下查找DNS解析->.baidu域名下查找DNS解析->blog域名下查找DNS解析->出错了

2.TCP连接:TCP三次握手

  • 第一次握手:由浏览器发起,告诉服务器我要发送请求了
  • 第二次握手:由服务器发起,告诉服务器我准备接受了,你块发送吧
  • 第三次握手:由浏览器发送,告诉服务器,我马上就发了,准备接受吧

3.发送请求:请求报文:HTTP协议的通信内容

4.接受响应:响应报文

5.渲染页面:

  • 遇见HTML标记,浏览器调用HTML解析器成Token并构建dom数
  • 遇见style、link标记,浏览器调用css解析器,处理css标记并构建cssom数
  • 遇见script标记,浏览器调用JavaScript解析器,处理script代码(绑定事件,修改dom树,cssom数)
  • 将dom树和cssom树合并为一个渲染树
  • 根据渲染树来计算布局,并计算每个节点的几何信息(布局)
  • 将各个节点的颜色绘制到屏幕上(渲染) 注:这5个步骤不一定按顺序执行,如果dom树和cssom树被修改,可能会执行多次布局和渲染。往往在实际页面中这些步骤都会多次执行
  1. 断开连接:TCP四次挥手
  • 第一次挥手,由浏览器发起,发给服务器,我的请求报文发送完了,你准备关闭吧
  • 第二次挥手,由服务器发起,发给浏览器,我的请求报文接受完了,我准备关闭了,你也准备吧
  • 第三次挥手,由服务器发起,发给浏览器,我的响应报文发送完了,你准备关闭吧
  • 第四次挥手,由浏览器发起,发给服务器,我的响应报文接受完了,我准备关闭了,你也准备吧

reflow(回流)和repain(重绘)。DOM节点中的各个元素都是以盒模型的形式存在,这些都需要浏览器去计算其位置和大小等,这个过程称为relow;当盒模型的位置,大小以及其他属性,如颜色,字体,等确定下来之后,浏览器便开始绘制内容,这个过程称为repain。页面在首次加载时必然会经历reflow和repain。reflow和repain过程是非常消耗性能的,尤其是在移动设备上,它会破坏用户体验,有时会造成页面卡顿。所以我们应该尽可能少的减少reflow和repain。

JS的解析是由浏览器中的JS解析引擎完成的,事件循环(Event loop)

浏览器在解析过程中,如果遇到请求外部资源时,如图像,iconfont,JS等。浏览器将重复1-6过程下载该资源。请求过程是异步的,并不会影响HTML文档进行加载,但是当文档加载过程中遇到JS文件,HTML文档会挂起渲染过程,不仅要等到文档中JS文件加载完毕还要等待解析执行完毕,才会继续HTML的渲染过程。原因是因为JS有可能修改DOM结构,这就意味着JS执行完成前,后续所有资源的下载是没有必要的,这就是JS阻塞后续资源下载的根本原因。CSS文件的加载不影响JS文件的加载,但是却影响JS文件的执行。JS代码执行前浏览器必须保证CSS文件已经下载并加载完毕。

6 断开连接:TCP 四次挥手 截屏2021-05-06 20.41.39.png

  • 发起方向被动方发送报文,Fin、Ack、Seq,表示已经没有数据传输了。并进入 FIN_WAIT_1 状态。 (第一次挥手:由浏览器发起的,发送给服务器,我请求报文发送完了,你准备关闭吧)
  • 被动方发送报文,Ack、Seq,表示同意关闭请求。此时主机发起方进入 FIN_WAIT_2 状态。 (第二次挥手:由服务器发起的,告诉浏览器,我请求报文接受完了,我准备关闭了,你也准备吧)
  • 被动方向发起方发送报文段,Fin、Ack、Seq,请求关闭连接。并进入 LAST_ACK 状态。 (第三次挥手:由服务器发起,告诉浏览器,我响应报文发送完了,你准备关闭吧)
  • 发起方向被动方发送报文段,Ack、Seq。然后进入等待 TIME_WAIT 状态。被动方收到发起方的报文段以后关闭连接。发起方等待一定时间未收到回复,则正常关闭。 (第四次挥手:由浏览器发起,告诉服务器,我响应报文接受完了,我准备关闭了,你也准备吧)

node

nodejs的事件循环机制:

借助libuv的库实现的

  • 1 timer 定时器阶段:计时和执行到点的定时器回调函数
  • 2 pending callback :某些系统操作(例如TCP错误类型)的回调函数
  • 3 idle,prepare 准备阶段
  • 4 poll 轮询阶段(轮询队列):如果轮询队列不为空,依次同步取出轮询队列中的第一个回调函数执行,直到轮询队列为空,或达到系统最大的限制,如果轮询队列为空,并且事前设置过setImmediate函数,直接进入下一个check阶段;如果没有设置setImmediate函数,直接进入下一个check阶段,在当前poll阶段等待,直到轮询队列添加回调函数,就去第一个情况执行,如果定时器到点了,就去下一个阶段。
  • 5 check阶段 执行setImmediate设置的回调函数
  • 6 close callbacks 关闭阶段:执行close事件回调函数
//process.nextTick 优先执行
setTimeout(function () {
  console.log('setTimeout()')//2
},0)
setImmediate(function () {
  console.log('setImmediate()')//3
})

process.nextTick(function () {
  console.log('process.nextTick()')//1
})

node的写入文件操作 node写入文件分为同步跟异步有什么区别?

二面

深挖项目(哭了,挖到不知道说啥了,提到了优化) 3、你刚刚说到了图片懒加载,怎么实现的?有用过懒加载的插件吗? 4、怎么判断元素是否在可视范围内?

7、做过登录功能吗?怎么实现的? 8、怎么记录用户登录的状态?具体的? 9、为什么有了cookie还要有token 11、最近有看什么新的技术文章吗,给我讲讲(说了web安全) 12、反问,你刚刚说xss的时候说到了给cookie设置httponly,为什么要操作cookie?要配合什么来用?

14、扫码登录怎么实现的?结合token怎么做?你刚刚说最后会返回给用户浏览器,返回之后会做什么? 15、ts怎么扩展类?能写一下吗

  1. 问项目
  2. 前端工程化 => 如何解决webpack打包慢。
  3. 前端前沿技术了解 balabala...