Google Sheet API(Node.js利用)で、複数のシートを「1,2,3,4...」と並べて生成したいのに、
async,awaitで生成しても、シートが2,4,3,1みたいに順不同になってしまうのを、
どう回避できるかなかなかわかりませんでした。
辿り着いた解決策は、
array.reduceとPromiseを組み合わせて、thenでつないでいき、
Promise内でsetTimeoutをする、というものでした。
reduceに慣れていなかったので、
各引数の理解(特に第1とinitialValue)と、thenの理解、
また、初期値にPromice.resolve()を渡すあたりが難しかったです。
以下、実際に動くようになったコードです。
(SheetAPIのラッパークラスを自作していますので、よしなに読み替えてください)
import {Sheet} from './Sheet.mjs'//シート関連の処理を集めた自作クラス
import dotenv from 'dotenv'
dotenv.config()
const spreadsheetId = process.env.SOME_SPREADSHEET_ID
/**
* 複数のシートを順番に作成する
*/
const main = async function() {
const sheet = await Sheet.build()//auth取得などはここで処理している
//複数シート作成のため連番を準備(スプレッド構文便利ね)
const arr = [...(Array(10).keys())].slice(1)//0は排除
//関数の中でPromiseオブジェクトを返す無名関数を準備。これをarr.reduceで逐次実行する
const createWithSleep = (sheetName) => {
return () => {//ここで無名関数化してPromiseを返すのがreduce.then実行のキモ。無いと動かなかった
return new Promise(resolve => {
setTimeout(()=>{
createSheet(sheetName, sheet)//シート生成メソッド呼び出し
resolve()//resolve()でreduce内のthenが発火
}, 2000)//thenで実行していても、一定の時間差がシート順次生成に必要!500などではだめだった
})
}
}
//ここのarr.reduceでの逐次実行がとても重要!これがないとシートの生成が順不同になる(thenでの処理実行チェーン)
//シート名は's2'などでは読み取りなどのAPI実行時にカラム名と間違えられ困ったので、'組'というダブルバイトにしている
arr.reduce((pre, cur) => pre.then(createWithSleep('組' + cur)),
Promise.resolve())//最初にthenを発火させるために空のPromise.resolve()をinitialValueとして配置
}
//シートの生成部分. setTimeoutで十分時間をとっているのでasync,awaitは設定せず
const createSheet = (sheetName, sheet) => {
//ここのcreateSheetは普通のAPIメソッドの単なるラッパーです
sheet.createSheet(sheetName, spreadsheetId).then(() => console.log('created'))
}
main()
Google Sheet APIは、サクッとspreadsheetを作れたり、値を書き込んだり読み込んだり、
sheetを作成したり、超便利ですね。
nodeでローカルから楽しく操作できるのが気に入りましたが、
ちょいちょい書き方に詰まったので、同じところで詰まった方に役に立てばと、
恥を忍んでコードを晒してみます。
どなたかのお役に立てば幸いにて。
ではでは。