6月29日得物一面

发布时间 2023-06-29 16:13:49作者: Mr、Kr

一、Object.prototype.toString() 的调用

对于 Object.prototype.toString() 方法,会返回一个形如 "[object XXX]" 的字符串。

如果对象的 toString() 方法未被重写,就会返回如上面形式的字符串。

({}).toString();     // => "[object Object]"
Math.toString();     // => "[object Math]"

 

但是,大多数对象,toString() 方法都是重写了的,这时,需要用 call()Reflect.apply() 等方法来调用。

var x = {
  toString() {
    return "X";
  },
};

x.toString();                                     // => "X"

Object.prototype.toString.call(x);                // => "[object Object]"

Reflect.apply(Object.prototype.toString, x, []);  // => "[object Object]"

二、Object.prototype.toString() 的原理

对于 Object.prototype.toString.call(arg),若参数为 null 或 undefined,直接返回结果。


Object.prototype.toString.call(null);       // => "[object Null]"
Object.prototype.toString.call(undefined);  // => "[object Undefined]"

 

若参数不为 nullundefined,则将参数转为对象,再作判断。对于原始类型,转为对象的方法即装箱,此处不赘述。

转为对象后,取得该对象的 [Symbol.toStringTag] 属性值(可能会遍历原型链)作为 tag,如无该属性,或该属性值不为字符串类型,则依下表取得 tag, 然后返回 "[object " + tag + "]" 形式的字符串。

// Boolean 类型,tag 为 "Boolean"
Object.prototype.toString.call(true);            // => "[object Boolean]"

// Number 类型,tag 为 "Number"
Object.prototype.toString.call(1);               // => "[object Boolean]"

// String 类型,tag 为 "String"
Object.prototype.toString.call("");              // => "[object String]"

// Array 类型,tag 为 "String"
Object.prototype.toString.call([]);              // => "[object Array]"

// Arguments 类型,tag 为 "Arguments"
Object.prototype.toString.call((function() {
  return arguments;
})());                                           // => "[object Arguments]"

// Function 类型, tag 为 "Function"
Object.prototype.toString.call(function(){});    // => "[object Function]"

// Error 类型(包含子类型),tag 为 "Error"
Object.prototype.toString.call(new Error());     // => "[object Error]"

// RegExp 类型,tag 为 "RegExp"
Object.prototype.toString.call(/\d+/);           // => "[object RegExp]"

// Date 类型,tag 为 "Date"
Object.prototype.toString.call(new Date());      // => "[object Date]"

// 其他类型,tag 为 "Object"
Object.prototype.toString.call(new class {});    // => "[object Object]"

 

下面为部署了 Symbol.toStringTag 的例子。可以看出,属性值期望是一个字符串,否则会被忽略。

var o1 = { [Symbol.toStringTag]: "A" };
var o2 = { [Symbol.toStringTag]: null };

Object.prototype.toString.call(o1);      // => "[object A]"
Object.prototype.toString.call(o2);      // => "[object Object]"

 

Symbol.toStringTag 也可以部署在原型链上:

class A {}
A.prototype[Symbol.toStringTag] = "A";
Object.prototype.toString.call(new A());   // => "[object A]"

 

新标准引入了 [Symbol.toStringTag] 属性,是为了把此方法接口化,用于规范新引入的对象对此方法的调用。但对于“老旧”的对象,就只能直接输出值,以保证兼容性。

 

 

三、部署了此属性的内置对象

下面,我列出所有部署了此属性的内置对象。

  1. 三个容器对象。这类对象用作命名空间,用于存储同一类方法。
JSON[Symbol.toStringTag];         // => "JSON"

Math[Symbol.toStringTag];         // => "Math"

Atomics[Symbol.toStringTag];      // => "Atomic"

 

这三个对象的 toString() 都没有重写,直接调用 toString() 方法也可以得到相同的结果。

JSON.toString();         // => "[object JSON]"

Math.toString();         // => "[object Math]"

Atomics.toString();      // => "[object Atomics]"

 

2. 两个新引入的类型 BigIntSymbol

BigInt.prototype[Symbol.toStringTag];      // => "BigInt"

Symbol.prototype[Symbol.toStringTag];      // => "Symbol"

组件的封装

vue组件的定义

● 组件(Component)是Vue.js最强大的功能之一

● 组件可以扩展HTML元素,封装可重用代码

