前端的同学对Promise
肯定都很熟悉,而Future
便是dart
中Promise
,但方法名称和使用方式还是有些许的差异的。
下面我们尝试,利用Future
封装出js中我们熟悉的Promise
。
Javascript Promise 参考
https://es6.ruanyifeng.com/#docs/promise
实现Promise的基本用法
import 'dart:async';
class Promise {
Future future;
Promise(dynamic excutor(dynamic resolve(val), dynamic reject(val))) {
if (!(excutor is Function)) {
throw new AssertionError('Promise resolver $excutor is not a function');
}
final completer = Completer();
try {
excutor(completer.complete, completer.completeError);
} catch (e) {
completer.completeError(e);
}
this.future = completer.future;
}
/// Promise链式回调,对应Dart [.then]
Future then(Future Function(dynamic) onValue, {Function onError}) {
return this.future?.then(onValue, onError: onError);
}
/// Promise链式回调,对应Dart [.catchError]
Future catch_(Function onError, {bool Function(Object) test}) {
return this.future?.catchError(onError, test: test);
}
/// Promise链式回调,对应Dart [.whenComplete]
Future finally_(Future<dynamic> Function() action) {
return this.future?.whenComplete(action);
}
}
使用示例
Promise promise = Promise((resolve,reject){
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
})
// 链式回调
promise
.then((value) => null)
.catch_((error) => null)
.finally_((action) => null);
// 如果要使用dart的 async/await 需要先获取到 Promise 实例内的 Future
dynamic result = await promise.future;
Futrue中有对应实现的方法
Promise.all
, Promise.race
, Promise.resolve
, Promise.reject
class Promise{
/// 用于将多个 Future 实例,包装成一个新的 Future 实例。
/// 等待[futures]完成并收集其结果。
static Future all(Iterable<Future> futures) => Future.wait(futures);
/// 对应Dart [Future.any]
/// 返回[futures]中成功完成的第一个future的结果。
/// 任意失败都会导致抛出异常
static Future race(Iterable<Future> futures) => Future.any(futures);
/// 对应Dart [Future.value]
static Future resolve(dynamic value) => Future.value(value);
/// 对应Dart [Future.error]
static Future reject(dynamic value) => Future.error(value);
}
Futrue中有无对应实现的方法
Promise.allSettled
方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只有等到所有这些参数实例都返回结果,不管是fulfilled
还是rejected
,包装实例才会结束。该方法由 ES2020 引入
class Promise{
static final String FULFILLED = 'fulfilled';
static final String REJECTED = 'rejected';
/// 用于将多个 Future 实例,包装成一个新的 Future 实例。
/// 不论成功失败,都返回结果
static Future allSettled(Iterable<Future> futures) {
List<dynamic> result = List.generate(futures.length, (index) => null);
final completer = Completer();
for (int i = 0; i < futures.length; i++) {
futures.elementAt(i).then((value) {
result[i] = {'status': FULFILLED, 'value': value};
}).catchError((error) {
result[i] = {'status': REJECTED, 'reason': error};
}).whenComplete(() {
if (result.every((element) => element != null)) {
return completer.complete(result);
}
});
}
return completer.future;
}
}
Promise.any()
方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例。只要参数实例有一个变成fulfilled
状态,包装实例就会变成fulfilled
状态;如果所有参数实例都变成rejected
状态,包装实例就会变成rejected
状态。该方法目前是一个第三阶段的提案 。
Promise.any()
跟Promise.race()
方法很像,只有一点不同,就是不会因为某个 Promise 变成rejected
状态而结束。
class Promise{
/// 返回[futures]中成功完成的第一个future的结果;
/// 全部失败才会抛出异常
/// ```
/// @param futures {Iterable<Future>} Future 实例组
/// @param onlyError {bool} 是否只抛出最后一个异常结果,否则抛出一个异常 List ,默认 false
/// ```
static Future any(Iterable<Future> futures, {bool onlyError = false}) async {
List<dynamic> errors = [];
final completer = Completer();
for (int i = 0; i < futures.length; i++) {
futures.elementAt(i).then((value) {
completer.complete(value);
}).catchError((error) {
errors[i] = error;
if (futures.length == errors.length) {
completer.completeError(onlyError ? error : errors);
}
});
}
return completer.future;
}
}
顺便把延迟函数
也封装一下,毕竟毫秒延迟的使用频率是最高的。
class Promise{
static Future sleep(int ms) => Future.delayed(Duration(milliseconds: ms));
}