前端笔记:Promise对象及链式传递
回调地狱
针对以下代码中的回调函数层层嵌套的关系,形成了回调地狱
function confession(name, onfulfilled, onrejected) {
console.log('已发送邀请,请等待回复...');
setTimeout(() => {
if (0.3 >= Math.random()) {
onfulfilled(`恭喜${name},你被接受了~`);
} else {
onrejected(`抱歉${name},你被拒绝了...`);
}
}, 1000);
}
confession('王哥', (reply) => {
console.log('成功', reply);
}, (reply) => {
console.log('失败', reply);
confession('孙哥', (reply) => {
console.log('成功', reply);
}, (reply) => {
console.log('失败', reply);
confession('张哥', (reply) => {
console.log('成功', reply);
}, (reply) => {
console.log('失败', reply);
confession('赵哥', (reply) => {
console.log('成功', reply);
}, (reply) => {
console.log('失败', reply);
})
})
})
})
若要解决这个问题就需要 Promise规范
Promise规范
Pomise是一个专门处理异步场景的规范,用来避免回调地狱的产生,使异步代码更加的简洁高效。
每一个promise对象都有两个阶段和三个状态。
两个阶段:未决阶段 unsettled、已决阶段 settled
- 第一阶段 (Unsettled):
pending - 第二阶段 (Settled):
fulfilled或rejected
三个状态:挂起状态 pending、完成状态 fulfilled、失败状态 rejected
pending:初始状态,既不是成功,也不是失败。对应“进行中”阶段。fulfilled:操作成功完成。当resolve函数被调用时,Promise 的状态会从pending变为fulfilled。对应“已确定”阶段中的成功情况。rejected:操作失败。当reject函数被调用或执行器函数内部抛出异常时,Promise 的状态会从pending变为rejected。对应“已确定”阶段中的失败情况。
Promise 核心特性——状态的不可逆性
为了让这段描述在技术层面更加严谨,同时在逻辑上更易懂,我们可以将其整合优化为以下两条核心准则:
1. 状态流转的单向性(时间不能倒流)
Promise 实例在生命周期内,状态只能发生一次单向流转。它总是从初始的等待态(pending)出发,最终变为成功态(fulfilled)或失败态(rejected)。这个过程是绝对单向的,不存在任何“逆行”或“回退”的可能。
2. 结果的不可篡改性(历史不可改写)
一旦 Promise 的状态从pending变为 fulfilled或 rejected,它的状态就会被永久锁定(固化)。无论后续代码如何尝试再次调用resolve或reject,都无法改变已经确定的结果。
Promise链式调用
catch方法
.catch(onRejected) 等价于 .then(null, onRejected)
新 Promise 的状态由什么决定?
规则一:什么都不做 → 原样传递
如果 .then() 里面什么都不写或者没有对应的处理函数:
- 如果上游是成功 → 新 Promise 也是成功,数据和上游一样
- 如果上游是失败 → 新 Promise 也是失败,错误和上游一样
// 上游成功时
Promise.resolve("原始数据").then().then(data => {
console.log(data); // "原始数据" - 数据原样传递
});
// 上游失败时
Promise.reject("错误信息").then().catch(error => {
console.log(error); // "错误信息" - 错误原样传递
});
规则二:正常处理 → 用返回值更新
如果 .then() 里的回调函数正常执行完毕(没有抛出错误):
- 有返回值 → 新 Promise 成功,数据是这个返回值
- 没有返回值 (
undefined) → 新 Promise 成功,数据是undefined
Promise.resolve("Hello")
.then(data => data + " World") // 返回 "Hello World"
.then(result => {
console.log(result); // "Hello World"
return "Next Value"; // 返回新值
})
.then(final => {
console.log(final); // "Next Value"
});
规则三:处理出错 → 转为失败
如果 .then() 里的回调函数执行过程中抛出了错误:
- 新 Promise 变为失败状态,错误信息就是抛出的内容
Promise.resolve("OK")
.then(data => {
throw new Error("出错了!"); // 抛出错误
})
.catch(error => {
console.log(error.message); // "出错了!"
});
规则四:返回 Promise → 等待其结果
如果 .then() 里的回调函数返回另一个 Promise 对象:
- 新 Promise 会等待这个返回的 Promise 完成,然后采用它的最终状态和数据
Promise.resolve("Start")
.then(data => {
// 返回一个异步操作
return fetch("/api/data"); // 这是一个 Promise
})
.then(response => {
// 这里的 response 是上面 fetch 成功后的结果
return response.json();
})
.catch(error => {
// 这里可能捕获上面任何一个步骤的错误
});
代码示例:
new Promise((resolve, reject) => {
throw new Error(1); //抛出错误,为rejected状态
})
.then((res) => {
console.log(res);
return new Error('2'); //未对rejected进行处理,仍然为rejected Error(1)
})
.catch((err) => {
throw err;
return 3; //对rejected进行处理,处理中又抛出错误,状态为rejected Error(1)
})
.then((res) => {
console.log(res);
}); //未对rejected进行处理,仍然为rejected Error(1)
async和await关键字
async关键字用于修饰函数,被它修饰的函数,返回的值为Promise
async function foo() {
// 没有 await,没有 return,没有 throw
}
const p = foo();
console.log(p); // Promise { <fulfilled>: undefined }
async function method(){
throw new Error(1); // 若执行过程报错,则任务是rejected
}
method(); // Promise { <rejected> Error(1) }
async函数会自动返回一个 Promise,且正常执行完毕时自动变为 fulfilled,值为undefined,不需要手动调用resolve。
async函数需要手动进行调用执行,不像 new Promise((resolve, reject) = > {}) 可以直接执行。
await关键字表示等待某个Promise完成,它必须用于async函数中
1. await 必须用于 async 函数中
// ❌ 错误:在非 async 函数中使用 await
function normalFunction() {
const result = await Promise.resolve(1); // SyntaxError: await is only valid in async functions
}
// ✅ 正确:在 async 函数中使用 await
async function asyncFunction() {
const result = await Promise.resolve(1);
console.log(result); // 输出: 1
}
asyncFunction();
2. await 也可以等待其他数据(非 Promise 值)
async function handleVariousValues() {
// 等待数字
const num = await 42;
console.log('数字:', num); // 输出: 数字: 42
// 等待字符串
const str = await "hello";
console.log('字符串:', str); // 输出: 字符串: hello
// 等待对象
const obj = await { name: "Alice" };
console.log('对象:', obj); // 输出: 对象: { name: 'Alice' }
// 等待 undefined
const undef = await undefined;
console.log('undefined:', undef); // 输出: undefined: undefined
}
handleVariousValues();
3. 使用 try-catch 处理失败任务
async function fetchData() {
try {
// 成功场景
const successData = await Promise.resolve("成功数据");
console.log('成功:', successData); // 输出: 成功: 成功数据
// 失败场景 - 故意抛出错误
await Promise.reject(new Error("网络请求失败"));
} catch (error) {
// 捕获并处理错误
console.error('捕获错误:', error.message); // 输出: 捕获错误: 网络请求失败
return "默认数据"; // 可以返回默认值
} finally {
console.log('清理工作完成');
}
}
fetchData().then(result => {
console.log('最终结果:', result); // 输出: 最终结果: 默认数据
});
await在执行上下文的时候,先执行await对应的Promise函数,若Promise返回值为fulfilled或是rejected,那么await会先进入微序列,若返回值为pending则先不进入微序列。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)