GithubHelp home page GithubHelp logo

web-knowledge's People

Stargazers

 avatar

Watchers

 avatar  avatar

web-knowledge's Issues

浏览器输入地址后,发生了什么?

在浏览器种输入url,例如:www.baidu.com

浏览器查找域名的IP地址

  • 查找浏览器缓存:一般浏览器都会缓存DNS记录一段时间,浏览器去查找这些缓存。如果有缓存,则直接返回IP,否则下一步
  • 查找系统缓存:浏览器缓存中找不到IP之后,浏览器会调用(windows中是gethostbyname),查找本机的host文件,如果对应域名的ip,则直接返回,否则下一步
  • 查找路由器缓存,如果前两步没有结果,则需要借助网络,路由器都有自己的DNS缓存,将前面的请求发给路由器,查找ISP服务商缓存的DNS服务器,如果查找到IP则直接返回,没有的话继续查找
  • 递归查询:如果以上步骤还找不到,则ISP的DNS服务器就会进行递归查询,所谓递归查询就是如果主机所访问的本地服务器不知道被查询的域名的IP地址,那么本地域名服务器就以DNS客户的身份,向其他根域名服务器继续发送请求,而不是让该主机自己进行下一步查询
  • 迭代查询:本地域名服务器采用迭代查询,它先向一个根域名服务器查询。本地域名服务器向根域名服务器的查询一般都是采用迭代查询。所谓迭代查询就是当根域名服务器收到本地服务器收到本地域名服务器发出的查询请求。那么告诉本地域名服务器下一步应该查询哪一个域名服务器,然后本地域名服务器自己进行后续的查询。(而不是替代本地域名服务器进行后续查询)

浏览器与目标服务器建立TCP链接

  • 主机浏览器通过DNS解析到了目标服务器IP地址后,与服务器建立TCP链接。
  • TCP链接的三次握手:浏览器所在的客户机向服务器发出连接请求报文(SYN标志位1);服务器接收报文后,同意建立连接,向客户机发送确认报文(SYN,ACK值均为1);客户机接收到确认报文后,再次向服务器发出报文,确认已收到确认报文;此处客户机与付为妻之间的TCP连接已经建立完成,开始通信。

浏览器通过HTTP发送请求

释放TCP连接

  • 四次挥手:
    1.浏览器所在的主机向服务器发出连接释放报文,然后停止发送数据
    2.服务器接收到释放报文后发出确认报文,然后将服务器上未传送完的数据发送完
    3.服务器数据发送完毕后,向客户机发送连接释放报文
    4.客户机接收到报文后,发出确认,然后等待一段事件后,释放TCP连接

浏览器显示界面

浏览器发送获取嵌入在页面中其他内容

一道题弄懂构造函数继承原型链的知识

function Animal(name){
    this.name = name
}
Animal.color = "black"
Animal.prototype.say = function(){
    console.log('im'+this.name)
}
var cat = new Animal("cat")
cat.say()
cat.name
cat.color;
Animal.say()
Animal.name
Animal.color

以上分别打印出什么,如果不看答案,自己独立做出来,那构造函数方面的知识点,就懂了,反之,建议往下看一看

答案 : im cat ; cat; undefined;error is not a function;Animal;black
第一个和第二个很简单,省略
cat.color 为undefine的原因是因为 cat是构造函数Animal实例化出来的,cat本身只有name,原型上有say方法,没有color属性,有的人说Animal.color = ‘black’是定义了属性的,Animal.color是再一个函数对象里面添加的静态属性,不属于原型链上的属性,所以为undefine
Animal.say() Animal是一个方法,该方法内部没有say方法,无法提供链式操作,所以报错
Animal.proto.say=function(){
console.log(333)
}
如果添加以上三行,则Animal.say()会打印出 333
Animal.name name属性为函数本身的表达式名字,则为 name
Animal.color 为添加的静态属性值,为 black

总之一句话 静态方法不能被实例对象调用

防抖和节流

防抖(debounce)

所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。

