递归串行调用承诺
Recursive serial call promise
我想实现对promise方法times
的递归串行调用,将fn
函数调用N次的结果返回给数组
目前我在times
函数中添加了一个额外的属性results
来保存每次fn
调用的结果
我也不想使用模块范围的变量来保存结果。或者,通过传递附加参数(如 times(fn, n, results)
)来保存结果,这将破坏函数签名。
不允许 async/await
语法。
有没有办法只用函数局部变量来保存结果?
const times = Object.assign(
(fn: (...args: any) => Promise<any>, n: number = 1) => {
if (n === 0) return times.results;
return fn().then((res) => {
times.results.push(res);
return times(fn, --n);
});
},
{ results: [] as any[] },
);
用法:
const createPromise = (args: any) =>
new Promise((resolve) => {
setTimeout(() => {
console.log(`[${new Date().toISOString()}]args: `, args);
resolve(args);
}, 1000);
});
async function test() {
const actual = await times(() => asyncFn('data'), 3);
console.log(actual); // output: [ 'data', 'data', 'data' ]
}
您想要实现的是具有顺序和递归模式。您可以通过以下方式实现它
Solution:
- 在你的函数中创建 2 个承诺
finalPromise
: 从函数返回的承诺
promise
:将由传递的 fn
创建的 Promise
- 对于
finalPromise
,复制解析器函数的引用并存储它以供手动调用,比如resolverFn
- 创建一个变量
result
来存储值。这应该是 any[]
类型
- 在
promise.then
,
- 将收到的值推送到
result
- 对时间进行后续调用。
- 后续调用的技巧,
- 如果
n === 1
,传递给 times
的回调将是 resolverFn
。确保在通过或执行 () => resolverFn(result)
之前绑定 result
- 否则通过
fn
- 存储此调用的输出,比如
innerPromise
然后在其上,用 result
调用 resolverFn
根本没有理由使用有状态 result
变量。只需反转递归方向:
function times<T>(fn: () => Promise<T>, n: number = 1): Promise<T[]> {
if (n === 0) return Promise.resolve([]);
else return times(fn, n-1).then(results =>
fn().then(res => {
results.push(res);
return results;
})
});
}
但是如果你坚持更渐进地创建承诺,你将需要使用累加器参数:
function times<T>(fn: () => Promise<T>, n: number = 1, results: T[] = []): Promise<T[]> {
if (n === 0) return Promise.resolve(results);
else return fn().then(res => {
results.push(res);
return times(fn, n-1, results);
});
}
如果您不喜欢在签名中包含额外的可选参数,请使用执行递归的本地辅助函数:
function times<T>(fn: () => Promise<T>, n: number = 1): Promise<T[]> {
function recurse(n: number, results: T[]): Promise<T[]> {
if (n === 0) return Promise.resolve(results);
else return fn().then(res => {
results.push(res);
return recurse(n-1, results);
});
}
return recurse(n, []);
}
// or more ugly (stateful):
function times<T>(fn: () => Promise<T>, n: number = 1): Promise<T[]> {
let results: T[] = [];
function recurse(): Promise<T[]> {
if (n-- === 0) return Promise.resolve(results);
else return fn().then(res => {
results.push(res);
return recurse();
});
}
return recurse();
}
我想实现对promise方法times
的递归串行调用,将fn
函数调用N次的结果返回给数组
目前我在times
函数中添加了一个额外的属性results
来保存每次fn
调用的结果
我也不想使用模块范围的变量来保存结果。或者,通过传递附加参数(如 times(fn, n, results)
)来保存结果,这将破坏函数签名。
async/await
语法。
有没有办法只用函数局部变量来保存结果?
const times = Object.assign(
(fn: (...args: any) => Promise<any>, n: number = 1) => {
if (n === 0) return times.results;
return fn().then((res) => {
times.results.push(res);
return times(fn, --n);
});
},
{ results: [] as any[] },
);
用法:
const createPromise = (args: any) =>
new Promise((resolve) => {
setTimeout(() => {
console.log(`[${new Date().toISOString()}]args: `, args);
resolve(args);
}, 1000);
});
async function test() {
const actual = await times(() => asyncFn('data'), 3);
console.log(actual); // output: [ 'data', 'data', 'data' ]
}
您想要实现的是具有顺序和递归模式。您可以通过以下方式实现它
Solution:
- 在你的函数中创建 2 个承诺
finalPromise
: 从函数返回的承诺promise
:将由传递的fn
创建的 Promise
- 对于
finalPromise
,复制解析器函数的引用并存储它以供手动调用,比如resolverFn
- 创建一个变量
result
来存储值。这应该是any[]
类型
- 在
promise.then
,- 将收到的值推送到
result
- 对时间进行后续调用。
- 将收到的值推送到
- 后续调用的技巧,
- 如果
n === 1
,传递给times
的回调将是resolverFn
。确保在通过或执行() => resolverFn(result)
之前绑定 - 否则通过
fn
result
- 如果
- 存储此调用的输出,比如
innerPromise
然后在其上,用result
调用
resolverFn
根本没有理由使用有状态 result
变量。只需反转递归方向:
function times<T>(fn: () => Promise<T>, n: number = 1): Promise<T[]> {
if (n === 0) return Promise.resolve([]);
else return times(fn, n-1).then(results =>
fn().then(res => {
results.push(res);
return results;
})
});
}
但是如果你坚持更渐进地创建承诺,你将需要使用累加器参数:
function times<T>(fn: () => Promise<T>, n: number = 1, results: T[] = []): Promise<T[]> {
if (n === 0) return Promise.resolve(results);
else return fn().then(res => {
results.push(res);
return times(fn, n-1, results);
});
}
如果您不喜欢在签名中包含额外的可选参数,请使用执行递归的本地辅助函数:
function times<T>(fn: () => Promise<T>, n: number = 1): Promise<T[]> {
function recurse(n: number, results: T[]): Promise<T[]> {
if (n === 0) return Promise.resolve(results);
else return fn().then(res => {
results.push(res);
return recurse(n-1, results);
});
}
return recurse(n, []);
}
// or more ugly (stateful):
function times<T>(fn: () => Promise<T>, n: number = 1): Promise<T[]> {
let results: T[] = [];
function recurse(): Promise<T[]> {
if (n-- === 0) return Promise.resolve(results);
else return fn().then(res => {
results.push(res);
return recurse();
});
}
return recurse();
}