● 在较高层面上,组件是自定义元素,Vue.js的编译器为他添加特殊功能

● 有些情况下,组件也可以表现用 is 特性进行了扩展的原生的HTML元素

● 所有的Vue组件同时也都是Vue实例,所以可以接受相同的选项对象(除了一些根级特有的选项),并提供相同的生命周期钩子
 

vue组件的功能

1)能够把页面抽象成多个相对独立的模块

2)实现代码重用,提高开发效率和代码质量,使得代码易于维护

Vue组件封装过程

● 首先,使用Vue.extend()创建一个组件

● 然后,使用Vue.component()方法注册组件

● 接着,如果子组件需要数据,可以在props中接受定义

● 最后,子组件修改好数据之后,想把数据传递给父组件,可以使用emit()方法

组件使用流程详细介绍

1、组件创建---有3中方法,extend()      <template id=''>      <script type='text/x-template'  id=''>

A、调用Vue.extend(),创建名为myCom的组件,template定义模板的标签,模板的内容需写在该标签下
 

    var myCom = Vue.extend({
        template: '<div>这是我的组件</div>'
    })

B、<template id='myCom'>标签创建,需要加上id属性

    <template id="myCom">
        <div>这是template标签构建的组件</div>
    </template>

C、<script type='text/x-template' id='myCom'>,需加id属性,同时还得加type="text/x-template",加这个是为了告诉浏览器不执行编译里面的代码

    <script type="text/x-template" id="myCom1">
        <div>这是script标签构建的组件</div>
    </script>

 



2、注册组件----有2中方法,全局注册,局部注册

A1、全局注册:一次注册( 调用Vue.component( 组件名称,为组件创建时定义的变量 ) ),可在多个Vue实例中使用。

我们先用全局注册,注册上面例子中创建的myCom组件

 

  Vue.component('my-com',myCom)

 



A2、全局注册语法糖:不需要创建直接注册的写法

    Vue.component('my-com',{
        'template':'<div>这是我的组件</div>'
    })

 


'my-com'为给组件自定义的名字,在使用时会用到,后面myCom对应的就是上面构建的组件变量。

A3、如果是用template及script标签构建的组件,第二个参数就改为它们标签上的id值

    Vue.component('my-com',{
        template: '#myCom'
    })

 



B1、局部注册:只能在注册该组件的实例中使用,一处注册,一处使用

    var app = new Vue({
        el: '#app',
        components: {
            'my-com': myCom
        }
    })

 



B2、局部注册语法糖:

    var app = new Vue({
        el: '#app',
        components: {
            'my-com': {
               template: '<div>这是我的组件</div>'
            }
        }
    })

 



B3、<template>及<script>创建的组件,局部注册

    var app = new Vue({
        el: '#app',
        components: {
            'my-com': {
               template: '#myCom'
            }
        }
    })

 



3、调用组件

只需要在调用组件的地方,写上组件名字的标签即可

    <div>
        /*调用组件*/
        <my-com></my-com>
    </div>

 



4、栗子

A、全局注册:新建一个html文件,引入vue.js,并且定义2个vue实例app1和app2

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>vue组件</title>
        <script src="vue.js"></script>
    </head>
    <body>
        <div id="app1">
            <my-com></my-com>
        </div>
        <div id="app2">
            <my-com></my-com>
        </div>
     
        <script>
            /*创建组件*/
            var myCom = Vue.extend({
                template: '<div>这是我的组件</div>'
            });
            /*全局注册组件*/
            Vue.component('my-com',myCom);
     
            /*定义vue实例app1*/
            var app1 = new Vue({
                el: '#app1'
            });
     
            /*定义vue实例app2*/
            var app2 = new Vue({
                el: '#app2'
            });
        </script>
    </body>
    </html>

 



显示效果:

可以看到,全局注册的组件在实例app1和实例app2中都可以被调用。

B、局部注册:将创建的组件注册到实例app1下

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>vue组件</title>
        <script src="vue.js"></script>
    </head>
    <body>
        <div id="app1">
            <my-com></my-com>
        </div>
        <div id="app2">
            <my-com></my-com>
        </div>
     
        <script>
            var myCom = Vue.extend({
                template: '<div>这是我的组件</div>'
            });
     
            // Vue.component('my-com',myCom);
            /*局部注册组件*/
            var app1 = new Vue({
                el: '#app1',
                components:{
                    'my-com':myCom
                }
            });
     
            var app2 = new Vue({
                el: '#app2'
            });
        </script>
    </body>
    </html>

 