function debounce(func, wait) {
    let timeout;
    return function () {
        let context = this;
        let args = arguments;
        if (timeout) clearTimeout(timeout);
        timeout = setTimeout(() => {
            func.apply(context, args)
        }, wait);
    }
}

节流(throttle)

所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率

function throttle(func, wait) {
    let previous = 0;
    return function() {
        let now = Date.now();
        let context = this;
        let args = arguments;
        if (now - previous > wait) {
            func.apply(context, args);
            previous = now;
        }
    }
}
content.onmousemove = throttle(count,1000);

看完这个,你就懂了Promise的一切

1.Promise的含义

promise 是前端的一种异步编程的解决方案,比传统的解决方案(回调函数和事件)更合理和更强大。ES6将其写进了语言标准,提供了原声的Promise对象

所谓promise,就是保存一个未来才会结束的事件(通常是异步操作),

  • promise对象的状态不受外界影响。promise对象代表一个异步操作,有三种状态:pending、fulfilled、rejected,只有异步操作的结果,可以决定当前是哪一种状态,其他操作都不能改变这种状态
  • 一但状态改变,就不会再变。promise的状态改变只有两种可能:从pending变为fulfilled和从pending变为rejected
  • promise也有一些缺点。首先,无法取消promise,一但新建他就会立即执行,无法中途取消;其次,如果不设置回调函数,promise内部抛出的错误,不会反应到外部;第三,当处于pending状态时,无法得知目前进展到哪一个阶段

2.基本用法

ES6规定,Promise是一个构造函数,用来生成promise实例

const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

promise生成实例后,可以用then方法分别制定resolve状态和reject状态的回调函数

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

3.then()

promise具有then方法。也就是说,then方法定义在原型对象 Promise.prototype上的。它的作用是为了Promise实例添加状态改变时的回调函数。前面说过,then方法的第一个参数是resolve状态的回调,第二个参数是reject状态的回调,他们都是可选的

then方法返回的是一个新的Promise实例(是新的,不是原来的),因此可采用链式写法,即then方法后面再调用另一个then方法

getJSON("/posts.json").then(function(json) {
  return json.post;
}).then(function(post) {
  // ...
});

上面带嘛使用then方法,依次制定了两个回调函数,第一个回调函数执行完成过后,会将返回结果作为参数,传入第二个回调函数。

4.catch()

catch()是.then(null, rejection)或.then(undefined, rejection)的别名,用于制定发生错误时的回调函数

getJSON('/posts.json').then(function(posts) {
  // ...
}).catch(function(error) {
  // 处理 getJSON 和 前一个回调函数运行时发生的错误
  console.log('发生错误!', error);
});
p.then((val) => console.log('fulfilled:', val))
  .catch((err) => console.log('rejected', err));

// 等同于
p.then((val) => console.log('fulfilled:', val))
  .then(null, (err) => console.log("rejected:", err));

5.finally()

finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。

promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});

finally方法的回调函数不接受任何参数,这意味着没有办法知道,前面的promise状态到底是fulfilled还是rejected。这表明,finally方法面的操作,应该与状态无关的,不依赖于promise的执行结果
finally本质上是then方法的特例

6.all()

promise.all()方法用于将多个Promise实例,包装成一个新的promise实例

const p = Promise.all([p1,p2,p3])

上面代码中,promise.all()方法接受一个数组作为参数,p1、p2、p3都是promise实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为promise实例,再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有Iterator接口,且返回的每一个成员都是Promise实例

p的状态由p1、p2、p3决定,分成两种情况。

1.只有p1、p2、p3的状态变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数
2.只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数

7.race()

const p = Promise.race([p1, p2, p3]);

上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

8.allSettled()

allSettled()方法接受一组promise实例作为参数,包装成一个新的promise实例。只有等到所有参数实例都返回结果,不管是fulfilled还是reject,实例才会结束

const promises = [
  fetch('/api-1'),
  fetch('/api-2'),
  fetch('/api-3'),
];

await Promise.allSettled(promises);
removeLoadingIndicator();

