ES6新特性2- Promise的介绍和使用,map和set集合,ES6-新增对象方法, async和await
目录
一、Promise简介
二、Promise的三种状态
三、Promise的基本用法
四、Promise的实例方法
五、Promise的链式调用
六、Promise封装读取文件
步骤
七、promise封装AJAX请求
map和set()
map()
Set
拓展
注意
ES6-新增对象方法
1. Object.is()
2. Object.assign()
3. Object.getOwnPropertyDescriptors()
4. Object.setPrototypeOf() 和 Object.getPrototypeOf()
5. Object.keys()、Object.values() 和 Object.entries()
6. Object.fromEntries()
async和await
一、async
二、await
三、使用示例
四、注意事项
一、Promise简介
Promise是ES6(ECMAScript 2015)引入的一个重要特性,它是异步编程的一种解决方案。在Promise出现之前,JavaScript的异步操作大多依赖于回调函数,但随着异步操作的复杂度增加,回调函数会出现“回调地狱”的问题,即过度使用嵌套回调函数导致代码的可读性和维护性变差。Promise的出现解决了这一问题,它提供了一种更优雅、更清晰的异步编程方式。
二、Promise的三种状态
Promise对象有三种状态:
- Pending(进行中):Promise对象初始状态,既没有被兑现(fulfilled),也没有被拒绝(rejected)。
- Fulfilled(已成功):意味着操作成功完成。
- Rejected(已失败):意味着操作失败。
Promise的状态只能从Pending变为Fulfilled或Rejected,且状态一旦改变,就不可逆转。
三、Promise的基本用法
- 创建Promise对象
const promise = new Promise((resolve, reject) => {
// 异步操作
if (/* 异步操作成功 */) {
resolve(value); // 将Promise对象的状态从Pending变为Fulfilled
} else {
reject(error); // 将Promise对象的状态从Pending变为Rejected
}
});
- 使用Promise对象
Promise对象提供了.then()
、.catch()
和.finally()
方法用于处理异步操作的结果或错误。
.then()
方法接受两个可选的回调函数作为参数,第一个回调函数在Promise对象的状态变为Fulfilled时调用,第二个回调函数在Promise对象的状态变为Rejected时调用。.catch()
方法是.then(null, rejectionHandler)
的简写形式,专门用于捕获前面链中任何.then()
的错误。.finally()
方法无论Promise最后的状态如何,都会执行提供的回调函数,常用于资源清理或UI恢复等场景。
四、Promise的实例方法
- .then()
promise.then(
function(value) {
// 处理Fulfilled状态
},
function(error) {
// 处理Rejected状态
}
);
- .catch()
promise.catch(function(error) {
// 处理错误
});
- .finally()
promise.finally(function() {
// 不管Promise最终是fulfilled还是rejected都会执行的代码
});
五、Promise的构造函数方法
- Promise.all()
Promise.all()
方法接受一个Promise数组作为参数,当所有Promise都变为Fulfilled时,返回一个包含所有结果的数组;当任意一个Promise变为Rejected时,立即返回该Promise的错误信息。
Promise.all([promise1, promise2, promise3])
.then(function(values) {
// 处理成功
})
.catch(function(error) {
// 处理失败
});
- Promise.race()
Promise.race()
方法与Promise.all()
类似,也接受一个Promise数组作为参数,但是只要有一个Promise变为Fulfilled或Rejected时,立即返回该Promise的结果或错误信息。
Promise.race([promise1, promise2, promise3])
.then(function(value) {
// 处理成功
})
.catch(function(error) {
// 处理失败
});
- Promise.allSettled()
Promise.allSettled()
方法也接受一个Promise数组作为参数,当所有Promise都被resolved时(无论是fulfilled还是rejected),返回一个包含所有结果的数组(每个结果包括状态和值)。
Promise.allSettled([promise1, promise2, promise3])
.then(function(results) {
// 处理成功
})
.catch(function(error) {
// 处理失败(注意:Promise.allSettled()本身不会rejected,因此这里的catch通常不会执行)
});
- Promise.resolve() 和 Promise.reject()
Promise.resolve()
:创建并返回一个已经resolved的Promise,通常用于将非Promise值转换为Promise,或者快速返回一个成功的Promise。Promise.reject()
:创建并返回一个已经被rejected的Promise,用于快速抛出错误。
五、Promise的链式调用
Promise支持链式调用,可以使用.then()
方法将多个异步操作串起来执行。每个.then()
方法返回一个新的Promise对象,因此可以继续调用.then()
方法进行下一步操作。
promise
.then(function(result1) {
return result2; // 或者返回另一个Promise对象
})
.then(function(result2) {
return result3;
})
.catch(function(error) {
// 处理错误
})
.finally(function() {
// 清理资源或恢复UI
});
六、Promise封装读取文件
const fs = require('fs').promises;
// 定义一个异步函数来读取文件
async function readFileAsync(filePath) {
try {
const data = await fs.readFile(filePath, 'utf8');
console.log('文件内容:', data);
} catch (error) {
console.error('读取文件时出错:', error);
}
}
// 调用函数并传入文件路径
const filePath = './example.txt';
readFileAsync(filePath);
步骤
引入fs.promises
const fs = require('fs').promises;
fs.promises 提供了一组返回Promise的方法,用于文件系统操作。
定义异步函数readFileAsync:
async function readFileAsync(filePath) {
读取文件:
const data = await fs.readFile(filePath, 'utf8');
//使用await关键字等待fs.readFile方法返回的Promise解决,并将文件内容存储在data变量中。第二个参数'utf8'指定了文件的编码格式。
处理文件内容或错误:
console.log('文件内容:', data);
//如果文件读取成功,将文件内容打印到控制台。
} catch (error) {
console.error('读取文件时出错:', error);
}
//如果文件读取失败,捕获错误并打印到控制台。
调用函数:
const filePath = './example.txt';
readFileAsync(filePath);
//调用readFileAsync函数并传入文件路径
七、promise封装AJAX请求
// 定义一个函数,该函数返回一个Promise对象
function ajaxRequest(url, method = 'GET', data = null) {
return new Promise((resolve, reject) => {
// 创建一个XMLHttpRequest对象
const xhr = new XMLHttpRequest();
// 初始化请求
xhr.open(method, url, true);
// 设置请求头(如果需要)
// xhr.setRequestHeader('Content-Type', 'application/json');
// 处理请求完成后的响应
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) {
// 请求成功,解析并返回响应数据
try {
const response = JSON.parse(xhr.responseText);
resolve(response);
} catch (error) {
reject(new Error('Error parsing JSON response'));
}
} else {
// 请求失败,返回错误信息
reject(new Error(`Request failed with status ${xhr.status}: ${xhr.statusText}`));
}
};
// 处理网络错误
xhr.onerror = () => {
reject(new Error('Network Error'));
};
// 发送请求(如果是POST请求,则传递数据)
if (method === 'POST' && data !== null) {
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
xhr.send(JSON.stringify(data));
} else {
xhr.send();
}
});
}
// 使用示例
ajaxRequest('https://api.example.com/data')
.then(response => {
console.log('Success:', response);
})
.catch(error => {
console.error('Error:', error.message);
});
// 发送POST请求的示例
const postData = { key: 'value' };
ajaxRequest('https://api.example.com/submit', 'POST', postData)
.then(response => {
console.log('POST Success:', response);
})
.catch(error => {
console.error('POST Error:', error.message);
});
定义函数ajaxRequest:
该函数接收三个参数:url(请求的URL),method(请求方法,默认为GET),data(请求数据,默认为null)。
返回一个Promise对象。
创建XMLHttpRequest对象:
使用new XMLHttpRequest()创建一个新的请求对象。
初始化请求:
使用xhr.open(method, url, true)初始化请求。
设置请求头:
如果需要发送JSON数据,可以添加Content-Type头。
处理响应:
使用xhr.onload处理请求完成后的响应。
如果响应状态码在200到299之间,则解析JSON数据并调用resolve。
如果响应状态码不在此范围内,则调用reject。
处理网络错误:
使用xhr.onerror处理网络错误。
发送请求:
根据请求方法(GET或POST)调用xhr.send()发送请求。
如果是POST请求,则将数据转换为JSON字符串并发送。
使用示例:
// 发送POST请求的示例
const postData = { key: 'value' };
ajaxRequest('https://api.example.com/submit', 'POST', postData)
.then(response => {
console.log('POST Success:', response);
})
.catch(error => {
console.error('POST Error:', error.message);
});
map和set()
map()
map()对象用于保存键值对,任何JS支持的值都可以作为一个键(key)或者是一个value()
与对象的不同之处:
- Object()的键只能是字符串或是ES6的symbol(),而map()可以是任何值
- Map 提供了 get()、set()、has()、delete() 和 clear() 等方法
- map对象有一个size属性可以获取map的大小(即键值对的个数)
// 使用字符串字面量作为键
var map1 = new Map([['name', 'ren'], ['age', 18]]);
// 添加一个新的键值对到 Map 中
// 注意:'score' 也应该是一个字符串字面量,除非您之前已经声明了变量 score
map1.set('score', 85);
console.log(map1); // 输出 Map(3) { 'name' => 'aille', 'age' => 18, 'score' => 85 } 或类似格式
// 从 Map 中删除一个键值对
map1.delete('age');
// 检查 Map 中是否包含某个键
console.log(map1.has('score')); // 输出 true
// 获取 Map 中与某个键关联的值
console.log(map1.get('score')); // 输出 85
// 获取 Map 的大小
console.log(map1.size); // 输出 2
// 清空 Map
map1.clear();
console.log(map1.size); // 输出 0
Set
Set 是一种集合数据结构,它允许你存储任何类型的唯一值(即没有重复的值)。Set 对象是值的集合,其中的值都是唯一的,没有重复的值 。
- Map 提供了 add()、has()、delete() 和 clear() 等方法和size属性
// 创建一个新的 Set
const set1 = new Set([1, 2, 3, 4, 5]);
// 向 Set 中添加一个元素 p
console.log(set1);
//向set()中添加一个元素
console.log(set1.add(6));
// 检查 Set 中是否包含某个元素
console.log(set1.has(1)); // true
// 从 Set 中删除一个元素
console.log(set1.delete(5));
// 清空 Set
set1.clear();
console.log(set1.size); // 输出 0
拓展
1.利用set可以进行数组去重结合扩展运算符和Array.form()方法
//set(数组去重)
const arr = [1, 2, 3, 4, 5, 5, 6, 7,7, 8, 9, 10];
const set2 = new Set(arr);
//把set转换为数组
const arr2 = [...set2];
console.log(arr2); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const arr3=Array.from(set2);
console.log(arr3); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
2.交集,利用数组方法filter()和set.has方法结合
//交集
const set3 = new Set([1, 2, 3]);
const set4 = new Set([2, 3, 4]);
const intersection = new Set([...set3].filter(value => set4.has(value)));
console.log(intersection); // Set(2) { 2, 3 }
3.并集
//并集
const union = new Set([...set3,...set4]);
console.log(union); // Set(4) { 1, 2, 3, 4 }
4.差集
//差集
const difference = new Set([...set3].filter(value => !set4.has(value)));
console.log(difference); // Set(1) { 1 }
注意
- Set 中的值都是唯一的,不会有重复的值。
- Map 允许使用任何类型作为键(包括对象),而对象的键只能是字符串(或者 Symbol)。
- 当你使用 for...of 循环遍历 Set 或 Map 时,Set 返回的是值,而 Map 返回的是键值对(即 [key, value] 数组)。
ES6-新增对象方法
1. Object.is()
目的:用来比较两个值是否严格相等。
用法:与严格比较符(===)的行为基本一致,但有两个不同之处:+0不等于-0,NaN等于自身。
示例:
console.log(Object.is(+0, -0)); // false
console.log(Object.is(NaN, NaN)); // true
2. Object.assign()
目的:用于将对象合并,将源对象可枚举的属性复制到目标对象。
用法:Object.assign(target, ...sources)。第一个参数是目标对象,后面的参数都是源对象。若目标和源有同名属性,或多个源有同名属性,后面的属性会覆盖前面的属性。该方法只考虑对象自身属性,不考虑继承的属性。
示例:
const target = { a: 1, b: 1 };
const source1 = { b: 2, c: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
console.log(target); // { a: 1, b: 2, c: 3 }
注意:该方法实行的是浅拷贝。
3. Object.getOwnPropertyDescriptors()
目的:用于获取指定对象所有自身属性(非继承属性)的描述对象,解决Object.assign()无法正确拷贝get和set属性的问题。
用法:Object.getOwnPropertyDescriptors(obj)。
示例:
const obj = { foo: 123, get bar() { return 'abc' } };
const descriptors = Object.getOwnPropertyDescriptors(obj);
console.log(descriptors);
// {
// foo: { value: 123, writable: true, enumerable: true, configurable: true },
// bar: { get: [Function: get bar], set: undefined, enumerable: true, configurable: true }
// }
用途:与Object.defineProperties()方法配合,用于对象拷贝。
4. Object.setPrototypeOf() 和 Object.getPrototypeOf()
Object.setPrototypeOf():设置一个对象的原型。
用法:Object.setPrototypeOf(obj, proto)。
示例:
let proto = {};
let obj = { x: 10 };
Object.setPrototypeOf(obj, proto);
proto.y = 20;
console.log(obj.y); // 20
Object.getPrototypeOf():读取一个对象的原型。
用法:Object.getPrototypeOf(obj)。
5. Object.keys()、Object.values() 和 Object.entries()
- Object.keys():返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名。
- Object.values():返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。
- Object.entries():返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。
示例:
const obj = { foo: 'bar', baz: 42 };
console.log(Object.keys(obj)); // ["foo", "baz"]
console.log(Object.values(obj)); // ["bar", 42]
console.log(Object.entries(obj)); // [["foo", "bar"], ["baz", 42]]
6. Object.fromEntries()
目的:Object.fromEntries()方法是Object.entries()的逆操作,用于将一个键值对数组转为对象。
用法:Object.fromEntries(entries)。
示例:
console.log(Object.fromEntries([['foo', 'bar'], ['baz', 42]]));
// { foo: "bar", baz: 42 }
async和await
async和await是ES2016(ES7)中新增的两个关键字,它们旨在简化Promise API的使用,使异步代码看起来和表现起来更像同步代码。
一、async
定义:async是一个修饰符,用于修饰函数(无论是函数字面量还是函数表达式),放置在函数最开始的位置。被async修饰的函数的返回结果一定是Promise对象。
作用:
- 将不是Promise对象的返回值封装为resolved的Promise并返回。
- 如果没有返回值,则返回一个rejected的Promise。
- 使得对async函数的调用不会造成阻塞,其内部所有的阻塞都被封装在一个Promise对象中异步执行。
二、await
定义:await也是一个修饰符,但只能放在async函数内部。
作用:
- 等待一个Promise对象返回的结果。如果等待的不是Promise对象,则返回该值本身。
- 阻塞当前async函数的执行,直到等待的Promise对象被resolve或reject。注意,这里的“阻塞”并不会花费CPU资源,因为JavaScript引擎能够同时做其他工作,如执行其他脚本、处理事件等。
- 使得异步代码可以按照同步代码的方式书写和阅读,从而提高了代码的可读性和可维护性。
三、使用示例
function takeLongTime(n) {
return new Promise(resolve => {
setTimeout(() => resolve(n + 200), n);
});
}
async function work() {
console.time('work');
const time1 = await takeLongTime(300);
const time2 = await takeLongTime(time1);
const time3 = await takeLongTime(time2);
console.log(`你最终挣了${time3}`);
console.timeEnd('work');
}
work();
四、注意事项
- await只能用在async函数中。
- 如果await等待的是一个非Promise对象,它会直接返回该值,而不会造成阻塞。
- 使用async和await时,需要处理可能发生的异常。这可以通过在async函数中使用try...catch语句来实现。