可以看到只渲染了app1实例下的组件,app2实例虽然调用了该组件,但是因为这个组件没有在其内部注册,也没有全局注册,所以报错说找不到该组件。

C、template 和script标签创建组件

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>vue组件</title>
        <script src="vue.js"></script>
    </head>
    <body>
        <div id="app1">
            <my-com></my-com>
            <my-com1></my-com1>
        </div>
     
        <template id="myCom">
            <div>这是template标签构建的组件</div>
        </template>
     
        <script type="text/x-template" id="myCom1">
            <div>这是script标签构建的组件</div>
        </script>
     
        <script>
            Vue.component('my-com1',{ //全局注册
                template: '#myCom1'
            });
     
            var app1 = new Vue({
                el: '#app1',
                components:{
                    'my-com':{
                        template: '#myCom'  //局部注册
                    }
                }
            });
        </script>
    </body>
    </html>

 



显示效果:

5、异步组件

vue作为一个轻量级前端框架,其核心就是组件化开发。我们一般常用的是用脚手架vue-cli来进行开发和管理,一个个组件即为一个个vue页面,这种叫单文件组件。我们在引用组件之时只需将组件页面引入,再注册即可使用。

当项目比较大型,结构比较复杂时,我们一般选用vue-cli脚手架去构建项目。因为vue-cli集成了webpack环境,使用单文件组件,开发更简单,易上手,尤其是在对组件的处理上。对于原生vue.js,我们就得将组件构建在同一个html的script标签下或者html的外部js中,所有组件集中在一块,不容易管理,这也是原生vue,js的一点不便之处

vue.js可以将异步组件定义为一个工厂函数。

使用$.get获取本地文件会跨域,所以要将项目部署到服务器中
 

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>vue组件</title>
        <script src="vue.js"></script>
        <script type="text/javascript" src='jquery-3.1.1.min.js'></script>
    </head>
    <body>
        <div id="app1">
            <head-com></head-com>
        </div>
        <script>
            Vue.component('head-com', function (resolve, reject) {
                $.get("a.html").then(function (res) {
                    resolve({
                        template: res
                    })
                });
            });
     
            var app1 = new Vue({
                el: '#app1'
            });
     
        </script>
    </body>
    </html>

 


显示效果如下:

6、Vue中的props数据流

通过在注册组件中申明需要使用的props,然后通过props中与模板中传入的对应的属性名,去取用这些值

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>vue组件</title>
        <script src="vue.js"></script>
        <script type="text/javascript" src='jquery-3.1.1.min.js'></script>
    </head>
    <body>
        <div id='app'>
           <my-component name="jiangjiang" come-from="guilin"></my-component>
           <!-- 然后在模板中通过属性传值的方式进行数据的注入 -->
        </div>
        <script>
            Vue.component('my-component', {
              props: ['name', 'comeFrom'],    //在注册组件的时候通过props选项声明了要取用的多个prop
              // 在注册组件的模板中使用到props选项中声明的值
              template: '<p>我叫:{{name}}, 我来自:{{comeFrom}}</p>',
              created: function () {
                console.log('在created钩子函数中被调用')
                console.log('我叫:', this.name)
                console.log('我来自:', this.comeFrom)
              }
            })
     
     
            new Vue({
              el: '#app'
            })
     
     
        </script>
    </body>
    </html>

 



注意:

A、props取值的方式

在注册组件的模板内部template,直接通过prop的名称取值就Ok

    template: '<p>我叫:{{name}}, 我来自:{{comeFrom}}</p>'

 



不在注册组件的模板内部template,用this.prop的方式

    console.log('我来自:', this.comeFrom)

 


B、在template选项属性中,可以写驼峰命名法,也可以写短横线命名法

      在HTML(模板)中,只能写短横线命名法

原因:vue组件的模板可以放在两个地方

a、Vue组件的template选项属性中,作为模板字符串

b、放在.html中[  用script  template标签创建的组件 ],作为HTML

问题在于HTML不区分大小写,所以在vue注册组件中通用的驼峰命名法,不适用于HTML中的Vue模板,在HTML中写入props属性,必须写短横线命名法(把原来props属性中的每个prop大写换成小写,并且在前面加“-”)