上面带嘛对服务器发出三个请求,等到三个请求都结束,不管请求成功还是失败,都会返回

9.any()

该方法接受一组promise实例作为参数,包装一个新的promise实例返回。只要参数实力有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成reject状态,包装实例就会变成rejected状态

resolve()

有时需要将现有对象转为Promise对象,promise.resolve()方法就起到这个作用

vue2中slot的使用

vue的slot主要分三种,默认插槽,具名插槽,作用域插槽;使用插槽是在存在父子关系的组件中使用,我们可以在子组件中决定插槽的位置,同时子组件也可以给这些插槽的默认信息,当父组件中没有需要给子组件插槽插入信息时,显示的是子组件插槽定义的默认信息,下边简单说下vue这三种插槽如何使用。

  1. 默认插槽的使用:

parent.vue

<template>
  <div>
    <slot-children>
      
        <p>我是slot</p>
     
    </slot-children>
    <div>--------------------</div>
  </div>
</template>

childen.vue

<template>
  <div>
      <slot >我是默认信息1</slot>
      <slot >我是默认信息2</slot>
  </div>
</template>
  • 默认插槽 父组件中定义的子组件中有定义的dom,子组件的slot中会展示该信息
  • 如果子组件中没有使用插槽的情况下,父组件中的p标签的内容是不会还给子组件的
  • 父组件定义要插入到子组件的插槽的内容,并不一定只有是dom结构类型的,也可以是一个组件,也可以是普通的数据结构,只要子组件有定义插槽,就会把内容填充进去
  • slot组件之间的通信子组件的slot用数据绑定,例:
    <slot :data='data'></slot>,父组件使用
<slot-children>
      <template slot-scope="user">
        <p>{{user.data}}</p>
      </template>
</slot-children>
  1. 具名插槽的使用:
  • vue 2.6.0 版本使用具名插槽和作用域插槽有了新的统一语法,使用v-slot替换了之前的slot和slot-scope

什么叫具名插槽?
官方说法:其实就是在子组件中定义插槽时,给对应的插槽分别起个名字,方便后边插入父组件将内容根据name来填充对应的内容。
接地气说法:slot加一个name属性命名,父组件中使用 v-slot:[name] 对应皆可

  1. 作用域插槽

作用域插槽:<slot :自定义name=data中的属性或对象>

<myli :title="val.title">
   <template v-slot:footer="message">
       <div>{{message.aa}}</div>
   </template>
</myli>
//书写组件时
 <template>
    <li>
        <slot name='footer' :aa="title"></slot>
    </li>
</template>
  • 需要注意message是传递的所有属性的集合 message.aa,当然也可以换成其他变量
  1. 来个简单总结
    v-slot的出现是为了代替原有的slot和slot-scope
    简化了一些复杂的语法。
    一句话概括就是v-slot :后边是插槽名称,=后边是组件内部绑定作用域值的映射。

JavaScript设计模式介绍

一、单例模式

定义: 保证一个类仅有一个实例,并提供一个访问它的全局访问点
核心: 确保只有一个实例,并提供全局访问
**实现:**假设调用一个方法,多次调用也只能设置一次

  function SetManager(name) {
      this.manager = name;
  }
  SetManager.prototype.getName = function() {
      console.log(this.manager);
  };
  var SingletonSetManager = (function() {
      var manager = null;
  
      return function(name) {
          if (!manager) {
              manager = new SetManager(name);
          }
  
          return manager;
      } 
  })();
  SingletonSetManager('a').getName(); // a
  SingletonSetManager('b').getName(); // a
  SingletonSetManager('c').getName(); // a

js变量和函数声明谁的优先级高?

var a = 3
function a(){
    console.log('fn')
}
console.log(a)

结果为3

// 交换顺序
function a(){
    console.log('fn')
}
var a = 3
console.log(a)

结果为3

此结果表名:变量优先级高于函数
  • 变量不赋值
var a
function a(){
    console.log('fn')
}
console.log(a)

