写给 Java 程序员的前端 Promise 教程

简介: 写给 Java 程序员的前端 Promise 教程

小伙伴们知道,松哥最近在录 TienChin 项目,用的 RuoYi-Vue 脚手架,前端关于网络请求的地方,很多都涉及到了 Promise,为了让小伙伴们能更好的理解前端代码,咱们抽空整一篇文章和大家聊聊整个 Promise。

1. 为什么需要 Promise

假设我现在有这样一个需求,用户先去登录,登录成功之后,再去服务端获取用户信息,获取到用户信息之后再去服务端获取前端的动态菜单。一般我们的 Ajax 请求都是异步形式,为了确保上一步操作成功再执行下一个请求,所以最终发出的请求伪代码类似下面这样:

$.ajax({
    url:'/login',
    data:loginForm,
    success: function (data) {
        //登录成功
        $.ajax({
            url:'/getInfo',
            success: function (userInfo) {
                //获取用户信息成功
                $.ajax({
                    url: '/getMenus',
                    success: function (menus) {
                        //获取菜单成功
                    }
                })
            }
        })
    }
})

为了确保一个异步任务执行完成后,再执行下一个异步任务,我们不得不在回调函数中不停的写下去,上面我举的例子是三个请求嵌套,实际上可能会更多。。。这就是前端所谓的回调地狱。而 Promise 就是来解决回调地狱的。

2. Promise

Promise 从字面上理解,就是承诺,承诺将来在某一个时间会做某一件事。通过 Promise 我们可以将异步任务执行的代码和处理的代码完全分离开。

还是第一小节这个例子,如果我们用 Promise 写,那么方式如下:

function login(resolve, reject) {
    setTimeout(() => {
        let number = Math.random();
        if (number > 0.5) {
            resolve("login success")
        } else {
            reject("login failed")
        }
    }, 2000);
}
function getInfo(resolve, reject) {
    setTimeout(() => {
        let number = Math.random();
        if (number > 0.5) {
            resolve("getInfo success")
        } else {
            reject("getInfo failed")
        }
    }, 2000);
}
function getMenus(resolve, reject) {
    setTimeout(() => {
        let number = Math.random();
        if (number > 0.5) {
            resolve("getMenus success")
        } else {
            reject("getMenus failed")
        }
    }, 2000);
}
new Promise(login).then(data => {
    console.log("login:", data);
    return new Promise(getInfo);
}).then(data => {
    console.log("getInfo:", data);
    return new Promise(getMenus);
}).then(data => {
    console.log("getMenus", data);
}).catch(err => {
    console.log("err:", err);
})

我们在 Promise 中写异步任务执行的代码,在上面的案例中,松哥通过 setTImeout 方法模拟了一个耗时操作,异步任务执行完毕后,我们调用 resolve 方法返回调用的结果(会进入到下一步的 then 中),也可以调用 reject 方法表示调用失败(会进入到 catch 中)。

3. then

then 中的返回值可以分为三种情况。

3.1 正常 return

then 中方法的参数,是上一个 Promise 对象 resolve 的值,一个 Promise 对象可以有多个 then,例如上面案例的登录功能,我们可以一直 then 下去:

function login(resolve, reject) {
    setTimeout(() => {
        let number = Math.random();
        if (number > 0.5) {
            resolve("login success")
        } else {
            reject("login failed")
        }
    }, 2000);
}
new Promise(login).then(data => {
    console.log("then1:", data);
    return data;
}).then(data => {
    console.log("then2:", data);
    return data;
}).then(data => {
    console.log("then3:", data);
}).catch(err => {
    console.log("err:", err);
})

这样可以一直返回,这有点像我们 Java 中的流式编程。

3.2 抛出异常

在 then 中,我们可以对返回结果进行判断,不满足条件也可以直接抛出异常,这样就会进入到最近的 catch 代码块中。如下案例:

function login(resolve, reject) {
    setTimeout(() => {
        let number = Math.random();
        if (number > 0.5) {
            resolve("login success")
        } else {
            reject("login failed")
        }
    }, 2000);
}
new Promise(login).then(data => {
    console.log("then1:", data);
    throw new Error("出错啦");
}).then(data => {
    console.log("then2:", data);
    return data;
}).then(data => {
    console.log("then3:", data);
}).catch(err => {
    console.log("err:", err);
})

像上面这段代码,如果进入到第一个 then 中,第一个 then 直接抛出异常,这样直接就进入到 catch 中了,后面的 then 就都不会执行了。

3.3 返回 Promise

第三种情况就是 then 中也可以返回一个 Promise 对象,这个就如同我们第二小节的案例,我这里就不再赘述了。

就说一句,如果 then 中返回的是一个 Promise 对象,那么接下来的 then 其实是这个 Promise 对象的 then,而不是一开始的 Promise 的 then 了。例如如下伪代码:

A.then((data)=>{return B}).then(xxx)

假设 A 和 B 都是 Promise 对象,那么第二个 then 方法是 B 的 then。

好啦,这就是 then 中的三种返回值情况。

4. catch

catch 主要是用来处理异常的情况,两种情况下会进入到 catch 中:

  • Promise 执行的时候通过 reject 返回数据。
  • then 中抛出 Error

出了问题,就由最近的 catch 来处理。

5. finally

最后还有一个 finally 用来兜底,这一套下来感觉有点像我们 Java 中的 try-catch-finally,也就是前面无论如何,最终 finally 中的代码都会执行。不过不同于 Java 中的 finally,Promise 中的 finally 在最终执行完毕后,还可以继续 then。。。前端的蜜汁操作。

6. 其他方法

最后,我们再来看看 Promise 中的其他静态方法。

6.1 Promise.all()

Promise.all() 方法可以接收多个 Promise 对象,并且只返回一个 Promise 实例,这个方法会等所有输入的 Promise 对象的 resolve 方法都返回的时候,或者所有输入的 Promise 对象中有一个 reject 的时候,这个 all 就会执行结束,来看如下一个案例:

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
    setTimeout(resolve, 3000, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
    console.log(values);
}).catch(err=>{
    console.log("err", err);
})

当 promise1、promise2 以及 promise3 都执行了 resolve 的时候,就会进入到 then 中,这三个中有任意一个执行了 reject 就会进入到 catch 中。

6.2 Promise.race()

Promise.race() 方法可以接收多个 Promise 对象,一旦迭代器中的某个 Promise resolve 或 reject,返回的 Promise 就会 resolve 或 reject。

和 all 方法的区别在于,race 方法是谁执行的快,就用谁的结果。我们来看如下一段代码:

const promise1 = new Promise((resolve, reject) => {
    setTimeout(resolve, 500, 'one');
});
const promise2 = new Promise((resolve, reject) => {
    setTimeout(reject, 600, 'two');
});
Promise.race([promise1, promise2]).then((value) => {
    console.log(value);
});

promise1 执行时间短,promise2 执行时间长,所以最终结果就是 promise1 的结果。

6.3 Promise.reject()

Promise.reject() 方法返回一个带有 reject 原因的 Promise 对象。来看如下一段代码:

function resolved(result) {
    console.log('Resolved');
}
function rejected(result) {
    console.error(result);
}
Promise.reject("error").then(resolved).catch(rejected);

这个执行的时候就会进入到 catch 中。

6.4 Promise.resolve()

Promise.resolve(value) 方法返回一个以给定值解析后的 Promise 对象。

const promise1 = Promise.resolve(3);
promise1.then(data=>{
    console.log("data", data);
},err=>{
    console.log("err", err);
})

这个用法比较简单,没啥好说的。

还有一些其他方法我就不一一列举了,感兴趣的小伙伴们可以看看 MDN 上的相关讲解:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise

好啦,这个东西搞懂了,我们再去看 TienChin 项目的前端,就会非常容易了!