将6中的
 

        <div id='app'>
           <my-component name="jiangjiang" come-from="guilin"></my-component>
           <!-- 然后在模板中通过属性传值的方式进行数据的注入 -->
        </div>

改成

        <div id='app'>
           <my-component name="jiangjiang" comeFrom="guilin"></my-component>
           <!-- 然后在模板中通过属性传值的方式进行数据的注入 -->
        </div>

 



显示效果,第二个没有显示

异步组件的实现原理;异步组件的3种实现方式---工厂函数、Promise、高级函数

异步组件实现的本质是2次渲染,先渲染成注释节点,当组件加载成功后,在通过forceRender重新渲染

高级异步组件可以通过简单的配置实现loading   resolve   reject   timeout  4种状态
 

继承

1、原型链继承
核心: 将父类的实例作为子类的原型

  function Parent1() {
    this.name = 'parent1';
    this.play = [1, 2, 3]
  }
  function Child1() {
    this.type = 'child2';
  }
  Child1.prototype = new Parent1();
  console.log(new Child1());
 
  // 潜在的问题
  let s1 = new Child1();
  let s2 = new Child1();
  s1.play.push(4);
  console.log(s1.play, s2.play); // [1,2,3,4]   [1,2,3,4]
  // 两个实例使用的是同一个原型对象。它们的内存空间是共享的,当一个发生变化的时候,另外一个也随之进行了变化,这就是使用原型链继承方式的一个缺点。


特点:
1.非常纯粹的继承关系,实例是子类的实例,也是父类的实例
2.父类新增原型方法/原型属性,子类都能访问到
3.简单,易于实现

缺点:
1.要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放到构造器中
2.无法实现多继承
3.来自原型对象的所有属性被所有实例共享(来自原型对象的引用属性是所有实例共享的)
4.创建子类实例时,无法向父类构造函数传参

2、构造函数继承(借助 call)
核心:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)

  function Parent1(){
    this.name = 'parent1';
  }
 
  Parent1.prototype.getName = function () {
    return this.name;
  }
 
  function Child1(){
    Parent1.call(this);
    this.type = 'child1'
  }
 
  let child = new Child1();
  console.log(child);  // 没问题
  console.log(child.getName());  // 会报错


特点:
1.解决了1中,子类实例共享父类引用属性的问题
2.创建子类实例时,可以向父类传递参数
3.可以实现多继承(call多个父类对象)

缺点:
1.实例并不是父类的实例,只是子类的实例
2.只能继承父类的实例属性和方法,不能继承原型属性/方法
3.无法实现函数复用,每个子类都有父类实例函数的副本,影响性能

3、组合继承(前两种组合)
核心:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用

  function Parent3 () {
    this.name = 'parent3';
    this.play = [1, 2, 3];
  }
 
  Parent3.prototype.getName = function () {
    return this.name;
  }
  function Child3() {
    // 第二次调用 Parent3()
    Parent3.call(this);
    this.type = 'child3';
  }
 
  // 第一次调用 Parent3()
  Child3.prototype = new Parent3();
  // 手动挂上构造器,指向自己的构造函数
  Child3.prototype.constructor = Child3;
  var s3 = new Child3();
  var s4 = new Child3();
  s3.play.push(4);
  console.log(s3.play, s4.play);  // 不互相影响
  console.log(s3.getName()); // 正常输出'parent3'
  console.log(s4.getName()); // 正常输出'parent3'


特点:
1.弥补了方式2的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法
2.既是子类的实例,也是父类的实例
3.不存在引用属性共享问题
4.可传参
5.函数可复用

缺点:
调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)

4、原型式继承
ES5 里面的 Object.create 方法,这个方法接收两个参数:一是用作新对象原型的对象、二是为新对象定义额外属性的对象(可选参数)

  let parent4 = {
    name: "parent4",
    friends: ["p1", "p2", "p3"],
    getName: function() {
      return this.name;
    }
  };
 
  let person4 = Object.create(parent4);
  person4.name = "tom";
  person4.friends.push("jerry");
  let person5 = Object.create(parent4);
  person5.friends.push("lucy");
 
  console.log(person4.name); // tom
  console.log(person4.name === person4.getName()); // true
  console.log(person5.name); // parent4
  console.log(person4.friends); // ['p1', 'p2', 'p3', 'jerry', 'lucy']
  console.log(person5.friends); // ['p1', 'p2', 'p3', 'jerry', 'lucy']



