LoginSignup
3
4

More than 5 years have passed since last update.

Promiseを複数の直列処理と並列処理を組み合わせる

Last updated at Posted at 2017-01-13

そもそもそんな複雑なことしないほうが...
まあそうですね…

今回のタイミングで改めてPromiseやArrayまわりと向き合ったのでメモ

直列処理

const task = (label, timeout) => {
    return () => {
        return new Promise((resolve, reject) => {
            console.log(`${label} start`);

            setTimeout(() => {
                console.log(`${label} done`);
                //timeout秒経ったら次へ
                resolve();
            }, timeout);
        });
    }
};

console.log('promise start');
Promise.resolve()
    .then(task('task1', 100))
    .then(task('task2', 200));

こんな処理が3回とかだったらまだいいかもしれないが、これが多数となったらこのままthenで続けるような記述をするのはつらすぎる…

そこでArray#reduceを使って記述してみる
Array.prototype.reduce() - JavaScript | MDN

Array#reduceを使って直列繋ぎ

promise-reduce.js
const task = (label, timeout) => {
    return () => {
        return new Promise((resolve, reject) => {
            console.log(`${label} start time: ${timeout}`);

            setTimeout(() => {
                console.log(`${label} done`);
                //timeout秒経ったら次へ
                resolve();
            }, timeout);
        });
    }
};

const REPEAT = 10;
[...Array(REPEAT).keys()].reduce((promise, current) => {
    let label = `task${current}`;
  let timeout = Math.floor((Math.random() * 500));
    return promise.then(task(label, timeout));
}, Promise.resolve());

結果

$node promise-reduce.js

task0 start time: 69
task0 done
task1 start time: 5
task1 done
task2 start time: 191
task2 done
task3 start time: 89
task3 done
task4 start time: 458
task4 done
task5 start time: 112
task5 done
task6 start time: 107
task6 done
task7 start time: 14
task7 done
task8 start time: 284
task8 done
task9 start time: 183
task9 done

並列×直列処理

この個数が更に増えたら、ちょっとだけ並列にも動かしたい。
でも結果は同時にほしい

promise-parallel-serial.js
const task = (label, timeout) => {
  return () => {
    return new Promise((resolve, reject) => {
      console.log(`start: ${label}  time: ${timeout}`);

      setTimeout(() => {
        console.log(`done:  ${label}  time: ${timeout}`);
        //timeout秒経ったら次へ
        resolve();
      }, timeout);
    });
  }
};

//直列処理は3つ
const REPEAT = 3;
//並列は4つ
const PARALLEL = 4;

const parallels = [...Array(PARALLEL).keys()].map(index => {
  let lastpromise = [...Array(REPEAT).keys()].reduce((promise, current) => {
    let label = `task ${index+1}-${current+1}`;
    let timeout = Math.floor((Math.random() * 500));
    return promise.then(task(label, timeout));
  }, Promise.resolve());

  return lastpromise;
});


Promise.all(parallels).then(() => {
    //並列実行したすべてが完了したとき
  console.log('all done');
});

結果

start: task 1-1  time: 179
start: task 2-1  time: 26
start: task 3-1  time: 199
start: task 4-1  time: 303
done:  task 2-1  time: 26
start: task 2-2  time: 469
done:  task 1-1  time: 179
start: task 1-2  time: 365
done:  task 3-1  time: 199
start: task 3-2  time: 36
done:  task 3-2  time: 36
start: task 3-3  time: 360
done:  task 4-1  time: 303
start: task 4-2  time: 474
done:  task 2-2  time: 469
start: task 2-3  time: 331
done:  task 1-2  time: 365
start: task 1-3  time: 82
done:  task 3-3  time: 360
done:  task 1-3  time: 82
done:  task 4-2  time: 474
start: task 4-3  time: 47
done:  task 4-3  time: 47
done:  task 2-3  time: 331

メモ

  • Promise.allはthenをまとめてるだけ。
  • async/awaitのほうがわかりやすいだろうな

参考

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4