在前端开发中,Promise 和 Future 都是处理异步编程的重要技术手段。它们的基本思想很相似,但其细节和实现方式却有很大的差别。本文将比较 Promise 和 Future 的异同,并为读者提供学习和指导意义。
Promise 和 Future 的定义
Promise 和 Future 都是处理异步编程的技术手段,目的是为了避免回调地狱(Callback Hell),让异步调用更加优雅和简便。具体地说,
Promise :是 ES6 语法中的概念;可以将它理解为一个代表了异步操作的对象,提供了一种统一的方法来处理异步操作返回值的成功和失败情况。
Future :是函数式编程 FLuture 库中的概念;可以将它理解为一个封装了异步操作的函数,通过链式调用来显式地控制状态的变化。
虽然它们的定义略有不同,但都是用来处理异步编程的情况,快捷且统一的处理回调函数解决了前端异步编程的难点。
Promise 和 Future 的实现方式
Promise 和 Future 的内在实现方式却有所不同。
Promise :主要是采用了状态转移机的方式来实现异步操作,有以下三种状态:
- Pending(进行中)
- Fulfilled(已成功)
- Rejected(已失败)
每个状态都是单向转换的,可以通过 then 方法和 catch 方法,依据 Promise 代码的(Promise A+规范,规范文档地址:https://promisesaplus.com/)操作,决定 Promise 对象如何转换。
Promise的常用方法:
| 方法 | 描述 |
|---|---|
| then | 在异步完成后调用,Promise成功则调用onFulfilled,失败则调用onRejected |
| catch | 当 Promise 状态为 rejected 时才会调用 |
- Future :主要是选择将异步结果包装成一个容器,通过链式调用显式地控制状态的变化,从而主动控制异步操作的执行顺序,其图示如下所示:
// www.javascriptcn.com code example
+------------------+
| Future |
+------------------+
⬇
+------------------+
| compute(value) |
+------------------+
⬇
+------------------+
| map(f:fn) |
+------------------+
⬇
+------------------+
| flatMap(f:fn) |
+------------------+
⬇
在这个例子中,Future 中封装的是一个 compute 方法,用来调用异步操作逻辑,map 和 flatMap 则用来显式控制状态的变化,执行逻辑中的 fn 回调函数,以实现线性的异步调用。
## Promise 和 Future 的区别
从上面的定义和实现方式来看,Promise 和 Future 在某些细节上略有不同,下面将从以下三个维度来阐述 Promise 和 Future 的区别:
1. **处理方式上的异同:**
Promise 和 Future 都用来处理异步编程,本质上使用 Promise 是将异步函数统一转为 Promise 内部的状态转移机来支持异步调用,而 Future 则是显式控制异步的状态转移,显然 Future 更简单并且能够更加灵活地编程。
2. **更改状态的方式:**
Promise 改变状态是通过回调方式来实现的,回调的存在使得其转换需要繁琐的判定,也就是链式回调的写法;而 Future 的方式是通过显式地调用 map 和 flatMap 来实现功能并减少回调的数量,使其代码更加简洁。
3. **惰性求值与及时求值:**
惰性求值的 Future 是在该操作被需要的时候才调用,而 Promise 是一直等待异步操作完成,然后再执行后面的逻辑,这在某些场合下会影响代码执行效率。
## 示例代码
Future领域的代码使用的是 Fluture 这个库,具体 API 可以参见 [https://github.com/fluture-js/Fluture#api](https://github.com/fluture-js/Fluture#api)。
下面是一个简单 Future 的例子:
```js
const { encaseP, map: fmap } from 'fluture';
// fluture example
const getUserProfile = (id) => fetch(`/api/users/${id}`);
const parseJson = (res) => res.json();
const getProfile = (id) =>
encaseP(getUserProfile, id)
.chain(fmap(parseJson))
.map(user => user.profile);
/* 在 JavaScript 中实现的几种方式如下 */
// 异步 await 示例
const getUserProfile_AsyncAwait = async (id) => {
const res = await getProfile(id);
const user = await parseJson(res);
return user.profile;
};
// Promise 示例
const getUserProfile_Promise = (id) => {
return new Promise(resolve => {
getProfile(id)
.fork(
() => resolve(null),
res => parseJson(res).fork(() => resolve(null), user => resolve(user.profile))
)
})
};学习意义
本文介绍了 Promise 和 Future 的异同比较,发现使用 Future 的代码具有更好的可读性和可维护性,能够避免回调地狱,并且更加灵活。同时,强烈建议读者评估一下自己所使用的异步框架是否真的符合设计的良好结构。最后,读者应当根据具体情况在代码中合理地应用 Future 的方法,优化异步调用的效率。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67ca47a8e46428fe9e240a41