当前位置: 首页 > news >正文

【前端】ECMAScript6从入门到进阶

【前端】ECMAScript6从入门到进阶

1.ES6简介及环境搭建

1.1.ECMAScript 6简介

在这里插入图片描述

(1)ECMAScript 6是什么

ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在2015年6月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。

(2)ECMAScript 和 JavaScript 的关系

ECMAScript是JavaScript的标准,JavaScript是ECMAScript的实现。换句话说,如果说JavaScript是一门语言的话,那么ECMAScript就是这门语言遵循的语法书。

(3)ES6 与 ECMAScript 2015 的关系

2011年的时候,ECMAScript 5.1版本发布,ECMA组织就开始准备6.0版本了。但因为这个版本引入的语法功能太多了,所以不可能通过一个版本就将所有功能涵盖。所以,标准委员会决定,标准在每年的6月份正式发布一次,作为当年的正式版本。接下来的时间,就在这个版本的基础上做改动,直到下一年的6月份,草案就自然变成了新一年的版本。这样一来,就不需要以前的版本号了,只要用年份标记就可以了。

就这样ES6的第一个版本就在2015.6正式发布了,正式名称就是《ECMAScript 2015标准》(简称ES2015)。

1.2.babel工具搭建ES6环境

采用 ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。

  • 首先确保环境中有node
node安装:http://nodejs.cn/download/
  • 初始化工程项目
// 使用默认配置初始化项目
npm init -y
  • 安装对应的依赖包
// 本地安装babel-cli及对应的转化规则
npm install --save-dev babel-cli babel-preset-es2015// 阿里巴巴定制的镜像源
npm install -g cnpm --registry=https://registry.npm.taobao.org
  • 创建项目目录

    • src目录用于存放编写的es6代码

    • dist目录用于存放由es6转化后的代码

  • 配置babel

新建.babelrc文件

// 配置用于转化当前代码的规则集
{"presets": ["es2015"]
}

babel的基本用法

// -o 参数指定输出文件
node_modules/.bin/babel src/index.js -o dist/index.js// -d 参数指定输出目录
node_modules/.bin/babel src -d dist

配置package.json文件实时编译

// 配置启动脚本的命令
"scripts": {// 监听index.js文件,一发生变化就执行babel转译的命令"dev": "babel src -w -d dist",
}

2.新的声明及数据赋值方式

2.1.变量声明let与const

作用域就是变量的有效范围,之前只有全局作用域和函数作用域,现在新增块级作用域。es6中新增let和const两种变量声明方式。

(1)let和const的相同点

  • 只在声明的代码块内有效
if (true) {var a = "a";
}
console.log(a);
// let声明变量,const同理
if (true) {let b = "b";
}
console.log(b);

在这里插入图片描述

  • 在同一作用域内不允许重复声明

在这里插入图片描述

  • 没有变量提升,在声明变量前,不能使用该变量
console.log(a);
var a = 'a';console.log(b);
let b = '1';

在这里插入图片描述

用var声明的变量会存在变量提升的问题,如果用let或者const就会消除变量提升问题,在遇到未定义的变量直接抛错。

(2)let和const的区别

  • const用来声明一个只读的变量
const x = 10;
x = 13;
console.log(x);

注意:const声明的变量同时必须立即赋值,如声明的是简单类型的数据,变量的值不可改变。

在这里插入图片描述

2.2.ES6新数据类型Symbol

在ES6之前JavaScript的原始数据类型有Number、String、Boolean、Null、Undefined。ES6中增加新的Symbol独一无二的类型。

对象的属性名容易产生命名冲突,为保证键名的唯一性,故es6引入Symbol这种新的原始类型数据,确保创建的每个变量都是独一无二的。

  • Symbol类型的数据是类似字符串的数据类型。
  • 由于Symbol函数返回的值是原始类型的数据,不是对象,故Symbol函数前不能使用new命令,否则会报错。
let s = Symbol();
console.log(typeof s);

在这里插入图片描述

let s1 = Symbol();
let s2 = Symbol();
console.log(s1===s2);let l1 = Symbol('lixiang');
let l2 = Symbol('lixiang');
console.log(l1===l2);

在这里插入图片描述

定义对象的唯一属性名

// 在对象里用Symbol作为属性名的三种写法
let s = Symbol();// 第一种方式: 借助数组读取s变量,此时不能用点运算符,点运算符默认后面的参数是字符串
let a = {};
a[s] = 'lixiang'// 第二种方式: 构造时声明
let a = {[s]: 'lixiang'
}// 第三种 Object.defineProperty
let a = {};
Object.defineProperty(a, s, { value: 'lixiang' });

在这里插入图片描述

定义常量