结果为 a()

  • 变量不赋值交换顺序
function a(){
    console.log('fn')
}
var a
console.log(a)

结果为 a()

由此可见,当变量没有赋值或初始化,函数声明优先级高于变量,否则变量优先级高于函数

浅谈vue中provide和inject 用法

provide可以是一个对象,也可以是一个函数返回对象,和$data类似
provide:Object | () => Object
inject:Array | { [key: string]: string | Symbol | Object }
provide和inject是vue2.2.0版本新增
provide和inject主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中
这对选项需要一起使用
作用:允许一个祖先组件向所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终有效。

provide 选项应该是一个对象或者返回一个对象的函数。该对象包含可注入其子孙的属性。在该对象中你可以使用 Symbol 作为key,但是旨在原生支持 Symbol 和Reflect.ownKeys 的环境下可工作。

inject选项应该是: 一个字符串数组或者一个对象,对象的key是本地的绑定名,value是可用的注入内容中搜索用的key(字符串或Symbol),或者一个对象,
该对象的:from属性是在可用的注入内容中搜索可用的key(字符串或Symbol)
default属性是降级情况下使用value
###使用场景:
由于vue有$parent属性可以让子组件访问父组件。但孙组件想要访问祖先组件就比较困难。通过provide/inject 可以轻松实现跨级访问组件组件的数据
###一种常见的用法是刷新vue组件
// app.vue主要内容

     <template>
          <div
               id="app"
           >
               <router-view
                     v-if="isRouterAlive"
                />
           </div>
    </template>
    // 父组件中返回要传给下级的数据
    provide(){
        return {
             reload:this.reload
        }
    },
    methods:{
        reload(){
             this.isrouterAlive = false;
             this.$nextTice(()=>{
                    this.isrouterAlive = true;
             })
        }
    } 

// 子级主要内容

<template>
  <div class="hello">
      <div>子级的数据</div>
      {{message}}
  </div>
</template>

<script>
export default {
  inject: ['message','reload'],
  data () {
    return {
     
    }
  },
  mounted(){
     this.reload()
  }
}
</script>

##提示:provide和inject绑定并不是可相应的。这是刻意为之的。然后,如果传入了一个可监听的对象,那么其对象的属性还是可响应的。

什么是BFC?看懂这一篇就够了

BFC定义

在解释什么是BFC之前,我们先来了解一下Box,Formatting Context的概念

Box:css布局的基本单位

Box是CSS布局的对象和基本单位,直观点来说,就是一个页面是由很多个Box组成的。元素的类型和display属性,决定了这个Box的类型。不同类型的Box,会参与不同的Formatting Context (一个决定如何渲染文档的容器),因此Box内的元素会以不同的方式渲染。让我们看看可能有哪些盒子:

  • block-level box: display属性为block,list-item,table的元素,会生成block-level box。并且参与block fomatting context;
  • inline-level box: display属性为inline,inline-block,inline-table的元素,会生成inline-level box。并且参与inline formatting context
  • run-in box:css3中才有,暂时不讲。

Formatting Context

Formatting Context 是 W3C CSS2.1规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定其子元素如何定位,以及和其他元素的关系和相互作用。最常见的Formatting context 有Block formatting context(简称BFC) 和Inline foramtting context(简称IFC)

BFC是一个独立的布局环境,其中的元素布局是不受外界的影响,并且在一个BFC中,块盒和行盒(行盒由一行中所有的内敛元素所组成)都会垂直的沿着其父元素的边框排列。
###BFC的布局规则

  • 内部的Box会在垂直方向,一个接一个的放置
  • Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box和margin会发生重叠
  • 每个盒子(块盒和行盒)的margin box的左边,与包含块border box的左边相接触(对于从右到左的格式化,否则相反)。即时存在浮动也是如此。
  • BFC的区域不会与float box重叠
  • BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此
  • 计算BFC的高度时,浮动元素也参与计算。
    ###偈创建BFC
  1. float的值不是none
  2. position的值不是static或者relative
  3. display的值时inline-block、table-cell、flex、table-caption或者inline-flex
  4. overflow的值不是visible

