【前端】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) | 获取指定键名的键值,如不存在则返回undefined | m.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简介 (1)ECMAScript 6是什么 ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在2015年6月正式发布了。它的目标ÿ…...
Android Shape设置背景
设置背景时,经常这样 android:background“drawable/xxx” 。如果是纯色图片,可以考虑用 shape 替代。 shape 相比图片,减少资源占用,缩减APK体积。 开始使用。 <?xml version"1.0" encoding"utf-8"?…...
什么是GraphQL?它与传统的REST API有什么不同?
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 什么是GraphQL?⭐ 与传统的REST API 的不同⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 欢迎来到前端入门之旅!感兴趣的可以订阅本专栏哦!这个专栏是为那些对Web开发感兴趣…...
如何定时备份使用Docker构建的MySQL容器中的数据库
👨🏻💻 热爱摄影的程序员 👨🏻🎨 喜欢编码的设计师 🧕🏻 擅长设计的剪辑师 🧑🏻🏫 一位高冷无情的编码爱好者 大家好,我是 DevO…...
Java【手撕链表】LeetCode 143. “重排链表“, 图文详解思路分析 + 代码
文章目录 前言一、两数相加1, 题目2, 思路分析2,1 找到中间结点2.2, 逆序后半段链表2.3, 合并两个链表 3, 代码 前言 各位读者好, 我是小陈, 这是我的个人主页, 希望我的专栏能够帮助到你: 📕 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中函数调用和启动第一个任务(栈相关!!!!!!)
本内容仅就一些较难理解的点讲解,请结合其它文章实用 在函数调用时,m3的处理器使用r0-r3共四个寄存器传参,其余的使用栈传参。 但是,如果传入的参数是全局变量,则不需传参,因为全局变量在函数内部是可见的…...
【PHP】如何关闭buffer实时输出内容到前端
前言 默认情况下,我们在PHP里使用echo等函数输出的内容,是不会马上发送给前端的,原因是有 buffer 的存在,buffer又分两处,一处是PHP本身的buffer,另一处是Nginx的buffer。只有当buffer满了之后,…...
Scala第二章节
Scala第二章节 scala总目录 章节目标 掌握变量, 字符串的定义和使用掌握数据类型的划分和数据类型转换的内容掌握键盘录入功能理解Scala中的常量, 标识符相关内容 1. 输出语句和分号 1.1 输出语句 方式一: 换行输出 格式: println(里边写你要打印到控制台的数据);方式二…...
Spring修炼之路(2)依赖注入(DI)
一、概念 依赖注入(Dependency Injection,DI)。 测试pojo类 : Address.java 依赖 : 指Bean对象的创建依赖于容器 . Bean对象的依赖资源 . 注入 : 指Bean对象所依赖的资源 , 由容器来设置和装配 . 二、 注入方式 2.1构造器注入 我们在之前的案例已经…...
编写Android.mk / Android.bp 引用三方 jar 包,aar包,so 库
一.前言 在Android10之后,所有项目工程中,官方推荐使用Android.bp去编译构建,以前使用Android.mk构建的项目随着版本迭代升级,慢慢需要变更为Android.bp, 两者的语法都需要去了解并熟练使用。 笔者之前写过Android.mk的…...
【kylin】【ubuntu】搭建本地源
文章目录 一、制作一个本地源仓库制作ubuntu本地仓库制作kylin本地源 二、制作内网源服务器ubuntu系统kylin系统 三、使用内网源ubuntukylin 一、制作一个本地源仓库 制作ubuntu本地仓库 首先需要构建一个本地仓库,用来存放软件包 mkdir -p /path/to/localname/pac…...
为什么 Go 语言 struct 要使用 tags
在 Go 语言中,struct 是一种常见的数据类型,它可以用来表示复杂的数据结构。在 struct 中,我们可以定义多个字段,每个字段可以有不同的类型和名称。 除了这些基本信息之外,Go 还提供了 struct tags,它可以用…...
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 题目: 一个主持人只能参加一个活动,至少需要多少主持人 思路: 对start, end排序从小到大;初始化指针l, r 0, 0;start[r]< end[l]时需要累加人数同时r,否则l,r同时移动;直至不再满中l<n &&am…...
Elasticsearch 集群时的内部结构是怎样的?
Apache Lucene : Flush, Commit Elasticsearch 是一个基于 Apache Lucene 构建的搜索引擎。 它利用 Lucene 的倒排索引、查询处理和返回搜索结果等功能来执行搜索。 它还扩展了 Lucene 的功能,添加分布式处理功能以支持大型数据集的搜索。 让我们看一下 Apache Luc…...
IoTDB 在国际数据库性能测试排行榜中位居第一?测试环境复现与流程详解第一弹!...
最近我们得知,Apache IoTDB 多项性能表现位居 benchANT 时序数据库排行榜(Time Series: DevOps)性能排行第一名!(榜单地址:https://benchANT.com/ranking/database-ranking) benchANT 位于德国&…...
react项目优化
随着项目体积增大,打包的文件体积会越来越大,需要优化,原因无非就是引入的第三方插件比较大导致,下面我们先介绍如何分析各个文件占用体积的大小。 1.webpack-bundle-analyzer插件 如果是webpack作为打包工具的项目可以使用&…...
青藏高原1-km分辨率生态环境质量变化数据集(2000-2020)
青藏高原平均海拔4000米以上,人口1300万,是亚洲九大河流的源头,为超过15亿人口提供淡水、食物和其他生态系统服务,被誉为地球第三极和亚洲水塔。然而,在该地区的人与自然的关系的研究是有限的,尤其是在精细…...
Nature Communications | 张阳实验室:端到端深度学习实现高精度RNA结构预测
RNA分子是基因转录的主要执行者,也是细胞运作的隐形功臣。它们在基因表达调控、支架构建以及催化活性等多个生命过程中都扮演着关键角色。虽然RNA如此重要,但由于实验数据的缺乏,准确预测RNA 的三维空间结构仍然是目前计算生物学面临的重大挑…...
提升您的Mac文件拖拽体验——Dropzone 4 for mac
大家都知道,在Mac上进行文件拖拽是一件非常方便的事情。然而,随着我们在工作和生活中越来越多地使用电脑,我们对于这个简单操作的需求也越来越高。为了让您的文件拖拽体验更加高效和便捷,今天我们向大家介绍一款强大的工具——Dro…...
Vue之transition组件
Vue提供了transition组件,使用户可以更便捷地添加过渡动画效果。 transition组件 transition组件也是一个抽象组件,并不会渲染出真实dom。Vue会在其第一个真实子元素上添加过渡效果。 props render 这里将render分为两部分,第一部分界定真…...
lenovo联想笔记本电脑ThinkPad X13 AMD Gen2(20XH,20XJ)原装出厂Windows10系统镜像
联想原厂Win10系统,自带所有驱动、出厂主题壁纸、系统属性联想LOGO专属标志、Office办公软件、联想电脑管家等预装程序 链接:百度网盘 请输入提取码 提取码:dolg 适用于型号:20XL,20XJ,20XG,21A1,20XK,20XH,20XF,21A0 所需要…...
php导出cvs,excel打开数字超过16变科学计数法
今天使用php导出cvs,在excel中打开,某一个字段是数字,长度高于16位结果就显示科学计数法 超过15位的话从第16位开始就用0代替了 查询了半天总算解决了就是在后面加上"\t" $data[$key][1] " ".$value[1]."\t";…...
CSS 模糊效果 CSS 黑白效果 CSS调整亮度 对比度 饱和度 模糊效果 黑白效果反转颜色
CSS 模糊效果 CSS 黑白效果 CSS调整亮度 饱和度 模糊效果 黑白效果 实现 调整亮度 饱和度 模糊效果 黑白效果 使用 filter1、模糊2、亮度3、对比度4、饱和度5、黑白效果6、反转颜色7、组合使用8、 filer 完整参数 实现 调整亮度 饱和度 模糊效果 黑白效果 使用 filter 1、模糊…...
蓝桥杯 题库 简单 每日十题 day11
01 质数 质数 题目描述 给定一个正整数N,请你输出N以内(不包含N)的质数以及质数的个数。 输入描述 输入一行,包含一个正整数N。1≤N≤10^3 输出描述 共两行。 第1行包含若干个素数,每两个素数之间用一个空格隔开&…...
dart flutter json 转 model 常用库对比 json_serializable json_model JsonToDart
1.对比 我是一个初学者,一直跟着教材用原生的json,最近发现实在太麻烦了.所以搜索了一下,发现真的有很多现成的解决方案. 网页 https://app.quicktype.io/?ldart 这个是测试下来最好用的 有很多选项,可以使用 json_serializable 也可以不使用 json_serializable 这是推荐最…...
nginx启用了自动目录列表功能的安全漏洞修复方法
一、前言 最近被扫描到安全漏洞,说是nginx启用了自动目录列表功能,现象就是访问http://localhost/file就能看到服务器上的目录 二、修复方法 1.把nginx.conf中的autoindex on改为autoindex off location /file {alias /myuser/userfile/file;autoi…...
vector向量类使用
向量是最简单的 STL 容器,其数据结构与数组相似,占据着一个连续的内存块。 由于内存位置是连续的,所以向量中的元素可以随机访问,访问向量中任何一个元素的时间也是固定的。存储空间的管理是自动的,当要将一个元素插入…...
【Java 进阶篇】MySQL多表查询:内连接详解
MySQL是一种强大的关系型数据库管理系统,允许您在多个表之间执行复杂的查询操作。本文将重点介绍MySQL中的多表查询中的一种重要类型:内连接(INNER JOIN)。内连接用于检索满足两个或多个表之间关联条件的行,它能够帮助…...
网络工程有限公司/品牌企业seo咨询
965. 单值二叉树 难度简单69 如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树。 只有给定的树是单值二叉树时,才返回 true;否则返回 false。 示例 1: 输入:[1,1,1,1,1,null,1] 输出:true示例…...
山东建设公司网站/360站长平台链接提交
先需求分析一下---传统的web应用是在线应用,这其实也是web的特色,对于PC时代问题并不大,但到了移动互联网时代,设备终端位置不再固定,依赖无线信号,网络的可靠性变得更低。比如:在火车上&#x…...
宁波网站制作哪家优惠多/做百度推广的公司电话号码
一般说来,大家认为线程池的大小经验值应该这样设置:(其中N为CPU的个数)如果是CPU密集型应用,则线程池大小设置为N1如果是IO密集型应用,则线程池大小设置为2N1如果一台服务器上只部署这一个应用并且只有这一…...
石家庄站建设费用多少/天津疫情最新消息
二叉树是n(n>0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树组成。 还有一些右斜树 左斜树 满二叉树 完全二叉树之类的 这篇文章 记录 1.二叉树建立…...
如何判断网站被google k/产品设计
字符串 1.单引号和双引号都一样2.单引号可以嵌套双引号,双引号可以嵌套单引号3.单单不能嵌套,双双不能嵌套,需要嵌套怎么办在里面的符号前面加上\用来转义4.charAt(n),打印第n几个数字,数字从0开始,如果参数大于最大长度或者负数,那么返回空字符串5.concat链接字符串 s1"…...
问题反馈的网站怎么做/推广营销方案
*体会静坐的乐趣 *把不用的东西捐出去 *整理相片 *分类放置物品 *从家务中解放出来 *辞掉现在的工作 *种一棵树 *和孩子一起做游戏 *听听流行音乐 *多读书 &a…...