const s = Symbol("李祥");

在这里插入图片描述

2.3.解构赋值详解

(1)什么是解构赋值

解构赋值可以理解为赋值操作的语法糖,它是针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。代码书写上言简意赅,语义明确,也方便了对象数组的读取操作。

ES6中只要某种数据可以循环迭代,都可以进行解构赋值。

(2)数组解构

// 变量多时,对应不上的变成undefined
let [a, b, c] = [1, 2];
console.log(a, b, c);

在这里插入图片描述

// 变量默认值,声明变量时将c默认成6
let [a, b, c = 6] = [1, 2];
console.log(a, b, c);

在这里插入图片描述

// 分割数组,将1赋值给a,2,3成一个新数组
let [a, ...other] = [1, 2, 3];
console.log(a, other);

在这里插入图片描述

// 空内容,将a赋值为1,b赋值为3
let [a,,b] = [1, 2, 3];
console.log(a, b);

在这里插入图片描述

(3)对象解构

//1赋值为a,2赋值为b
let { a, b } = { a: 1, b: 2 };
console.log(a, b);

在这里插入图片描述

//重命名
let { a: aa, b: bb } = { a: 1, b: 2 };
console.log(aa, bb);

在这里插入图片描述

(4)读取接口返回的数据

function fun() {return {name: "张三",hobby: [{title: "篮球",},{title: "唱",},{title: "RAP",},{title: "跳",},],};
}
let {name,hobby: [{ title }],
} = fun();
console.log(name, title);

3.ES6新增的数据操作方法

3.1.ES6提供的新的字符串方法

(1)新增的API

方法描述
includes(string, index)判断字符串中是否包含指定字符串,返回值是布尔值
startsWith(string, index)判断字符串的开头是否包含指定字符串,返回值是布尔值
endsWith(string, index)判断字符串的尾部是否包含指定字符串,返回值是布尔值
repeat(n)repeat() 方法返回一个新字符串,表示将原字符串重复n 次。
padStart(length, str)字符串补齐,用于头部补全
padEnd(length, str)字符串补齐,用于尾部补全
//判断str是否包含an
let str = 'lixiang';
console.log(str.includes('an'));
//从下标为5的字符开始判断是否含an
console.log(str.includes('an',5));

在这里插入图片描述

//判断str是否以l开头
let str = 'lixiang';
console.log(str.startsWith('l'));
//从下标为3的字符开始判断是否以l开头
console.log(str.startsWith('l',3));

在这里插入图片描述

//判断str是否以g结尾
let str = 'lixiang';
console.log(str.endsWith('g'));
//从下标为3的字符开始判断是否以g结尾
console.log(str.startsWith('g',3));

在这里插入图片描述

//入参数字为2,重复两次
let str = 'lixiang';
console.log(str.repeat(2));

在这里插入图片描述

//在lixiang前面补a,补够10位
let str = 'lixiang';
console.log(str.padStart(10, 'a'));

在这里插入图片描述

//在lixiang后面补a,补够10位
let str = 'lixiang';
console.log(str.padEnd(10, 'a'));

在这里插入图片描述

(2)模板字符串

在ES5的时候拼接字符串我们往往这样写。

const name = '李祥';
const age = 18;
const hobbies = '写代码';
const str = '我叫'+name+',今年'+age+'岁,'+'喜欢'+hobbies+'。'

在ES6中新引入的模版字符串,写法如下。

const str = `我叫${name},今年${age}岁,喜欢${hobbies}`
console.log(str);

在这里插入图片描述

(3)使用模板字符串的注意事项

  • 使用模板字符串表示多行字符串时,所有的空格和缩进都会被保留在输出之中。
  • 模板字符串中引入变量,要用 ${变量名} 这样的形式引入才可以。
  • 模板字符串中的${…} 大括号内部可以放入任意的 JavaScript 表达式,可以进行运算、可以引用对象属性、可以调用函数、可以甚至还能嵌套,甚至还能调用自己本身。
3.2.ES6扩展运算符的使用

(1)深拷贝一维数组

const list = [1, 2, 3, 4, 5];
const listCopy = [...list];
console.log(listCopy);

在这里插入图片描述

(2)分割数组

const list = [1, 2, 3, 4, 5];
const [, ...list1] = list;
console.log(list1);

在这里插入图片描述

(3)将数组转化成参数传递给函数

const list = [1, 2];
function fun(a, b) {console.log(a + b);
}
fun(...list);

在这里插入图片描述

3.3.ES6数组的扩展方法

(1)fill:替换数组中的元素,会改变原数组。想要不改变原数组的值,可以采用深拷贝。