相关文章
|
17天前
|
Java 程序员
JAVA程序员的进阶之路:掌握URL与URLConnection,轻松玩转网络资源!
在Java编程中,网络资源的获取与处理至关重要。本文介绍了如何使用URL与URLConnection高效、准确地获取网络资源。首先,通过`java.net.URL`类定位网络资源;其次,利用`URLConnection`类实现资源的读取与写入。文章还提供了最佳实践,包括异常处理、连接池、超时设置和请求头与响应头的合理配置,帮助Java程序员提升技能,应对复杂网络编程场景。
41 9
|
3月前
|
存储 算法 Java
惊!Java程序员必看:JVM调优揭秘,堆溢出、栈溢出如何巧妙化解?
【8月更文挑战第29天】在Java领域,JVM是代码运行的基础,但需适当调优以发挥最佳性能。本文探讨了JVM中常见的堆溢出和栈溢出问题及其解决方法。堆溢出发生在堆空间不足时,可通过增加堆空间、优化代码及释放对象解决;栈溢出则因递归调用过深或线程过多引起,调整栈大小、优化算法和使用线程池可有效应对。通过合理配置和调优JVM,可确保Java应用稳定高效运行。
139 4
|
3月前
|
Java 程序员
Java数据类型:为什么程序员都爱它?
Java数据类型:为什么程序员都爱它?
52 1
|
2天前
|
SQL 存储 Java
面向 Java 程序员的 SQLite 替代品
SQLite 是轻量级数据库,适用于小微型应用,但其对外部数据源支持较弱、无存储过程等问题影响了开发效率。esProc SPL 是一个纯 Java 开发的免费开源工具,支持标准 JDBC 接口,提供丰富的数据源访问、强大的流程控制和高效的数据处理能力,尤其适合 Java 和安卓开发。SPL 代码简洁易懂,支持热切换,可大幅提高开发效率。
|
14天前
|
SQL Java 程序员
倍增 Java 程序员的开发效率
应用计算困境:Java 作为主流开发语言,在数据处理方面存在复杂度高的问题,而 SQL 虽然简洁但受限于数据库架构。SPL(Structured Process Language)是一种纯 Java 开发的数据处理语言,结合了 Java 的架构灵活性和 SQL 的简洁性。SPL 提供简洁的语法、完善的计算能力、高效的 IDE、大数据支持、与 Java 应用无缝集成以及开放性和热切换特性,能够大幅提升开发效率和性能。
|
19天前
|
IDE Java 程序员
C++ 程序员的 Java 指南
一个 C++ 程序员自己总结的 Java 学习中应该注意的点。
20 5
|
1月前
|
JSON 前端开发 Java
震惊!图文并茂——Java后端如何响应不同格式的数据给前端(带源码)
文章介绍了Java后端如何使用Spring Boot框架响应不同格式的数据给前端,包括返回静态页面、数据、HTML代码片段、JSON对象、设置状态码和响应的Header。
130 1
震惊!图文并茂——Java后端如何响应不同格式的数据给前端(带源码)
|
2月前
|
消息中间件 存储 前端开发
「3.4w字」超保姆级教程带你实现Promise的核心功能
该文章通过详细的步骤和示例代码,逐步介绍了如何从零开始实现一个符合ECMAScript标准的Promise对象,涵盖了Promise的基本使用、状态管理、链式调用、错误处理机制及Promise.all和Promise.resolve等方法的实现。
「3.4w字」超保姆级教程带你实现Promise的核心功能
|
1月前
|
前端开发 小程序 Java
java基础:map遍历使用;java使用 Patten 和Matches 进行正则匹配;后端传到前端展示图片三种情况,并保存到手机
这篇文章介绍了Java中Map的遍历方法、使用Pattern和matches进行正则表达式匹配,以及后端向前端传输图片并保存到手机的三种情况。
18 1
|
1月前
|
前端开发 JavaScript
轻松上手:基于single-spa构建qiankun微前端项目完整教程
轻松上手:基于single-spa构建qiankun微前端项目完整教程
38 0