Node.js中的Promise的作用与知识点讲解
在Node.js和现代JavaScript编程中,异步编程是一种常见的编程范式,它允许程序在等待某些操作完成时继续执行其他任务。Promise
是处理异步操作的一种非常强大的工具,它提供了一种更加清晰和可控的方式来处理异步操作的成功和失败结果。
一. Promise的作用
Promise
是 JavaScript 中用于异步编程的一种解决方案,它代表了一个异步操作的最终完成(或失败)及其结果值。Promise
的作用主要包括以下几点:
-
统一异步操作的接口:在
Promise
出现之前,JavaScript 的异步操作通常依赖于回调函数。Promise
提供了一个统一的异步操作接口,使得异步操作可以像同步操作一样通过顺序的代码来处理,这被称为“Promise 链”。 -
避免回调地狱:当多个异步操作有依赖关系时,使用回调函数会导致代码嵌套多层,形成所谓的“回调地狱”。
Promise
通过链式调用可以避免这种情况,使代码更加清晰。 -
状态一旦改变,不可再变:
Promise
有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。一旦Promise
的状态从 pending 变为 fulfilled 或 rejected,这个状态就不会再改变,这有助于简化异步逻辑。 -
支持成功和失败的处理:
Promise
提供了.then()
方法来处理异步操作成功的情况,以及.catch()
方法来处理失败的情况。这使得错误处理变得更加集中和一致。 -
支持finally操作:
Promise
提供了.finally()
方法,无论异步操作成功还是失败,都会执行.finally()
中的代码,这适用于清理资源等需要在异步操作结束后执行的代码。 -
可以构造复杂的异步逻辑:通过
Promise.all()
、Promise.race()
等方法,可以方便地构造多个异步操作的并行、竞态等复杂逻辑。 -
更好的错误处理:在回调中,如果一个错误发生,它可能会被忽略,因为回调函数没有 try/catch 语句。而
Promise
可以通过链式调用的.catch()
方法来捕获整个链中的错误。 -
与现代JavaScript特性集成:
Promise
与现代 JavaScript 的其他特性(如async
/await
)集成得很好,使得异步代码可以写得更像同步代码,提高了代码的可读性和可维护性。
总的来说,Promise
提供了一种更强大、更灵活、更易于管理的方式来处理 JavaScript 中的异步操作。
二. Promise的关键知识点
Promise
是 JavaScript 中处理异步操作的核心对象,它代表了一个异步操作的最终完成(或失败)及其结果值。以下是 Promise
的一些关键知识点:
1. Promise 的状态
一个 Promise
对象有三种状态:
- Pending(进行中):初始状态,既不是成功,也不是失败状态。
- Fulfilled(已成功):意味着操作成功完成。
- Rejected(已失败):意味着操作失败。
状态一旦改变,就不会再变,任何时候只能从 Pending 变为 Fulfilled 或 Rejected。
2. 创建 Promise
创建一个 Promise
,你需要使用 new Promise
构造函数,并提供一个执行器函数(executor function),它带有两个参数:resolve
和 reject
。
let myPromise = new Promise((resolve, reject) => {
// 异步操作
if (/* 成功条件 */) {
resolve(value); // 操作成功,调用 resolve
} else {
reject(reason); // 操作失败,调用 reject
}
});
3. 使用 Promise
一旦创建了 Promise
,你可以使用 .then()
和 .catch()
方法来添加处理成功的回调(成功时调用)和处理失败的回调(失败时调用)。
myPromise
.then(value => {
// 成功时执行的代码
})
.catch(error => {
// 失败时执行的代码
});
4. 链式调用
Promise
的 .then()
方法会返回一个新的 Promise
,这允许链式调用。
myPromise
.then(result => {
// 第一个异步操作的结果
return anotherAsyncOperation(result);
})
.then(newResult => {
// 第二个异步操作的结果
})
.catch(error => {
// 任何一个异步操作失败时执行的代码
});
5. Promise.all
当需要等待多个异步操作全部完成时,可以使用 Promise.all
。
Promise.all([promise1, promise2, ...])
.then(results => {
// 所有 Promise 都成功时执行的代码
})
.catch(error => {
// 任何一个 Promise 失败时执行的代码
});
6. Promise.race
Promise.race
接受一个 Promise
数组作为参数,并返回一个新的 Promise
,这个新的 Promise
会在数组中任何一个 Promise
完成(成功或失败)时立即完成。
Promise.race([promise1, promise2, ...])
.then(result => {
// 第一个完成的 Promise 的结果
})
.catch(error => {
// 第一个失败的 Promise 的错误
});
7. Promise.resolve 和 Promise.reject
Promise.resolve
和 Promise.reject
用于创建已经成功或失败的 Promise
。
let resolvedPromise = Promise.resolve(value); // 成功的 Promise
let rejectedPromise = Promise.reject(error); // 失败的 Promise
8. async/await
async
和 await
是基于 Promise
的语法糖,它们提供了一种更简洁的方式来写异步代码。
async function asyncFunction() {
try {
let result = await myPromise;
// 使用 result
} catch (error) {
// 处理错误
}
}
9. 错误处理
Promise
的错误处理非常重要。如果一个 Promise
链中没有 .catch()
方法,那么未捕获的错误可能会导致程序崩溃。
10. 微任务(Microtask)
Promise
的回调函数是在微任务队列中排队的,这意味着它们会在当前执行栈清空后,事件循环的下一阶段执行,而不是在宏任务(如 setTimeout 或 setInterval)之后。
掌握这些 Promise
的关键知识点,可以帮助你更有效地处理 JavaScript 中的异步编程问题。
三. 在项目中的应用
1. 方法1:Promise 原始用法
/*方法1:Promise 原始用法
前面如想取到多个sql结果,需要在每个回调函数中逐级嵌套查询
通过Promise可以用同步的方式写异步的代码,不用层层嵌套了
Promise 基础用法
1.创建Promise对象 p1
*/
const p1 = new Promise(function(resolve,reject){
1.1 放异步任务或代码
...
1.2返回结果
...
resolve(data) //异步任务完成的时候,调用resolve返回结果
reject(err) //异步任务失败的时候,调用resolve返回结果
})
/* 2.通过then...catch获取Promise对象中的结果
then中对应的是成功时候的结果,就是resolve返回的结果
catch中对应的是失败时候的结果,就是reject返回的结果
Promise 其它API 只Promise.all
Promise.all(obj) obj就promise对象数组,当所有的异步任务完成后,会吧结果依次放入到一个新数组中
可以的then的回调函数中取得结果
*/
Promise.all([p1,p2])
.then(repaire_data=>{
console.log(repaire_data)
arr.push(repaire_data[0],repaire_data[1]);
res.json({ code: 0, msg: "状态条数", data: arr });
})
.catch(err=>{
console.log(err)
})
2. 方法2:Promise 原始用法+优化
//方法2:Promise 原始用法+优化
const getTotalNum = (status)=>{
return new Promise((resolve,reject)=>{
return mysql.query(`SELECT count(id) AS total FROM reapply WHERE status = ${status}`, (error, data) => {
if (error) {
reject(error)
console.log(error.sql);
} else {
resolve(data[0]?.total)
// arr.push(totalNum_pass);
}
});
})
}
Promise.all([getTotalNum(0),getTotalNum(1)])
.then(repaire_data=>{
console.log(repaire_data)
arr.push(repaire_data[0],repaire_data[1]);
res.json({ code: 0, msg: "状态条数", data: arr });
})
.catch(err=>{
console.log(err)
})
3. 方法3:Promise 原始用法+优化+async await
await 是更好的异步解决方案,更简洁。不需要用then…catch,await等待的是Promise对象里面then的结果。
用到await的函数需要async function(){}来标记。
//方法3:Promise 原始用法+优化+async await
const getTotalNum = (status)=>{
return new Promise((resolve,reject)=>{
return mysql.query(`SELECT count(id) AS total FROM reapply WHERE status = ${status}`, (error, data) => {
if (error) {
reject(error)
console.log(error.sql);
} else {
resolve(data[0]?.total)
// arr.push(totalNum_pass);
}
});
})
}
// 错误处理,使用try...catch
try{
// 成功
let num01 = await getTotalNum(0)
let num02 = await getTotalNum(1)
let num03 = await getTotalNum(2)
let num04 = await getTotalNum(3)
let num05 = await getTotalNum(-1)
let num06 = await getTotalNum(-2)
res.json({ code: 0, msg: "状态条数", data: [num01,num02,num03,num04,num05,num06] });
}
catch{
// 失败
res.json({ code: -1, msg: "状态条数", data: [] });
}
四. 结论
Promise
是Node.js和现代JavaScript中处理异步操作的强大工具。它通过提供一种结构化的方式来处理异步操作的成功和失败结果,使得代码更加清晰、易于维护,并且可以有效地并行处理多个异步操作。掌握Promise
的使用,对于任何JavaScript开发者来说都是非常重要的。