BFC的作用

1. 利用BFC避免margin重叠





    
    
    
    <title>防止margin重叠</title>

<style>
    *{
        margin: 0;
        padding: 0;
    }
    p {
        color: #f55;
        background: yellow;
        width: 200px;
        line-height: 100px;
        text-align:center;
        margin: 30px;
    }
</style>

    

看看我的 margin是多少

看看我的 margin是多少

前端性能优化与监控

* 减少http请求

* 多频操作、防抖节流

* 服务端渲染、静态资源使用CDN

* 图片尽量使用webp icon

* 减少不必要的重绘和回流

* 事件委托

* 合理使用css选择器

element-ui el-table发生错位问题怎么处理

     <style>
        .el-table--border th.gutter:last-of-type { 
            display: block!important; 
            width: 17px!important; 
        }
    </style>
###在app.vue或者index.html中添加以上样式,即可完美解决,其他一些比如:
        this.$nextTick(() => {
              this.$refs.table.doLayout(); //解决表格错位
        });
### 不能很好解决,用css方式解决最完美

JSbridge 在Vue项目中的封装和使用

jsBridge.js

 
let isAndroid = navigator.userAgent.indexOf('Android') > -1 || navigator.userAgent.indexOf('Adr') > -1;
let isiOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);

//这是必须要写的,用来创建一些设置
function setupWebViewJavascriptBridge(callback) {
    //Android使用
    if (isAndroid) {
        if (window.WebViewJavascriptBridge) {
            callback(window.WebViewJavascriptBridge);
        } else {
            document.addEventListener(
                'WebViewJavascriptBridgeReady',
                () => {
                    callback(window.WebViewJavascriptBridge);
                },
                false
            );
        }
        console.log('tag', '安卓');
        sessionStorage.phoneType = 'android';
    }

    //iOS使用
    if (isiOS) {
        if (window.WebViewJavascriptBridge) {
            return callback(window.WebViewJavascriptBridge);
        }
        if (window.WVJBCallbacks) {
            return window.WVJBCallbacks.push(callback);
        }
        window.WVJBCallbacks = [callback];
        var WVJBIframe = document.createElement('iframe');
        WVJBIframe.style.display = 'none';
        WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';
        document.documentElement.appendChild(WVJBIframe);
        setTimeout(() => {
            document.documentElement.removeChild(WVJBIframe);
        }, 0);
        console.log('tag', 'ios');
        sessionStorage.phoneType = 'ios';
    }
}
//注册回调函数,第一次连接时调用 初始化函数(android需要初始化,ios不用)
setupWebViewJavascriptBridge((bridge) => {
    if (isAndroid) {
        //初始化
        bridge.init((message, responseCallback) => {
            var data = {
                'Javascript Responds': 'Wee!'
            };
            responseCallback(data);
        });
    }
});

export default {
    // js调APP方法 (参数分别为:app提供的方法名  传给app的数据  回调)
    callHandler(name, data, callback) {
        setupWebViewJavascriptBridge((bridge) => {
            bridge.callHandler(name, data, callback);
        });
    },
    // APP调js方法 (参数分别为:js提供的方法名  回调)
    registerHandler(name, callback) {
        setupWebViewJavascriptBridge((bridge) => {
            bridge.registerHandler(name, (data, responseCallback) => {
                callback(data, responseCallback);
            });
        });
    }
}

在main.js中引入

import Bridge from './config/JSbridge.js'
Vue.prototype.$bridge = Bridge

在组件中

methods:{
    #### js调用app方法
    sendMsgToAndroid(){
            let msg = "传给app的数据"
            this.$bridge.callHandler('dataToAndroid',msg,(res)=>{
                   alert('获取app响应数据:'+res)
             })
    }
    #### app调用js方法
    getAPPDate(){
          this.$bridge.registerHandler('androiddataToJs', (data, responseCallback) => {
                alert('app主动调用js方法,传入数据:'+ data)
                responseCallback(data)
          })
     }
}