const list = [1, 2, 3, 4, 5];
//全部替换成6
const list1 = [...list].fill(6);
//下标从1开始到下表为4之间左闭右开,全部替换成6
const list2 = [...list].fill(6, 1, 4);
console.log(list);
console.log(list1);
console.log(list2);

在这里插入图片描述

(2)find:查询数组中符合条件的元素。

const list = [{ name: "李祥", age: 15 },{ name: "张三", age: 10 },{ name: "李四", age: 19 },{ name: "王武", age: 20 },
];
const result = list.find(function (item) {return item.name === "李祥";
});
console.log(result);

在这里插入图片描述

(3)findIndex:查询数组中符合条件的元素的索引。

const result = list.findIndex(function (item) {return item.name === "李祥";
});
console.log(result);

在这里插入图片描述

(4)flat:用于合并数组。

const list = [1, 2, 3, [4, 5, 6, [ 7, 8]]];
const list2 = list.flat(2);
console.log(list2);

在这里插入图片描述

(5)filter:过滤出符合条件的元素,与find不同的是filter返回一个数组。

const result = list.filter(function (item) {return item.name === "李祥";
});
console.log(result);

在这里插入图片描述

3.4.ES6数组中map方法

map用于将一个类型的数字转换成另外一个类型。

const list = [{ name: "李祥", age: 15 },{ name: "张三", age: 10 },{ name: "李四", age: 19 },{ name: "王武", age: 20 },
];
//遍历集合中每一项,创建obj对象,将原对象属性复制到新的obj中
//然后给obj增加一个属性state
const mapList = list.map(function (i) {let obj = {};//对象拷贝Object.assign(obj, i);obj.sex = 0;return obj;
});
console.log(mapList);

在这里插入图片描述

3.5.ES6对象的新特性

创建对象

const a = {name: 'lixiang',age: 21,address: {city: 'BeiJing',town: 'ChangYang'},
};

(1)深拷贝简单对象

const b = { ...a };
console.log(b);

在这里插入图片描述

(2)给对象设置默认值

const b = { ...a, name: 'zhangsan' };
console.log(b);

在这里插入图片描述

(3)合并对象

const b = { sex:'0' };
const c = {...a,...b}
console.log(c);

在这里插入图片描述

(4)属性初始化、方法的简写

在这里插入图片描述

(5)Object新增的方法

  • Object.is:判断两个对象是否相等
let res = Object.is({name:'lx'}, {name:'lx'});
console.log(res);
let res1 = Object.is(NaN, NaN);
console.log(res1);

在这里插入图片描述

  • Object.assign:对象复制
let a = { name: 'lx', age: 24 };
let b = {};
let c = Object.assign(b, a);
console.log(c);

在这里插入图片描述

  • Object.keys:获取对象所有的key
let a = { name: 'lx', age: 24 };
const arr = Object.keys(a);
console.log(arr);

在这里插入图片描述

  • Object.values:获取对象所有的value
let a = { name: 'lx', age: 24 };
const arr = Object.values(a);
console.log(arr);

在这里插入图片描述

  • Object.entries:获取key和value
let a = { name: 'lx', age: 24 };
const arr = Object.entries(a);
console.log(arr);

在这里插入图片描述

3.6.ES6新增Map与WeakMap

JavaScript中的对象,实质就是键值对的集合,但是在对象里却只能用字符串作为键名。在一些特殊的场景里就满足不了我们的需求了,正因为此,Map这一数据提出了,它是JavaScript中的一种更完善Hash结构。

Map对象:用于保存键值对,任何值(对象或者原始值)都可以作为一个键名或一个值。

  • 属性及方法
属性/方法作用例子
size返回键值对的数量m.size
clear()清除所有键值对m.clear()
has(key)判断键值对中是否有指定的键名,返回值是布尔值m.has(key)
get(key)获取指定键名的键值,如不存在则返回undefinedm.get(key)
set(key, value)添加键值对,如键名已存在,则更新键值对m.set(key, value)
delete(key)删除指定键名的键值对m.delete(key)

(1)创建一个Map

//创建一个空map
let map = new Map();
//创建一个带有默认值的map
let mapDef = new Map([['name','lx'],['age',12]
]);
console.log(map);
console.log(mapDef);

在这里插入图片描述

(2)API演示

//创建一个空map
let map = new Map();
//map中增加一个元素
map.set('name','lx');
map.set('age',20);
console.log(map);
//map中修改一个元素
//map中set方法如果有key则覆盖,没有则新增
map.set('name','zs');
console.log(map);
//返回键值对的数量
console.log(map.size);
//判断是否有某个key
console.log(map.has('name'));
//获取某个key的value
console.log(map.get('name'));
//删除某个key
map.delete('name');
console.log(map);
//清空
map.clear();
console.log(map);