通过 Object.create 这个方法可以实现普通对象的继承,不仅仅能继承属性,同样也可以继承 getName 的方法。
第一个结果“tom”,比较容易理解,person4 继承了 parent4 的 name 属性,但是在这个基础上又进行了自定义。
第二个是继承过来的 getName 方法检查自己的 name 是否和属性里面的值一样,答案是 true。
第三个结果“parent4”也比较容易理解,person5 继承了 parent4 的 name 属性,没有进行覆盖,因此输出父对象的属性。
最后两个输出结果是一样,其实 Object.create 方法是可以为一些对象实现浅拷贝的。

5、寄生式继承
使用原型式继承可以获得一份目标对象的浅拷贝,然后利用这个浅拷贝的能力再进行增强,添加一些方法,这样的继承方式就叫作寄生式继承。

虽然其优缺点和原型式继承一样,但是对于普通对象的继承方式来说,寄生式继承相比于原型式继承,还是在父类基础上添加了更多的方法。

   let parent5 = {
    name: "parent5",
    friends: ["p1", "p2", "p3"],
    getName: function() {
      return this.name;
    }
  };
 
  function clone(original) {
    let clone = Object.create(original);
    clone.getFriends = function() {
      return this.friends
    };
    return clone;
  }
 
  let person5 = clone(parent5);
  console.log(person5.getName()); // parent5
  console.log(person5.getFriends()); //  ['p1', 'p2', 'p3']



通过上面这段代码,我们可以看到 person5 是通过寄生式继承生成的实例,它不仅仅有 getName 的方法,而且可以看到它最后也拥有了 getFriends 的方法。

6、寄生组合式继承
结合第四种中提及的继承方式,解决普通对象的继承问题的 Object.create 方法,我们在前面这几种继承方式的优缺点基础上进行改造,得出了寄生组合式的继承方式,这也是所有继承方式里面相对最优的继承方式。

  function clone (parent, child) {
    // 这里改用 Object.create 就可以减少组合继承中多进行一次构造的过程
    child.prototype = Object.create(parent.prototype);
    child.prototype.constructor = child;
  }
 
  function Parent6() {
    this.name = 'parent6';
    this.play = [1, 2, 3];
  }
   Parent6.prototype.getName = function () {
    return this.name;
  }
  function Child6() {
    Parent6.call(this);
    this.friends = 'child5';
  }
 
  clone(Parent6, Child6);
 
  Child6.prototype.getFriends = function () {
    return this.friends;
  }
 
  let person6 = new Child6();
  console.log(person6);  // child6 {name: "parent6",play: [1, 2, 3], friends: "child5"}
  console.log(person6.getName()); // parent6
  console.log(person6.getFriends()); // child5


通过这段代码可以看出来,这种寄生组合式继承方式,基本可以解决前几种继承方式的缺点,较好地实现了继承想要的结果,同时也减少了构造次数,减少了性能的开销.

总体看下来,这六种继承方式中,寄生组合式继承是这六种里面最优的继承方式

ES6 提供了继承的关键字 extends

class Person {
  constructor(name) {
    this.name = name
  }
  // 原型方法
  // 即 Person.prototype.getName = function() { }
  // 下面可以简写为 getName() {...}
  getName = function () {
    console.log('Person:', this.name)
  }
}
 