CommonJs模块和ES6模块的区别

CommonJS模块输出的是一个值的拷贝,ES6模块输出的是值的引用。
CommonJS模块是运行时加载,ES6模块是编译时输出接口。

CommonJS模块输出的是值的拷贝,也就是说,一但输出一个值,模块内部变化不会影响这个值

// common.js
var count = 1;

var printCount = () =>{ 
   return ++count;
}

module.exports = {
     printCount: printCount,
     count: count
};
 // index.js
let v = require('./common');
console.log(v.count); // 1
console.log(v.printCount()); // 2
console.log(v.count); // 1

common.js里面改变了count,但是输出的结果还是原来的。这是因为count是一个原始类型的值,会被缓存。除非写成一个函数,才能得到内部变动的值。将common里的module.exports改写成

module.exports = {
     printCount: printCount,
     get count(){
         return count
     }
};

而在es6中,写法是这样的,利用export和import导入的

// es6.js
export let count = 1;
export function printCount() {
     ++count;
}
// main1.js
import  { count, printCount } from './es6';
console.log(count)  // 1
printCount();
console.log(count) // 2

es6模块是动态引入,并且不会缓存,模块里面的便令绑定其所在的模块,而是动态地去加载值,并且不能重新复制
另外还想说一个 export default

let count = 1;
 function printCount() {
     ++count;
} 
export default { count, printCount}
// main3.js
import res form './main3.js'
console.log(res.count)

重绘和回流

浏览器在加载页面的时候会生成一个render(渲染)树,加载完成后当渲染树中的某一些元素发生了比如形状,尺寸,隐藏,由于元素之间位置的相互关系发生改变,都会使渲染树发生改变,从而需要重新构建渲染树,这叫回流

而当渲染树中的某些元素发生的改变不会影响个元素之间的位置关系,比如color,background等只是改变外观,则不需要重建渲染树,这就叫做重绘。

区别:当发生回流时一定发生了重绘,但是当发生重绘时则不一定发生回流

前端怎么每隔1秒渲染一部分数据

  • 工作当中,我们可能会遇到这种情况,后端给前端返回几百条数据,要前端自己渲染,如果前端直接渲染到浏览器,就会卡得你不要不要得。
  • 这个时候,有想法的玩家就有了一些想法,前端可以每隔1秒加载,先加载可视区域,这种方式可行不
function test() {
 let arr = [1, 2, 3]
 arr.forEach(async item => {
  const res = await fetch(item)
  console.log(res)
 })
 console.log('end')
}
 
function fetch(x) {
 return new Promise((resolve, reject) => {
     resolve(x)
 })
}
test()
  • 以上代码, 按照我们的理解是 打印 1 2 3 ‘end’ 实际上是先打印 ‘end’ 1 2 3, 这是为什么呢。
原因如下:
  1. 首先这是因为foreach是没有return返回值的(可以自己去跟下源码,foreach内部实现只是简单的回调)
  2. 而foreach里面的回调函数因为加了async的原因,所以默认会返回一个promise,但是因为foreach的实现并没有返回值,所以导致返回的这个promise对象没人去管了

为了保证 ‘end’ 最后输出,我们肯定要先等待循环的返回结果因此改成如下代

async function test() {
 let arr = [1, 2, 3]
 await arr.forEach(async item => {
  const res = await fetch(item)
  console.log(res)
 })
 console.log('end')
}

但是这样改之后依然行不通,原因是foreach没有返回值,所以我们必须保证循环能够有返回值,所以要将foreach改成map

async function test() {
 let arr = [1, 2, 3]
 await arr.map(async item => {
  const res = await fetch(item)
  console.log(res)
 })
 console.log('end')
}

结果依然不行,然后我们会发现其实map返回的并不是一个promise对象,而是一个包含promise对象的数组[promise, promise, promise],其中每个promise对象都是循环迭代产生的结果。而await是处理不了数组的,它只能处理promise对象。考虑到这一点我们基本上就差不多知道如何改正了、有两种方法。