在这里插入图片描述

(3)遍历器生成函数

const keys = map.keys();
const values = map.values();
const entries = map.entries();
console.log(Array.from(keys));
console.log(Array.from(values));
console.log(Array.from(entries));

在这里插入图片描述

WeakMap:只接受对象作为键名,而且无法遍历

const weakMap = new WeakMap([[{ name: 'lx' ,age: 21},{id:1,hobby:'唱、跳、rap、篮球'}]]);
console.log(weakMap);

在这里插入图片描述

在这里插入图片描述

3.7.ES6新增Set与WeakSet

Set是ES6给开发者提供的一种类似数组的数据结构,可以理解为值的集合。它和数组的最大的区别就在于: 它的值不会有重复项。

Set保证成员值唯一,用于集合去重。

  • 属性及方法
属性/方法作用例子
add新增元素s.add(key)
size返回成员个数s.size
clear()清除所有成员s.clear()
has(value)判断键值对中是否有指定的值,返回值是布尔值s.has(key)
delete(value)删除指定值s.delete(key)

(1)创建一个Set

const a = { name: 'lx' };
const set = new Set([a]);
console.log(set);const list = new Set([1, 2, 3, 4]);
console.log(list);

在这里插入图片描述

(2)API演示

const set = new Set([1, 2, 3, 4]);
console.log(set);
//获取set长度
console.log(set.size);
//判断是否存在2元素
console.log(set.has(2));
//删除2元素
set.delete(2);
console.log(set.has(2));

在这里插入图片描述

WeakSet:数组成员必须是对象

  • WeakSet结构也提供了add( ) 方法,delete( ) 方法,has( )方法给开发者使用,作用与用法跟Set结构完全一致。
  • WeakSet 结构不可遍历。因为它的成员都是对象的弱引用,随时被回收机制回收,成员消失。所以WeakSet 结构不会有keys( ),values( ),entries( ),forEach( )等方法和size属性。
3.8.Array与Set的转换
// 数组转set
const list = [1, 2, 3];
const set = new Set(list);
console.log(set);// set转数组
const arr = Array.from(set);
console.log(arr);
3.9.Object与Map的转换
// 对象转map
const obj = { nane: 'lx', age:24 };
const map = new Map(Object.entries(obj));
console.log(map);// map转对象
const obj1 = Object.fromEntries(map);
console.log(obj1);

4.ES6新增高阶知识点

4.1.ES6中新增代理Proxy

(1)Proxy简介

正如Proxy的英译"代理"所示,Proxy是ES6为了操作对象引入的API。它不直接作用在对象上,而是作为一种媒介,如果需要操作对象的话,需要经过这个媒介的同意。

(2)使用方式

/* @params
** target: 用Proxy包装的目标对象
** handler: 一个对象,对代理对象进行拦截操作的函数,如set、get
*/
let p = new Proxy(target, handler)

(3)案例实战

const house = {name: '三室一厅-次卧',price: 1000,phone: '18823139921',id: '20230131',state: '**',
};const handle = {get: function (obj, key) {switch (key) {case 'price':return obj[key] + 500;case 'phone':return obj[key].substring(0, 3) + '****' + obj[key].substring(7);default:return obj[key];}},set: function (obj, key, value) {if (key === 'state') {obj[key] = value;}},
};const houseproxy = new Proxy(house, handle);
console.log(houseproxy.id);
console.log(houseproxy.phone);
console.log(houseproxy.price);
houseproxy.state='****';
console.log(houseproxy.state);

在这里插入图片描述

4.2.ES6中新增反射Refect

(1)Reflect简介

与Proxy相同,ES6引入Reflect也是用来操作对象的,它将对象里一些明显属于语言内部的方法移植到Reflect对象上,它对某些方法的返回结果进行了修改,使其更合理,更具语义化,并且使用函数的方式实现了Object的命令式操作。

  • 属性及方法
属性/方法作用
Reflect.apply(target, thisArg, args)对一个函数进行调用操作,同时可以传入一个数组作为调用参数。
Reflect.construct(target, args)对构造函数进行 new 操作,相当于执行 new target(…args)。
Reflect.get(target,name, receiver)获取对象身上某个属性的值,类似于 target[name]。如果没有该属性,则返回undefined。
Reflect.set(target, name,value, receiver)Reflect.defineProperty方法基本等同于Object.defineProperty,直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,不同的是,Object.defineProperty返回此对象。而Reflect.defineProperty会返回布尔值
Reflect.has(target,name)判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同。
Reflect.ownKeys(target)返回一个包含所有自身属性(不包含继承属性)的数组。(类似于 Object.keys(), 但不会受enumerable影响, Object.keys返回所有可枚举属性的字符串数组).
Reflect.isExtensible(target)判断一个对象是否是可扩展的(是否可以在它上面添加新的属性),类似于 Object.isExtensible()。返回表示给定对象是否可扩展的一个Boolean 。(Object.seal 或 Object.freeze 方法都可以标记一个对象为不可扩展。)
Reflect.preventExtensions(target)让一个对象变的不可扩展,也就是永远不能再添加新的属性。
4.3.Proxy实现数据双向绑定

