経緯
WEBスクレイピングやろうと思った訳ですよ。ただ「このページを定期的にクロールする」とかじゃなくて「わんさかあるページからわんさか情報取ってくる」ってやつで、流石にページロードの間隔空けないと問題が起こるなぁと思って。
setTimeout
は戻り値がとれない
外部にコンテナ用意して入れるとか、そんなむりやりな方法もありますが、関数が戻り値を返すんだからそのままほしいじゃん。
実装(普通の関数)
// 関数を遅延実行できるようにするやつ
const lazyFunction = (f, ...args) => {
return () => f(...args)
}
// 適当な関数
const log = (n) => {
console.log(n)
return n
}
// 適当な関数を5個実行できるようにする
const logs = [1,2,3,4,5].map(n => lazyFunction(log,n))
// 等間隔実行の関数
const intervaledExecute = async (fs, interval) => {
const promises = fs.map((f, i) => new Promise((resolve, reject) => {
// setTimeout を interval 伸ばしながら実行するようにする
setTimeout(() => resolve(f()), interval * i)
}))
// Promiseは一気に解決しちゃう
return await Promise.all(promises)
}
// 1秒毎に1、2、3、4、5って出てその後に[1,2,3,4,5]が出る
(async () => {
res = await intervaledExecute(logs, 1000)
console.log(res)
})()
実装(実行したいのがPromiseだった場合)
// ここはかわらない
const lazyFunction = (f, ...args) => {
return () => f(...args)
}
// 適当なPromise関数
const logp = n => new Promise((resolve, reject) => {
console.log(n)
setTimeout(() => resolve(n), 500)
})
const logps = [1,2,3,4,5].map(n => lazyFunction(logp, n))
// 等間隔実行関数
const intervaledExecutePromises = async (ps, interval) => {
const promises = ps.map((p,i) => new Promise((resolve, reject) => {
// then で Promise の結果を取り出して外の resolve に渡す
setTimeout(
() => p().then((r, s) => resolve(r)),
interval * i
)
}))
return await Promise.all(promises)
}
// 0.5 秒毎に数字が出て最後に配列が出る
(async () => {
res = await intervaledExecutePromises(logps, 500)
console.log(res)
})()
力技だなぁ……なんかもーちょっと……スマートな書きかた無いかなぁ……