
开始答题
版本一(失败)
/**
* @param {Promise} promise1
* @param {Promise} promise2
* @return {Promise}
*/
var addTwoPromises = async function(promise1, promise2) {
return now Promise((resolve,reject)=>{
promise1.then(const result1 = result)
promise2.then(const result2 = result)
resolve(result1+result2)
})
};
/**
* addTwoPromises(Promise.resolve(2), Promise.resolve(2))
* .then(console.log); // 4
*/
提交报错

询问ai报错原因
错误一
:是new Promise 不是now Promise
错误二
:promise1.then(const result1 = result)
语法错误,.then()
里面应该传函数,不能直接写赋值。
解决这个错误的时候,我发现函数,表达式,语句的区别我不太懂,附上一张图解释它们的区别

错误三
:result
没定义,你要的是 .then(res => {...})
。
会犯这个错误的原因是,我之前看是有这样的写法
promise const p1 = new Promise(resolve => setTimeout(() => resolve("A"), 1000));
p1.then(console.log);
//p1.then(console.log);等价于p1.then((res)=>console.log(res))
为什么想起上述的写法,我会写出 promise1.then(const result1 = result)这样的代码,我也不知道了,当初就是那样想的。
`错误四` :result1
和 result2
是异步拿到的,在执行 resolve
的时候可能还没取到result1,result2。
版本二(失败)
/**
* @param {Promise} promise1
* @param {Promise} promise2
* @return {Promise}
*/
var addTwoPromises = async function (promise1, promise2) {
return new Promise((resolve, reject) => {
let runCount = 2
promise1.then((res) => {
const result1 = res
if (--runCount == 0)
resolve(result1 + result2)
})
promise2.then((res) => {
const result2 = res
if (--runCount == 0)
resolve(result1 + result2)
})
})
};
/**
* addTwoPromises(Promise.resolve(2), Promise.resolve(2))
* .then(console.log); // 4
*/
报错