(1)需求

实现一个双向的数据绑定。

在这里插入图片描述

(2)实现

  • 编写html代码
<body>请输入内容:<input type="text" id = "input"/><br/>实时内容展示:<span id = "span"></span><script src="./js/index.js"></script>
</body>
  • 编写js代码
// 获取dom节点
const input = document.getElementById("input");
const span = document.getElementById("span");
//定义双向绑定的对象
let obj = {};//定义代理对象的handle方法
const handle = {get: function (target, key) {return target[key];},set: function (target, key, value) {if (key === "text" && value) {span.innerHTML = value;return (target[key] = value);}},
};//创建代理对象
const proxy = new Proxy(obj, handle);//创建键盘的监听事件
input.addEventListener("keyup", function (e) {proxy.text = e.target.value;console.log(proxy.text);
});

5.函数的扩展、类及模块化

5.1.函数参数的扩展

(1)函数参数可设置默认值

//求和方法,当a和b都不传值时,默认都为1
function sum(a = 1, b = 1) {return a + b;
}
console.log(sum());
console.log(sum(3));
console.log(sum(3,5));

在这里插入图片描述

(2)rest参数,可变参数

//求和方法,可变参数
function sum(...rest) {let num = 0;rest.forEach((e)=>{num+=e;})return num;
}
console.log(sum(...[1,2]));
console.log(sum(...[1,2,4]));

在这里插入图片描述

5.2.ES6新增箭头函数

(1)箭头函数简介