第一是将循环改成常规的遍历方式

async function test() {
 let arr = [1, 2, 3]
 for(let i in arr){
   const res = await fetch(arr[i])
   console.log(res)              
 }
 console.log('end')
}

第二种就比较高端了,使用Promise.all(),这是一个专门处理promise数组的方法,当async标记的箭头函数返回一个promise对象时,map方法得到的就是一个promise对象数组,然后我们将这个数组丢给Promise.all()去依次执行,然后只需要使用await去等待执行结果,就能保证后面的end在得到结果后才会被输出,得到最终输出结果1,2,3,end

async function test() {
 let arr = [1, 2, 3]
 await Promise.all(arr.map(async item => {
  const res = await fetch(item)
  console.log(res)
 }))
 console.log('end')
}

http请求get和post的本质区别

最直观的区别就是 get是将参数放到url上,post是通过request body 传递参数

大家最能给到的标准答案

  • get在浏览器回退时是无害的,而post会再次提交请求
  • get产生的url地址可以被保留书签,而post不可以
  • get请求会被浏览器主动cache,而post不会,除非手动设置
  • get请求只会进行url编码,而post支持多种编码格式
  • get记录会被完整的保存在浏览器历史记录里,而post的参数不会被保留
  • get请求在url中是又长度限制的,而post则没有此限制,对参数的数据格式,get只接受ASCII编码,而post无限制
  • get比post更不安全,因为参数直接暴露在url上,所以不能用来传递敏感信息
  • get参数通过url传递,post是放在request body中

很遗憾,上面这些答案都是教科书似的答案,不是真正面试官想听到的

get和post最本质的区别是什么???

如果我告诉你,get和post本质上没有区别,你信么
get和post是什么,是http协议中两种发送请求方法
http的底层是tcp/ip。所以get和post的底层也是tcp/ip,也就是说,get和post都是tcp/ip连接
get和post能做的事情是一样的,你要个get加上request body,给post加上url参数,在技术上完全是行得通的
那么,那些所谓的标准区别究竟是什么


在我大万维网世界中,还有另外一种通讯角色:运输公司,不同的浏览器(发起http请求)和服务器(接受http请求)都是不同的运输公司。虽然理论上,你可以在车上加很多货物(url中无限加参数)。
但是运输公司可不傻,装货和卸货都是需要成本的,所以要限制单次运输量来控制降低风险,数据量太大对浏览器和服务器都是很大负担。浏览器只会处理自己规定长度的字节,超出部分,恕不处理。
如果你用了get服务,在requrest body中偷偷藏了数据。不同服务器的处理方式也是不同的,有些浏览器会帮你卸货,读取数据,有些则自动忽略,所以get虽然可以带request body,但是不一定能被接收到
** 总体来说,就是get和post本质上并无差别,但是由于http的规定和浏览器、服务器之间的限制,导致他们在应用过程中有一些些去区别 **

get和post还有一个更大的区别,

简单的说就是:

get产生一个tcp数据包,post产生两个tcp数据包。

长的来说就是:

对于get的请求方式,浏览器会把http header data一并发送过去,服务器响应200(返回数据);

对于post的,浏览器先发送header,服务器响应100 containue,浏览器再次发送 data,服务器响应200(返回数据)。

也就是说get只需要汽车跑一趟就把货送到了,而post得跑两趟,第一趟先和服务器打个招呼,“hai 等下我要送一批货过来,记得迎接一下”,然后再回头把货送过去


因为post需要两步。时间上消耗多一点点。看起来get比post更有效,就有团队推荐使用get代替post来优化网站性能,但是这是一个坑,需要谨慎处理。

  • get和post都有自己的语义,不能随便使用
  • 据研究,在网络良好的情况下。发一次包的时间和发两次包的时间差别几乎可以无视。在网络差多的情况下,两次包TCP在验证数据完整性上,有非常大的优点
  • 并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。

看到这。如果以后有人问你:“get和post区别的时候,你的心情会是这样的”


1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.