当前位置: 首页 > news >正文

力扣 30 天 JavaScript 挑战 第41天 (第十二题)对异步操作,promise,async/await有了更深理解

开始答题

版本一(失败)

/*** @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)这样的代码,我也不知道了,当初就是那样想的。

`错误四` :result1result2 是异步拿到的,在执行 resolve 的时候可能还没取到result1,result2。

版本二(失败)

/*** @param {Promise} promise1* @param {Promise} promise2* @return {Promise}*/
var addTwoPromises = async function (promise1, promise2) {return new Promise((resolve, reject) => {let runCount = 2promise1.then((res) => {const result1 = resif (--runCount == 0)resolve(result1 + result2)})promise2.then((res) => {const result2 = resif (--runCount == 0)resolve(result1 + result2)})})};/*** addTwoPromises(Promise.resolve(2), Promise.resolve(2))*   .then(console.log); // 4*/

报错

报错原因:const result1 = resconst 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,result2promise1.then((res) => {result1 = resif (--runCount == 0)resolve(result1 + result2)})promise2.then((res) => {result2 = resif (--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。这些方法有助于扁平化代码结构,使其更可读和可维护,避免过多的回调嵌套。

http://www.dtcms.com/a/354098.html

相关文章:

  • 【Linux实时内核机制】ww_rt_mutex 的contending_lock异常问题
  • android/java中主线程和子线程的详解
  • Nano Banana揭秘:Google Gemini 2.5 Flash Image正式发布 | AI图像编辑新时代
  • 内网应用如何实现外网访问?外地通过公网地址访问内网服务器的设置方法
  • 动态规划:青蛙跳台阶实践
  • H20 性能表现之 Kimi-K2
  • 【git】:gitee项目管理vs2019
  • 装饰器进阶与设计模式
  • Linux入门教程 第十五章 Linux 系统调优工具
  • 【工具篇】github/huggingface 镜像源总结
  • 嵌入式系统学习Day24(线程)
  • Custom SRP - Shadow Masks
  • Axure:如何将SVG转换为形状
  • leetcode 155 官方golang标准答案错误
  • Java Lambda 处理日期时间 根据区间找出区间内集合
  • Linux程序与进程:核心概念与管理全解析
  • Class45循环神经网络RNN
  • “互联网 +”时代下开源 AI 大模型 AI 智能名片 S2B2C 商城小程序:行业变革与未来展望
  • 基于 Ultralytics YOLO11与 TrackZone 的驱动的高效区域目标跟踪方案实践
  • Python Imaging Library (PIL) 全面指南:PIL基础入门-Python图像处理实战
  • 多版本兼容的golang客服系统
  • 稀土:从“稀有”到“命脉”的科技核心
  • 通过概率正 - 未标记网络从医学图像的特定感兴趣区域中学习|文献速递-深度学习人工智能医疗图像
  • 【底层机制】thread_local 变量的初始化时机和生命周期
  • Spring Retry Spring 生态系统优雅的重试组件
  • 浏览器网页路径扫描器(脚本)
  • SQL优化:SQL模拟Split二维数组
  • Linux 基础开发工具
  • django-redis 使用类实现和使用
  • React(面试)