ES6中允许使用=>来定义函数。箭头函数相当于[匿名函数,并简化了函数定义。

箭头函数在语法上比普通函数简洁多。箭头函数就是采用箭头=>来定义函数,省去关键字function。

无参:()=>{},等同于:function (){}
有参:(a,b)=>{},等同于:function (a,b){}

(2)箭头函数不绑定this

//箭头函数this指当前块级作用域
const obj = {num: 10,sum() {setTimeout(() => {console.log(this.num);}, 1000);},
};
obj.sum();

在这里插入图片描述

如果不是箭头函数,setTimeout()函数调用指的是当前window。

const obj = {num: 10,sum() {setTimeout(function (){console.log(this);}, 1000);},
};
obj.sum();

在这里插入图片描述

(3)什么情况下不能箭头函数

  • 定义对象的方法
const obj = {num: 10,sum:() => {setTimeout(() => {console.log(this.num);}, 1000);},
};
obj.sum();

在这里插入图片描述

  • 箭头函数没有arguments
const fun = () => {console.log(arguments);
};
fun();

在这里插入图片描述

  • 定义构造函数
const Car = () => {console.log(this);
};
let car = new Car();

在这里插入图片描述

  • 定义DOM事件的回调函数
const span = document.getElementById("span");
span.addEventListener("click", () => {console.log(this);this.innerHTML = "触发事件";
});

在这里插入图片描述

在这里插入图片描述

const span = document.getElementById("span");
span.addEventListener("click", function () {console.log(this);this.innerHTML = "触发事件";
});

在这里插入图片描述

5.3.ES6中新引入类的概念

ES6之前javascript中只有对象,没有类的概念。它是基于原型的面向对象语言。原型对象特点就是将自身的属性共享给新对象。

(1)定义类

class Person {constructor(name, age) {this.name = name;this.age = age;}sayHello() {console.log(`我是${this.name},今年${this.age}`);}
}
const person = new Person("张三", 18);
person.sayHello();
console.log(person);

在这里插入图片描述

(2)类的继承,重写父类的方法

class Person {constructor(name, age) {this.name = name;this.age = age;}hello() {console.log(`我是${this.name},今年${this.age}`);}
}class Student extends Person {//子类重写父类属性constructor(name, age, sex) {super(name, age);this.sex = sex;}hello() {console.log(`我是${this.name},今年${this.age}岁,性别:${this.sex === '1'?'男':'女'}`);}
}const person = new Student('张三', 18,'1');
person.hello();
console.log(person);

在这里插入图片描述

(3)静态方法和静态属性

//静态方法和静态属性只能由类名进行调用
class Person {static eyes = '眼睛';static hello(){console.log(`我是${this.name}`);}
}console.log(Person.eyes);
Person.hello();

在这里插入图片描述

5.4.ES6新增模块化开发

ES6之前是没有类的概念的,也就没有模块这一说法。理想情况下,开发者应该只注重核心业务的开发,对于其他有一定通用性的业务可以直接引入,也就是模块。多人开发,本应如此。

  • CommonJS:Commonjs是作为Node中模块化规范以及原生模块面世的。
  • AMD和RequireJs:AMD是"Asynchronous Module Definition"的缩写,意思就是"异步模块定义"。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到所有依赖加载完成之后(前置依赖),这个回调函数才会运行。

Import 和 export案例

  • export.js
const name = '李祥';function hello(){console.log('hello word');
}class Car{constructor(name){this.name=name;}run(){console.log(this.name+'跑起来了');}
}export default{name,hello,Car,
}
  • Import.js
import test from './export.js';
console.log(test.name);
test.hello();
  • html中js引入要改成module类型
<script src="./js/import.js" type="module"></script>

在这里插入图片描述

6.ES6改进异步编程

6.1.Promise简介及案例

(1)什么是回调地狱

当异步操作想要有顺序时,只能在一个异步成功以后的回调函数里面嵌套另一个异步的操作,如果嵌套的层数过多就形成了回调地狱。

回调地狱的弊端:后期代码维护比较困难。

promise就是用来解决回调地狱。

promise封装了异步操作。创建一个promise对象,写一个函数作为参数,这个函数参数有两个参数,分别是resolve和reject。函数内部写异步操作,成功调resolve,失败调reject。这时promise对象就可以知道异步操作的状态。p.then(成功执行)p.catch(失败执行)。

promise本质就是一个状态机,记录异步内部操作的状态。

在es6之前写法代码耦合,出错时,无法排除。

function request() {axios.get("a.json").then((res) => {if (res && res.data.code === 0) {console.log(res.data.data.data);axios.get("b.json").then((res) => {if (res && res.data.code === 0) {console.log(res.data.data.data);axios.get("c.json").then((res) => {console.log(res.data.data.data);});}});}});
}request();
  • 简单说Promise就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
  • 从语法上说,Promise 是一个对象,从它可以获取异步操作的的最终状态(成功或失败)。
  • Promise 是一个构造函数,提供统一的 API,Promise里不仅可以存放着异步的代码,也可以放同步的代码。
// 准备阶段
new Promise((resolve, reject) => {})// 成功状态
new Promise((resolve, reject) => {resolve('成功'); // 同步代码
}).then((res) => {console.log(res);
});// 失败状态
new Promise((resolve, reject) => {reject('失败');
}).catch((err) => {console.log(err);
});

在这里插入图片描述

  • Promise对象的状态不受外界影响

    • pending 初始状态

    • resolve 成功状态

    • rejected 失败状态

      Promise 有以上三种状态,只有异步操作的结果可以决定当前是哪一种状态,其他任何操作都无法改变这个状态

  • Promise的状态一旦改变,就不会再变,任何时候都可以得到这个结果,状态不可以逆,只能由 pending变成resolve或者由pending变成rejected

(2)Promise解决回调地狱案例

//先定义三个函数
function requestA() {return new Promise((resolve, reject) => {axios.get("a.json").then((res) => {resolve(res);});});
}function requestB() {return new Promise((resolve, reject) => {axios.get("b.json").then((res) => {resolve(res);});});
}function requestC() {return new Promise((resolve, reject) => {axios.get("c.json").then((res) => {resolve(res);});});
}
function request() {requestA().then((res) => {console.log(res);return requestB();}).then((res) => {console.log(res);return requestC();}).then((res) => {console.log(res);});
}
request();

(3)Promise.all方法

  • Promise.all 实际上是一个函数,它接受一个 promise 数组并返回一个 promise。然后当所有的 promise 都完成时会得到结果数组或者当其中一个被拒绝时会抛出错误。
  • 返回值将会按照参数内的 promise 顺序排列,而不是由调用 promise 的完成顺序决定。
function requestAll() {Promise.all([requestA(), requestB(), requestC()]).then((res) => {console.log(res);}).catch((err) => {console.log(err);});
}
requestAll();

(4)Promise.race方法

Promse.race就是赛跑的意思,传入的promise 数组里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。

function requestRace() {Promise.race([requestA(), requestB(), requestC()]).then((res) => {console.log(res);}).catch((err) => {console.log(err);});
}
requestRace();
6.2.优雅的异步编程async

(1)什么是async

async是异步的简写,Generator(生成器)的语法糖,用于声明一个函数是异步函数。

async function sum(a,b) {await console.log(a+b);
}
sum(1,2);

async 写在函数前,返回一个Promise对象。

async await改造promise.then异步调用。

async function request() {try {const a = await requestA();const b = await requestB();const c = await requestC();console.log(a, b, c);} catch (err) {console.log(err);}
}
request();

相关文章:

【前端】ECMAScript6从入门到进阶

【前端】ECMAScript6从入门到进阶 1.ES6简介及环境搭建 1.1.ECMAScript 6简介 &#xff08;1&#xff09;ECMAScript 6是什么 ECMAScript 6.0&#xff08;以下简称 ES6&#xff09;是 JavaScript 语言的下一代标准&#xff0c;已经在2015年6月正式发布了。它的目标&#xff…...

Android Shape设置背景

设置背景时&#xff0c;经常这样 android:background“drawable/xxx” 。如果是纯色图片&#xff0c;可以考虑用 shape 替代。 shape 相比图片&#xff0c;减少资源占用&#xff0c;缩减APK体积。 开始使用。 <?xml version"1.0" encoding"utf-8"?…...

什么是GraphQL?它与传统的REST API有什么不同?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 什么是GraphQL&#xff1f;⭐ 与传统的REST API 的不同⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣…...

如何定时备份使用Docker构建的MySQL容器中的数据库

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的编码爱好者 大家好&#xff0c;我是 DevO…...

Java【手撕链表】LeetCode 143. “重排链表“, 图文详解思路分析 + 代码

文章目录 前言一、两数相加1, 题目2, 思路分析2,1 找到中间结点2.2, 逆序后半段链表2.3, 合并两个链表 3, 代码 前言 各位读者好, 我是小陈, 这是我的个人主页, 希望我的专栏能够帮助到你: &#x1f4d5; JavaSE基础: 基础语法, 类和对象, 封装继承多态, 接口, 综合小练习图书管…...

C语言 cortex-A7核 按键中断 实验【重点】

一、KEY1 include/key.h #ifndef __KEY_H__ #define __KEY_H__#include "stm32mp1xx_rcc.h" #include "stm32mp1xx_gpio.h" #include "stm32mp1xx_exti.h" #include "stm32mp1xx_gic.h"//RCC/GPIO章节初始化 void hal_rcc_gpio_init…...

freertos中函数调用和启动第一个任务(栈相关!!!!!!)

本内容仅就一些较难理解的点讲解&#xff0c;请结合其它文章实用 在函数调用时&#xff0c;m3的处理器使用r0-r3共四个寄存器传参&#xff0c;其余的使用栈传参。 但是&#xff0c;如果传入的参数是全局变量&#xff0c;则不需传参&#xff0c;因为全局变量在函数内部是可见的…...

【PHP】如何关闭buffer实时输出内容到前端

前言 默认情况下&#xff0c;我们在PHP里使用echo等函数输出的内容&#xff0c;是不会马上发送给前端的&#xff0c;原因是有 buffer 的存在&#xff0c;buffer又分两处&#xff0c;一处是PHP本身的buffer&#xff0c;另一处是Nginx的buffer。只有当buffer满了之后&#xff0c…...

Scala第二章节

Scala第二章节 scala总目录 章节目标 掌握变量, 字符串的定义和使用掌握数据类型的划分和数据类型转换的内容掌握键盘录入功能理解Scala中的常量, 标识符相关内容 1. 输出语句和分号 1.1 输出语句 方式一: 换行输出 格式: println(里边写你要打印到控制台的数据);方式二…...

Spring修炼之路(2)依赖注入(DI)

一、概念 依赖注入&#xff08;Dependency Injection,DI&#xff09;。 测试pojo类 : Address.java 依赖 : 指Bean对象的创建依赖于容器 . Bean对象的依赖资源 . 注入 : 指Bean对象所依赖的资源 , 由容器来设置和装配 . 二、 注入方式 2.1构造器注入 我们在之前的案例已经…...

编写Android.mk / Android.bp 引用三方 jar 包,aar包,so 库

一.前言 在Android10之后&#xff0c;所有项目工程中&#xff0c;官方推荐使用Android.bp去编译构建&#xff0c;以前使用Android.mk构建的项目随着版本迭代升级&#xff0c;慢慢需要变更为Android.bp&#xff0c; 两者的语法都需要去了解并熟练使用。 笔者之前写过Android.mk的…...

【kylin】【ubuntu】搭建本地源

文章目录 一、制作一个本地源仓库制作ubuntu本地仓库制作kylin本地源 二、制作内网源服务器ubuntu系统kylin系统 三、使用内网源ubuntukylin 一、制作一个本地源仓库 制作ubuntu本地仓库 首先需要构建一个本地仓库&#xff0c;用来存放软件包 mkdir -p /path/to/localname/pac…...

为什么 Go 语言 struct 要使用 tags

在 Go 语言中&#xff0c;struct 是一种常见的数据类型&#xff0c;它可以用来表示复杂的数据结构。在 struct 中&#xff0c;我们可以定义多个字段&#xff0c;每个字段可以有不同的类型和名称。 除了这些基本信息之外&#xff0c;Go 还提供了 struct tags&#xff0c;它可以用…...

WebGL笔记:WebGL中JS与GLSL ES 语言通信,着色器间的数据传输示例:用鼠标控制点位

用鼠标控制点位 <canvas id"canvas"></canvas><!-- 顶点着色器 --> <script id"vertexShader" type"x-shader/x-vertex">attribute vec4 a_Position;void main() {// 点位gl_Position a_Position;// 尺寸gl_PointSize…...

算法 主持人调度-(双指针+贪心)

牛客网: BM96 题目: 一个主持人只能参加一个活动&#xff0c;至少需要多少主持人 思路: 对start, end排序从小到大&#xff1b;初始化指针l, r 0, 0&#xff1b;start[r]< end[l]时需要累加人数同时r&#xff0c;否则l,r同时移动&#xff1b;直至不再满中l<n &&am…...

Elasticsearch 集群时的内部结构是怎样的?

Apache Lucene : Flush, Commit Elasticsearch 是一个基于 Apache Lucene 构建的搜索引擎。 它利用 Lucene 的倒排索引、查询处理和返回搜索结果等功能来执行搜索。 它还扩展了 Lucene 的功能&#xff0c;添加分布式处理功能以支持大型数据集的搜索。 让我们看一下 Apache Luc…...

IoTDB 在国际数据库性能测试排行榜中位居第一?测试环境复现与流程详解第一弹!...

最近我们得知&#xff0c;Apache IoTDB 多项性能表现位居 benchANT 时序数据库排行榜&#xff08;Time Series: DevOps&#xff09;性能排行第一名&#xff01;&#xff08;榜单地址&#xff1a;https://benchANT.com/ranking/database-ranking&#xff09; benchANT 位于德国&…...

react项目优化

随着项目体积增大&#xff0c;打包的文件体积会越来越大&#xff0c;需要优化&#xff0c;原因无非就是引入的第三方插件比较大导致&#xff0c;下面我们先介绍如何分析各个文件占用体积的大小。 1.webpack-bundle-analyzer插件 如果是webpack作为打包工具的项目可以使用&…...

青藏高原1-km分辨率生态环境质量变化数据集(2000-2020)

青藏高原平均海拔4000米以上&#xff0c;人口1300万&#xff0c;是亚洲九大河流的源头&#xff0c;为超过15亿人口提供淡水、食物和其他生态系统服务&#xff0c;被誉为地球第三极和亚洲水塔。然而&#xff0c;在该地区的人与自然的关系的研究是有限的&#xff0c;尤其是在精细…...

Nature Communications | 张阳实验室:端到端深度学习实现高精度RNA结构预测

RNA分子是基因转录的主要执行者&#xff0c;也是细胞运作的隐形功臣。它们在基因表达调控、支架构建以及催化活性等多个生命过程中都扮演着关键角色。虽然RNA如此重要&#xff0c;但由于实验数据的缺乏&#xff0c;准确预测RNA 的三维空间结构仍然是目前计算生物学面临的重大挑…...

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

Spark 之 入门讲解详细版(1)

1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室&#xff08;Algorithms, Machines, and People Lab&#xff09;开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目&#xff0c;8个月后成为Apache顶级项目&#xff0c;速度之快足见过人之处&…...

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

大数据学习(132)-HIve数据分析

​​​​&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4…...

深度学习习题2

1.如果增加神经网络的宽度&#xff0c;精确度会增加到一个特定阈值后&#xff0c;便开始降低。造成这一现象的可能原因是什么&#xff1f; A、即使增加卷积核的数量&#xff0c;只有少部分的核会被用作预测 B、当卷积核数量增加时&#xff0c;神经网络的预测能力会降低 C、当卷…...

#Uniapp篇:chrome调试unapp适配

chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器&#xff1a;Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...

毫米波雷达基础理论(3D+4D)

3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文&#xff1a; 一文入门汽车毫米波雷达基本原理 &#xff1a;https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...

人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent

安全大模型训练计划&#xff1a;基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标&#xff1a;为安全大模型创建高质量、去偏、符合伦理的训练数据集&#xff0c;涵盖安全相关任务&#xff08;如有害内容检测、隐私保护、道德推理等&#xff09;。 1.1 数据收集 描…...