Javascript 承诺:将相同的承诺链接 n 次,然后做其他事情
Javascript Promises: Chain same promise n times, then do something else
我有一个返回承诺的函数,可以做一些异步的事情,我们称它为 functionToRepeat()
。
我正在尝试编写函数 repeatFunction(amount)
,以便它启动承诺,等待完成,再次启动,等待完成,等等给定的次数。这个 repeatFunction(amount)
也应该是 thenable 的,这样我就可以在它执行后链接其他东西。
这是我的尝试:
function functionToRepeat(){
let action = new Promise(function(resolve,reject){
setTimeout(function(){
console.log("resolved!");
resolve()}
,1000);
})
return action
}
function repeatFunction(amount) {
if(amount==0){
return Promise.resolve();
}
return functionToRepeat().then(function(){
repeatFunction(amount-1);
});
}
repeatFunction(5).then(function(){
console.log("DONE!");
})
这成功地链接了我的承诺(或者它接缝,我在控制台中每秒得到一个 "resolved!")。
但是 .then()
我尝试在我的 repeatFunction(5)
之后链接发生在第一个承诺结束之后,而不是在所有 5 个承诺结束之后!
所以在我的控制台中我得到:
解决!
完毕!
解决!
解决!
解决!
已解决!
我做错了什么,我应该改变什么?
您在拨打 repeatFunction(amount-1)
时错过了 return
function functionToRepeat(){
let action = new Promise(function(resolve,reject){
setTimeout(function(){
console.log("resolved!");
resolve()}
,1000);
})
return action
}
function repeatFunction(amount) {
if(amount==0){
return Promise.resolve();
}
return functionToRepeat().then(function(){
return repeatFunction(amount-1); // Added return
});
}
repeatFunction(5).then(function(){
console.log("DONE!");
})
我想你快到了,但是你必须在函数的 then 块中再次 return repeatFunction 才能重复。
return functionToRepeat().then(function(){
return repeatFunction(amount-1);
});
}
如果你有一个then
,但没有return任何东西,那么它只会解决上面的承诺。事情就是这样。
let loopP = (n, f, ...args) => {
let p = f(...args);
p.then(res => {
if (n - 1) {
loopP(n - 1, f, res);
}
});
};
其中n
是迭代次数,f
是要调用的Promise返回函数。对 f
的每次连续调用都会在解析时传递前一次调用的结果。
例如...
let addOneP = i => {
console.log(i + 1);
return Promise.resolve(i + 1);
};
loopP(5, addOneP, 0);
// logs:
// 1
// 2
// 3
// 4
// 5
简单的怎么样:
function repeat(func, times) {
var promise = Promise.resolve();
while (times-- > 0) promise = promise.then(func);
return promise;
}
测试时:
function oneSecond() {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log("tick");
resolve();
}, 1000);
});
}
repeat(oneSecond, 5).then(function () {
console.log("done");
});
此输出在 5 秒内生成:
tick
tick
tick
tick
tick
done
您可以通过简单的 while
循环使用 async
/await
。这让你在 Asyncland 中允许你在重复的函数完成后继续链接
async function asyncRepeat (f, n) {
while (n-- > 0)
await f()
}
asyncRepeat(functionToRepeat, 5).then(() => {
console.log('done')
})
// some value
// some value
// some value
// some value
// some value
// done
这是垃圾。您只能使用副作用函数作为 asyncRepeat
的 f
参数。所以登录到控制台是可行的,但是如果你真的想用那个值做些什么呢?
这是对 asyncRepeat
的更新,允许您通过重复应用输入函数(在本例中为 asyncDouble
)
(粗体中的重要变化)
async function asyncRepeat (f, n<b>, x</b>) {
while (n-- > 0)
<b>x = </b>await f(<b>x</b>)
return <b>x</b>
}
function <b>asyncDouble</b> (<b>x</b>) {
return new Promise(function (resolve, reject) {
setTimeout(() => {
console.log('x is currently: %d', x)
resolve(<b>x * 2</b>) // resolve an actual value
}, 1000)
})
}
asyncRepeat(asyncDouble, 5<b>, 2</b>).then(result => {
console.log('result: %d', result)
})
// x is currently: 2
// x is currently: 4
// x is currently: 8
// x is currently: 16
// x is currently: 32
// result: 64
您可能会发现 relign useful for this kind of thing. Here's your example written with relign series and relign setTimeout。
const fnToRepeat = () =>
relign.setTimeout(() => console.log("resolved!"), 1000);
relign.series((new Array(5)).fill(fnToRepeat))
.then(() => console.log('done'));
我想要类似的东西,所以我在 (https://repl.it/@turlockmike/BriskLovableLinuxkernel)
处写了一个通用函数
function repeat(fn, times) {
if (times == 1) {
return fn()
} else {
return new Promise(function(resolve, reject) {
return fn().then(function() {
return resolve(repeat(fn,times - 1))
})
})
}
}
用法
function doSomething() {
return new Promise(function(resolve, reject) {
//do something interested here
setTimeout(function(){
console.log("resolved!");
resolve()}
,1000);
})
}
repeat(doSomething, 5).then(() => {
console.log("all Done!")
})
const http = require('http');
const https = require('https');
const { t, d, r } = require('minimist')(process.argv.slice(2));
const checkRoot = config => {
const { delaySeconds, rootUrl } = config ? config : { delaySeconds: 6 };
const delay = delaySeconds * 1000;
const protocolString = rootUrl.split(':')[0];
const protocol = {
http: http,
https: https,
};
return new Promise(res => {
setTimeout(() => {
protocol[protocolString]
.get(rootUrl, resp => {
let data = '';
resp.on('data', chunk => {
data += chunk;
});
resp.on('end', () => {
res({ success: data.includes('<!doctype html>') });
});
})
.on('error', err => {
console.log(`Error: ${err.message}`);
res({ success: false });
});
}, delay);
});
};
const repeatChecking = async ({ times, delaySeconds, rootUrl }) => {
let isReady = false;
console.log(
`will try ${times}, and with ${delaySeconds} seconds delay in between for ${rootUrl}`
);
let i = 1;
while (i <= times) {
if (isReady === true) {
break;
}
const res = await checkRoot({ delaySeconds, rootUrl }).then();
isReady = res.success;
console.log(`testing ${i}, status: root ready => ${res.success}`);
i++;
}
if (isReady) {
console.log('Done, root is ready');
return;
}
process.stdout.write('ERROR: root could not be reached\n');
process.exit(1);
};
repeatChecking({ times: t, delaySeconds: d, rootUrl: r });
我有一个返回承诺的函数,可以做一些异步的事情,我们称它为 functionToRepeat()
。
我正在尝试编写函数 repeatFunction(amount)
,以便它启动承诺,等待完成,再次启动,等待完成,等等给定的次数。这个 repeatFunction(amount)
也应该是 thenable 的,这样我就可以在它执行后链接其他东西。
这是我的尝试:
function functionToRepeat(){
let action = new Promise(function(resolve,reject){
setTimeout(function(){
console.log("resolved!");
resolve()}
,1000);
})
return action
}
function repeatFunction(amount) {
if(amount==0){
return Promise.resolve();
}
return functionToRepeat().then(function(){
repeatFunction(amount-1);
});
}
repeatFunction(5).then(function(){
console.log("DONE!");
})
这成功地链接了我的承诺(或者它接缝,我在控制台中每秒得到一个 "resolved!")。
但是 .then()
我尝试在我的 repeatFunction(5)
之后链接发生在第一个承诺结束之后,而不是在所有 5 个承诺结束之后!
所以在我的控制台中我得到:
解决! 完毕! 解决! 解决! 解决! 已解决!
我做错了什么,我应该改变什么?
您在拨打 repeatFunction(amount-1)
return
function functionToRepeat(){
let action = new Promise(function(resolve,reject){
setTimeout(function(){
console.log("resolved!");
resolve()}
,1000);
})
return action
}
function repeatFunction(amount) {
if(amount==0){
return Promise.resolve();
}
return functionToRepeat().then(function(){
return repeatFunction(amount-1); // Added return
});
}
repeatFunction(5).then(function(){
console.log("DONE!");
})
我想你快到了,但是你必须在函数的 then 块中再次 return repeatFunction 才能重复。
return functionToRepeat().then(function(){
return repeatFunction(amount-1);
});
}
如果你有一个then
,但没有return任何东西,那么它只会解决上面的承诺。事情就是这样。
let loopP = (n, f, ...args) => {
let p = f(...args);
p.then(res => {
if (n - 1) {
loopP(n - 1, f, res);
}
});
};
其中n
是迭代次数,f
是要调用的Promise返回函数。对 f
的每次连续调用都会在解析时传递前一次调用的结果。
例如...
let addOneP = i => {
console.log(i + 1);
return Promise.resolve(i + 1);
};
loopP(5, addOneP, 0);
// logs:
// 1
// 2
// 3
// 4
// 5
简单的怎么样:
function repeat(func, times) {
var promise = Promise.resolve();
while (times-- > 0) promise = promise.then(func);
return promise;
}
测试时:
function oneSecond() {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log("tick");
resolve();
}, 1000);
});
}
repeat(oneSecond, 5).then(function () {
console.log("done");
});
此输出在 5 秒内生成:
tick
tick
tick
tick
tick
done
您可以通过简单的 while
循环使用 async
/await
。这让你在 Asyncland 中允许你在重复的函数完成后继续链接
async function asyncRepeat (f, n) {
while (n-- > 0)
await f()
}
asyncRepeat(functionToRepeat, 5).then(() => {
console.log('done')
})
// some value
// some value
// some value
// some value
// some value
// done
这是垃圾。您只能使用副作用函数作为 asyncRepeat
的 f
参数。所以登录到控制台是可行的,但是如果你真的想用那个值做些什么呢?
这是对 asyncRepeat
的更新,允许您通过重复应用输入函数(在本例中为 asyncDouble
)
(粗体中的重要变化)
async function asyncRepeat (f, n<b>, x</b>) {
while (n-- > 0)
<b>x = </b>await f(<b>x</b>)
return <b>x</b>
}
function <b>asyncDouble</b> (<b>x</b>) {
return new Promise(function (resolve, reject) {
setTimeout(() => {
console.log('x is currently: %d', x)
resolve(<b>x * 2</b>) // resolve an actual value
}, 1000)
})
}
asyncRepeat(asyncDouble, 5<b>, 2</b>).then(result => {
console.log('result: %d', result)
})
// x is currently: 2
// x is currently: 4
// x is currently: 8
// x is currently: 16
// x is currently: 32
// result: 64
您可能会发现 relign useful for this kind of thing. Here's your example written with relign series and relign setTimeout。
const fnToRepeat = () =>
relign.setTimeout(() => console.log("resolved!"), 1000);
relign.series((new Array(5)).fill(fnToRepeat))
.then(() => console.log('done'));
我想要类似的东西,所以我在 (https://repl.it/@turlockmike/BriskLovableLinuxkernel)
处写了一个通用函数function repeat(fn, times) {
if (times == 1) {
return fn()
} else {
return new Promise(function(resolve, reject) {
return fn().then(function() {
return resolve(repeat(fn,times - 1))
})
})
}
}
用法
function doSomething() {
return new Promise(function(resolve, reject) {
//do something interested here
setTimeout(function(){
console.log("resolved!");
resolve()}
,1000);
})
}
repeat(doSomething, 5).then(() => {
console.log("all Done!")
})
const http = require('http');
const https = require('https');
const { t, d, r } = require('minimist')(process.argv.slice(2));
const checkRoot = config => {
const { delaySeconds, rootUrl } = config ? config : { delaySeconds: 6 };
const delay = delaySeconds * 1000;
const protocolString = rootUrl.split(':')[0];
const protocol = {
http: http,
https: https,
};
return new Promise(res => {
setTimeout(() => {
protocol[protocolString]
.get(rootUrl, resp => {
let data = '';
resp.on('data', chunk => {
data += chunk;
});
resp.on('end', () => {
res({ success: data.includes('<!doctype html>') });
});
})
.on('error', err => {
console.log(`Error: ${err.message}`);
res({ success: false });
});
}, delay);
});
};
const repeatChecking = async ({ times, delaySeconds, rootUrl }) => {
let isReady = false;
console.log(
`will try ${times}, and with ${delaySeconds} seconds delay in between for ${rootUrl}`
);
let i = 1;
while (i <= times) {
if (isReady === true) {
break;
}
const res = await checkRoot({ delaySeconds, rootUrl }).then();
isReady = res.success;
console.log(`testing ${i}, status: root ready => ${res.success}`);
i++;
}
if (isReady) {
console.log('Done, root is ready');
return;
}
process.stdout.write('ERROR: root could not be reached\n');
process.exit(1);
};
repeatChecking({ times: t, delaySeconds: d, rootUrl: r });