报错原因:const result1 = res
和 const result2 = res
都是 块级作用域变量 (const
定义的变量只在当前函数块里可见)。
我改的时候,把变量提升搞乱了,我尝试使用了var来声明变量,以为使用var声明的变量提升了,promise1.then里面就可以拿到result2的值了,结果是拿不到。
原因是:
var
变量提升,只在函数作用域 里有效。我的两个 .then
各自是一个独立函数作用域,互相看不到对方的变量。
版本三(成功)
/**
* @param {Promise} promise1
* @param {Promise} promise2
* @return {Promise}
*/
var addTwoPromises = async function (promise1, promise2) {
return new Promise((resolve, reject) => {
let runCount = 2,result1,result2
promise1.then((res) => {
result1 = res
if (--runCount == 0)
resolve(result1 + result2)
})
promise2.then((res) => {
result2 = res
if (--runCount == 0)
resolve(result1 + result2)
})
})
};
/**
* addTwoPromises(Promise.resolve(2), Promise.resolve(2))
* .then(console.log); // 4
*/
学习官方题解里面的知识点
什么是 Promise?
promise表示现在还没有完成,将来会完成的一个异步操作。
它有三种状态
1.挂起:初始状态,还没有完成
2.已完成 :异步操作成功了,得到了值,成功的操作通过resolve
返回值,在.then
中拿到通过resolve返回的值。
3.已拒绝 :异步操作失败了,发生了错误,错误的操作通过reject
返回值,在.catch
中拿到reject返回的错误。
什么是async/await
async/await是promise的语法糖,通过这个语法糖可以像处理同步操作那样处理异步函数。
async
- 放在函数前面,表示这个函数一定会返回一个promise。
- 即使函数返回的是一个普通的值,加了async也会变成promise。
await
- 只能在async函数里面使用
- await会暂停当前函数,等待promise函数执行结束,才会继续执行函数
- 如果 Promise 成功,返回结果继续往下执行;如果失败,就抛出异常。
Promise.all() 是干嘛的?
有时候你需要 并行执行多个异步任务 ,并在它们全部完成后再继续。
这时就可以用 Promise.all()
。
- 传进去一个数组(里面可以是 Promise,也可以是普通值)。
- 它会返回一个新的 Promise:
-
- 如果所有任务都成功,返回的 Promise 也成功,结果是一个「数组」,包含每个 Promise 的结果,顺序和输入一致。
- 如果有一个任务失败,返回的 Promise 就直接失败,失败原因就是那个 Promise 抛出的错误。
举例
✅ 所有任务都成功
Promise.all([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)])
.then(values => console.log(values));
// 输出: [1, 2, 3]
❌ 有任务失败
Promise.all([Promise.resolve(1), Promise.reject("error"), Promise.resolve(3)])
.then(values => console.log(values))
.catch(err => console.log(err));
// 输出: "error" 这里只会输出一个error 是在catch里输出的,如果失败了就不走then了
实际应用场景
假设你要同时请求三个 API:
const user = fetch('/api/user');
const posts = fetch('/api/posts');
const comments = fetch('/api/comments');
Promise.all([user, posts, comments])
.then(([userRes, postsRes, commentsRes]) => {
// 三个请求都完成后,才会到这里
console.log("全部完成:", userRes, postsRes, commentsRes);
})
.catch(err => console.error("有一个请求失败:", err));
开始学习官方的解法
解法一:使用promise.all
/**
* @param {Promise} promise1
* @param {Promise} promise2
* @return {Promise}
*/
var addTwoPromises = async function(promise1, promise2) {
try {
const [res1, res2] = await Promise.all([promise1, promise2]);
return res1 + res2;
} catch (error) {
console.error(error);
throw error; // 重新抛出错误以保持将错误传播给调用者的行为
}
};
作者:力扣官方题解
链接:https://leetcode.cn/problems/add-two-promises/solutions/2506145/shi-yong-promise-chu-li-yi-bu-cao-zuo-by-m5ob/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
解法二:不使用promise.all
/**
* @param {Promise} promise1
* @param {Promise} promise2
* @return {Promise}
*/
var addTwoPromises = async function(promise1, promise2) {
try {
return await promise1 + await promise2;
} catch (error) {
console.error(error);
throw error; // 重新抛出错误以保持将错误传播给调用者的行为
}
};
作者:力扣官方题解
链接:https://leetcode.cn/problems/add-two-promises/solutions/2506145/shi-yong-promise-chu-li-yi-bu-cao-zuo-by-m5ob/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
解法三:Promise.then 链式调用
/**
* @param {Promise} promise1
* @param {Promise} promise2
* @return {Promise}
*/
var addTwoPromises = async function(promise1, promise2) {
try{
return promise1.then(
(val1)=>promise2.then((val2)=>val1+val2)
)
} catch(error){
throw error
}
};
/**
* addTwoPromises(Promise.resolve(2), Promise.resolve(2))
* .then(console.log); // 4
*/
这里要注意 不能写成promise2.then((val2)=>{val1+val2})
因为
- 箭头函数 没花括号 = 自动返回表达式。
- 箭头函数 有花括号 = 需要手写
return
。
解法四:使用计数器
/**
* @param {Promise} promise1
* @param {Promise} promise2
* @return {Promise}
*/
var addTwoPromises = async function (promise1, promise2) {
return new Promise((resolve, reject) => {
let count = 2;
let res = 0;
[promise1, promise2].forEach(async promise => {
try {
const subRes = await promise;
res += subRes;
count--;
if (count === 0) {
resolve(res);
}
} catch (err) {
reject(err);
}
});
});
};
涉及到的面试题
1. 说一下promise.all
答案见上述
2. 如何处理promise的错误
通过try catch finally
3. 同步,异步的区别
同步是指一个程序执行完后,另一个程序再执行。异步是指多个程序可以同时执行。
4. 回调函数和promise有什么区别,为什么更喜欢用promise,回调地狱是什么,如何解决回调地狱。
回调函数是将一个函数作为参数传递给另一个函数,当异步操作完成是调用这个作为参数的函数
示例:
function getData(callback) {
setTimeout(() => {
callback("数据加载完成");
}, 1000);
}
getData((result) => {
console.log(result); // 1 秒后输出 "数据加载完成"
});
👉 缺点:
- 回调函数之间会不断嵌套,逻辑复杂时非常难读。
- 错误处理不统一,每层都要自己处理
error
。
Promise 是一个对象,表示 异步操作的最终结果 (成功或失败)。
它提供 .then()
和 .catch()
来处理结果,更清晰地链式调用。
示例:
function getData() {
return new Promise((resolve) => {
setTimeout(() => {
resolve("数据加载完成");
}, 1000);
});
}
getData().then((result) => {
console.log(result); // 1 秒后输出 "数据加载完成"
});
👉 优点:
- 可以链式调用:
p.then(...).then(...).catch(...)
- 错误捕获统一用
.catch
,比回调函数更干净。
回调地狱是指代码结构变得嵌套层次很深,每个回调都作为另一个回调的参数传递。这种嵌套会很快变得复杂,使代码难以理解,导致问题,如代码重复、错误处理问题以及难以维护和调试的困难。
为了缓解回调地狱,可以使用几种方法,例如使用命名函数、使用控制流库(如 async.js 或 Promises)或使用现代 JavaScript 特性如 async/await。这些方法有助于扁平化代码结构,使其更可读和可维护,避免过多的回调嵌套。