TL;DR
type Supplier<T> = () => T;
export const sequence = <T>(promises: Supplier<PromiseLike<T>>[]): Promise<T[]> => {
if (promises.length === 0) {
return Promise.resolve([]);
}
return new Promise((resolve, reject) => {
const results: T[] = [];
promises
.reduce((p1: Supplier<PromiseLike<T>>, p2: Supplier<PromiseLike<T>>): Supplier<PromiseLike<T>> => {
return () => {
return p1().then((t: T) => {
results.push(t);
return p2();
});
};
})()
.then(
(t: T) => {
results.push(t);
resolve(results);
},
(e: unknown) => {
reject(e);
}
);
});
};
経緯
ときどき Promise<T>[]
を0番目から順番に実行してほしいことがあります。こんなときに Promise.all()
を使ってしまうととすべての Promise
を同時に実行してしまうためこの要件を満たすことができません。そこで0番目の Promise
が履行されたら1番目の Promise
を、1番目が履行されたら2番目を...といった順次実行ができる Promise
の処理を考えてみました。
結論
できれば Promise.all()
とシグネチャを同じにしたかったが不可能でした。参考
Promise.all<T>(values: Iterable<T | PromiseLike<T>>): Promise<Awaited<T>[]>;
理由は Promise
の実行を遅延させるために関数で包んであげないといけなかったからです。