class Gamer extends Person {
  constructor(name, age) {

 

TS范式有哪些

一、泛型是什么?有什么作用

当我们定义一个变量不确定类型的时候有两种解决方式:

    使用any
    使用any定义时存在的问题:虽然 以 知道传入值的类型但是无法获取函数返回值的类型;另外也失去了ts类型保护的优势
    使用泛型
    泛型指的是在定义函数/接口/类型时,不预先指定具体的类型,而是在使用的时候在指定类型限制的一种特性。

二、泛型用法
2.1 在函数中使用泛型

function test <T> (arg:T):T{
  console.log(arg);
  return arg;
}
test<number>(111);// 返回值是number类型的 111
test<string | boolean>('hahaha')//返回值是string类型的 hahaha
test<string | boolean>(true);//返回值是布尔类型的 true

使用方式类似于函数传参,传什么数据类型,T就表示什么数据类型, 使用表示,T也可以换成任意字符串。
2.2 在接口中使用泛型
// 注意,这里写法是定义的方法哦
interface Search {
  <T,Y>(name:T,age:Y):T
}

let fn:Search = function <T, Y>(name: T, id:Y):T {
  console.log(name, id)
  return name;
}
fn('li',11);//编译器会自动识别传入的参数,将传入的参数的类型认为是泛型指定的类型

 



2.3 在类中使用泛型
class Animal<T> {
 name:T;
 constructor(name: T){
  this.name = name;
 }
 action<T>(say:T) {
   console.log(say)
 }
}
let cat = new Animal('cat');
cat.action('mimi')



三、泛型约束
3.1使用接口约束泛型
interface Person {
  name:string;
  age:number;
}
function student<T extends Person>(arg:T):T {
  return arg;
}

student({name:'lili'});//类型 "{ name: string; }" 中缺少属性 "age",但类型 "Person" 中需要该属性
student({ name: "lili" , age:'11'});//不能将类型“string”分配给类型“number”
student({ name: "lili" , age:11});

3.2 数组泛型

let arr:Array<number> =[1,2,3] === let arr:number[]=[1,2,3]

 


四、泛型工具类型
4.1 Partial

partial<T>的作用就是将某个类型中的属性全部变为可选项?
示例:
interface Person {
  name:string;
  age:number;
}
function student<T extends Person>(arg: Partial<T>):Partial<T> {
  return arg;
}

4.2 Record

Record<K extends keyof any, T>的作用是将K中所有的属性转换为T类型;示例:
interface PageInfo {
  title: string
}
type Page = 'home'|'about'|'other';
const x: Record<Page, PageInfo> = {
  home: { title: "xxx" },
  about: { title: "aaa" },
  other: { title: "ccc" },
};

 



4.3 Pick

Pick<T, K extends keyof T>的作用是将某个类型中的子属性挑出来,变成包含这个类型部分属性的子类型,示例:
interface Todo {
  title:string,
  desc:string,
  time:string
}
type TodoPreview = Pick<Todo, 'title'|'time'>;
const todo: TodoPreview ={
  title:'吃饭',
  time:'明天'
}

 



4.4 Exclude

Exclude<T,U>的作用是将某个类型中属于另一个类型的属性移除掉,示例:

type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
const t:T0 ='b';

4.5 ReturnType

returnType<T>的作用是用于获取函数T的返回类型,示例:
type T0 = ReturnType<() => string>; // string
type T1 = ReturnType<(s: string) => void>; // void
type T2 = ReturnType<<T>() => T>; // {}
type T3 = ReturnType<<T extends U, U extends number[]>() => T>; // number[]
type T4 = ReturnType<any>; // any
type T5 = ReturnType<never>; // any
type T6 = ReturnType<string>; // Error
type T7 = ReturnType<Function>; // Error

 

并行请求两个接口后再请求第三个

面试官问我,如何并行请求两个接口,拿到数据后再请求第三个接口?

完蛋,一时大脑一片空白,心想平时还真没遇到过类似场景。

最怕场面突然安静,寂静的几十秒中我惭愧的真想找个地缝钻进去。。。

一:Promise解决

对的,你没想错就是Promise的all方法。

我平时看的ES6关键时刻都到狗肚子去了,明明知道这个语法却联系不到实用场景上。

    // 第一个请求
    let p1 = new Promise((resolve) => {
        axios({
            url: 'http://39.104.22.73:8081/ScoreRead/foreend',  // 列表接口
            method: 'post',
        }).then((resp) => {
            resolve(resp.data.data.num);
        }).catch();
    });

    // 第二个请求
    let p2 = new Promise((resolve) => {
        axios({
            url: 'http://39.104.22.73:8888/TagRead/foreend', // 标签列表接口
            method: 'post',
        }).then((resp) => {    
            resolve(resp.data.data.length);
        }).catch();
    });

    // 静态方法all的then方法就等同于,多个promise实例方法的多个then汇集
    Promise.all([p1,p2]).then((value)=>{
        console.log(value);
        $("#promise3").html(`${value[0]} + ${value[1]}`);
        // 这里可以再执行第三个请求
    });

 

 

二:Axios的写法

function getUserAccount() {
  return axios.get('/user/12345');
}
 
function getUserPermissions() {
  return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
  .then(axios.spread(function (acct, perms) {
    // 两个请求现在都执行完成
  }));