目录
一.Promise的原理
1.1promise原理:
Promise是JavaScript中一种异步编程的解决方案,用于解决回调地狱和代码可读性差的问题。它是一个包装了异步操作的对象,可以让我们更优雅、清晰地处理异步操作。
1.2Promise的优点
优化了异步操作的流程控制,避免了回调地狱和嵌套的回调函数。
可以更好地处理异步操作的状态和结果,使代码更加清晰、简洁。
可以使用Promise.all()方法和Promise.race()方法来处理多个异步操作的结果,进一步简化异步编程的过程。
1.3Promise的缺点
对于初学者来说,可能需要一些时间来理解Promise的概念和使用方法。
需要在异步操作完成后手动调用resolve()或reject()方法,可能会出现遗漏或错误。
无法取消Promise,一旦创建就必须等待其状态发生变化。
在使用.then()方法链式调用多个Promise对象时,如果其中任意一个Promise对象发生错误,整个链式调用都会停止,需要使用.catch()方法来捕获错误。
二.Promise的状态
Promise对象有三种状态,分别为pending、resolved和rejected。Promise对象的状态只能从pending转变为resolved或rejected,一旦状态变化,就不会再改变。
2.1 pending
初始化状态,即Promise实例创建后的初始状态,既不是成功也不是失败状态。
2.2 fulfilled
操作成功的状态,这意味着Promise的一个操作已经成功完成。Promise对象的结果会传递给.then()方法注册的回调函数。
"resolved"可能是对"fulfilled"状态的一个普遍误解,因为一个"resolved"的Promise可能是"fulfilled"或者"rejected"。
2.3 rejected
意味着异步操作失败,Promise对象的错误会传递给.catch()方法注册的回调函数
三.async/await
3.1 概念
async/await是一种在JavaScript中处理异步操作的语法糖,它使得异步操作的代码看起来像是同步的代码,使得异步操作更加容易理解和对调试,同时也能够避免回调地狱。
3.2 原理
async/await是基于Promise实现的,async函数返回一个Promise对象,await可以等待一Promise对象的执行结果,如果该Promise对象是resolved状态,则返回其resolve的结果;如果该Promise对象是rejected状态,则抛出其reject的原因。
3.3 作用
async/await可以用于处理异步操作,提供了一种更加优雅的方式来处理异步代码。
3.4 用法
sync函数需要使用async关键字来声明,它可以包含多个await语句,await语句必须在async函数中使用,用来等待Promise对象的执行结果。使用async/await的代码看起来像是同步代码,但实际上是异步执行的
3.5 应用场景
async/await可以用于处理所有需要异步执行的场景,如网络请求、文件读写等操作。它特别适用于需要按照顺序执行多个异步操作的场景,可以避免回调地狱,提高代码的可读性和可维护性。
下面是一个使用async/await处理异步请求的示例
async function fetchData() {
const response1 = await fetch('http://api.example.com/data1');
const data1 = await response1.json();
const response2 = await fetch('http://api.example.com/data2');
const data2 = await response2.json();
return { data1, data2 };
}
fetchData()
.then(result => console.log(result))
.catch(error => console.error(error));
上面的代码使用async/await处理了两个异步请求,等待每个请求的结果后再执行下一个请求,最终返回两个请求的结果。代码看起来像是同步执行的,但实际上是异步执行的。
在这个例子中,我们定义了一个async函数fetchData,它通过fetch函数异步获取数据,并使用await关键字等待数据获取完成。当数据获取完成后,我们再使用await关键字将response转换为json格式的数据,并打印出来。如果在获取数据的过程中出现了错误,我们使用.catch语句捕获错误并打印出来。
使用async/await可以让我们避免回调地狱和Promise链式调用的复杂性,使代码更加简洁易懂。
四.异步编程与Promise的关系
4.1 相同点
setTimeout和Promise都是JavaScript中用于管理异步代码的工具。
4.2 区别
setTimeout和Promise都是用于实现异步操作的机制,它们之间的区别在于
①setTimeout是一种基于回调函数的机制,它通过设置一个定时器,在一定时间后触发回调函数来实现异步操作。而Promise是一种基于状态的机制,它通过返回一个Promise对象,来表示异步操作的完成状态。
②setTimeout只能实现一次性的异步操作,且不具备错误处理机制,而Promise可以实现多次异步操作的串联和并行可以链式地处理多个异步操作,让代码变得更为清晰易读。另外还可以通过Promise的链式调用和async/await语法,可以更方便地管理异步操作的顺序和结果。
③Promise具有更多的功能和优势。比如Promise可以处理异步操作的异常情况,而setTimeout需要在回调函数中手动处理异常。Promise还可以通过.catch()方法捕获异常,并返回一个新的Promise对象来表示异常的处理结果。此外,Promise还可以实现异步操作的取消、超时控制等功能。
综上所述,虽然setTimeout和Promise都可以实现异步操作,但是Promise具有更强大的功能和更好的可维护性,因此在实际开发中,推荐使用Promise来管理异步操作。
五.Promise的创建
5.1创建Promise对象
在ES6中,可以使用Promise构造函数来创建一个Promise对象,构造函数接收一个参数——一个函数,这个函数有两个参数resolve和reject,分别表示异步操作成功和失败的回调函数。resolve函数会将Promise对象的状态从pending变成resolved,而reject函数则会将状态从pending变成rejected。
const promise = new Promise((resolve, reject) => {
// 异步操作
if (/* 异步操作成功 */) {
resolve(result); // 改变Promise对象状态为resolved
} else {
reject(error); // 改变Promise对象状态为rejected
}
});
5.2Promise链式调用
Promise对象的.then()方法可以为Promise对象注册成功的回调函数,.catch()方法可以为Promise对象注册失败的回调函数,可以链式调用多个.then()方法,也可以在链的最后使用.catch()方法处理错误。
promise.then((result) => {
// 处理异步操作成功的结果
return new Promise((resolve, reject) => {
// 进行更加复杂的异步操作
if (/* 操作成功 */) {
resolve(newResult);
} else {
reject(newError);
}
});
})
.then((newResult) => {
// 处理新的异步操作成功的结果
})
.catch((error) => {
// 处理错误
});
六.Promis使用方法
在 JavaScript 中,Promise 是一种用于异步编程的机制,它代表一个尚未完成但最终会完成的操作。在 Promise 中,有两个重要的概念:原型对象和构造函数。原型对象是指所有 Promise 实例共享的对象,其中定义了 then()、catch() 等方法,而构造函数则用于创建 Promise 对象的函数。
6.1.Promise原型对象的方法
Promise原型对象的方法有:then()、catch()、finally()。
6.1.1 .then()
.then() 方法注册一个回调函数,用于处理 Promise 成功状态的结果。它接受两个可选参数:成功回调函数和失败回调函数。如果一个回调函数没有被提供,它会被忽略。
例如:
const promise = new Promise((resolve, reject) => {
resolve(42);
});
promise.then((result) => {
console.log(result); // 输出 42
});
6.1.2 .catch()
.catch() 方法注册一个回调函数,用于处理 Promise 失败状态的结果。它接受一个参数:失败回调函数。
const promise = new Promise((resolve, reject) => {
reject(new Error('Something went wrong'));
});
promise.catch((error) => {
console.error(error.message); // 输出 "Something went wrong"
});
6.1.3 .finally()
.finally() 方法注册一个回调函数,无论 Promise 成功或失败都会执行该回调函数。它不接受任何参数。
例如:
const promise = new Promise((resolve, reject) => {
resolve(42);
});
promise
.then((result) => {
console.log(result); // 输出 42
})
.finally(() => {
console.log('Promise completed'); // 输出 "Promise completed"
});
6.2Promise构造函数的方法
Promise构造函数的方法有:resolve()、reject()、all()、race()。
6.2.1 Promise.resolve()
Promise.resolve() 方法返回一个以给定值解析后的 Promise 对象。如果参数本身就是一个Promise 对象,那么 Promise.resolve() 方法会直接返回该对象,不会创建新的 Promise 对象。
语法:Promise.resolve(value)
参数:
value: 任何值
返回值:一个 Promise 对象
示例:
const myPromise = Promise.resolve('hello');
myPromise.then((value) => {
console.log(value); // 输出 "hello"
});
const myOtherPromise = Promise.resolve(myPromise);
console.log(myPromise === myOtherPromise); // 输出 true
在上面的示例中,第一个 Promise.resolve() 方法返回一个解析为字符串 "hello" 的 Promise 对象。在 then() 方法中,可以打印该字符串。
第二个 Promise.resolve() 方法接收一个 Promise 对象作为参数。由于该参数已经是 Promise 对象,所以 Promise.resolve() 方法直接返回该对象,而不是创建一个新的 Promise 对象。因此,myPromise 和 myOtherPromise 变量引用的是同一个 Promise 对象,因此它们的值相等。
6.2.2 Promise.reject()
Promise.reject() 方法返回一个带有拒绝原因的 Promise 对象。
语法:Promise.reject(reason)
参数:
reason: 一个拒绝原因,通常是一个 Error 对象,但也可以是任何其他值
返回值:一个 Promise 对象,状态为拒绝状态,并且拒绝原因为给定的 reason 参数。
示例:
const myPromise = Promise.reject(new Error('Something went wrong!'));
myPromise.catch((error) => {
console.log(error.message); // 输出 "Something went wrong!"
});
在上面的示例中,Promise.reject() 方法返回一个带有拒绝原因的 Promise 对象,并且在 catch() 方法中可以捕获拒绝原因并打印出错误信息。
6.2.3 Promise.all()
Promise.all() 方法接收一个由 Promise 对象组成的数组作为参数,并返回一个新的 Promise 对象。当所有的 Promise 对象都变为解决状态时,该 Promise 对象的状态也变为解决状态,返回一个解决值数组,其中包含所有 Promise 对象的解决值。如果任何一个 Promise 对象变为拒绝状态,该 Promise 对象的状态也变为拒绝状态,并返回第一个被拒绝的 Promise 对象的拒绝原因。
语法:Promise.all(iterable)
参数:
iterable: 一个可迭代对象,其中每个成员都是 Promise 对象。
返回值:一个 Promise 对象
示例:
const promise1= Promise.resolve('hello');
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'world');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values); // 输出 ["hello", 42, "world"]
});
在上面的示例中,Promise.all() 方法接收一个包含三个 Promise 对象的数组作为参数。promise1 是一个解析为字符串 "hello" 的 Promise 对象,promise2 是一个直接解析为数字 42 的对象,promise3 是一个在 100 毫秒后解析为字符串 "world" 的 Promise 对象。在 then() 方法中,打印出所有 Promise 对象的解析值数组。由于所有的 Promise 对象都已经解析,因此打印出 ["hello", 42, "world"]。
6.2.4 Promise.race()
Promise.race() 方法接收一个由 Promise 对象组成的数组作为参数,并返回一个新的 Promise 对象。当参数数组中的任意一个 Promise 对象变为解决状态或拒绝状态时,该 Promise 对象的状态也会相应地变为解决状态或拒绝状态,并返回解决值或拒绝原因。
语法:Promise.race(iterable)
参数:
iterable: 一个可迭代对象,其中每个成员都是 Promise 对象。
返回值:一个 Promise 对象
示例:
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'two');
});
Promise.race([promise1, promise2]).then((value) => {
console.log(value); // 输出 "two"
});
在上面的示例中,Promise.race() 方法接收一个包含两个 Promise 对象的数组作为参数。其中,promise1 在 500 毫秒后解析为字符串 "one",而 promise2 在 100 毫秒后解析为字符串 "two"。由于 promise2 先解析,因此 Promise.race() 方法返回解析为 "two" 的 Promise 对象,并在 then() 方法中打印该字符串。
七.Promise在实际场景中的应用
Promise是一种异步编程解决方案,可以有效地处理异步操作,避免回调地狱,提高代码可读性和可维护性。在实际应用场景中,Promise常用于网络请求、文件读写、定时任务等异步操作。
Promise的原理是基于状态机的概念,包含三种状态:Pending(等待态)、Fulfilled(成功态)和Rejected(失败态)。在Promise对象实例化时,会处于Pending状态,当异步操作完成时,Promise对象的状态会变为Fulfilled或Rejected状态,并返回相应的结果。
以下是一个简单的Promise示例,模拟一个异步获取用户信息的过程:
// Promise示例
function getUserInfo(userId) {
return new Promise((resolve, reject) => {
// 模拟异步请求
setTimeout(() => {
const users = [
{ id: 1, name: 'Alice', age: 23 },
{ id: 2, name: 'Bob', age: 28 },
{ id: 3, name: 'Charlie', age: 31 }
];
const user = users.find(user => user.id === userId);
if (user) {
// 请求成功,将结果通过resolve返回
resolve(user);
} else {
// 请求失败,将错误信息通过reject返回
reject(new Error('User not found'));
}
}, 1000);
});
}
// 使用Promise获取用户信息
getUserInfo(2)
.then(user => {
console.log(user); // { id: 2, name: 'Bob', age: 28 }
})
.catch(error => {
console.error(error); // Error: User not found
});
上述代码演示了如何使用Promise获取用户信息的过程。在函数getUserInfo内部,首先创建一个新的Promise对象,并在Promise构造函数中定义异步操作的逻辑。这里通过setTimeout模拟异步请求,然后在回调函数中处理异步操作的结果,并根据结果调用resolve或reject方法,将异步操作的结果返回。
在使用Promise获取用户信息时,可以通过调用getUserInfo函数,并使用then方法处理异步操作成功时的结果,或者使用catch方法处理异步操作失败时的错误信息。在这个例子中,使用then方法打印出了获取到的用户信息,使用catch方法捕获了未找到用户时的错误信息。
除了网络请求和文件读写等异步操作外,Promise在定时任务、多个异步操作的协同等场景中也有广泛的应用。通过合理地使用Promise,可以避免回调地狱,提高代码的可读性和可维护性。