KDP(電子出版)のメモ 急急如律令

Amazon Kindleダイレクト・パブリッシングでの電子出版や電子書籍の作成販売について、文章やイラストの作成や編集方法について書いています。

node-fetchを使って躓いたところ

 サイトのクロールに今まで使っているのがnode.jsのrequest。非同期処理の書き方がなれないのでsync-requestを使ったり。sync-requestは同期処理っぽくかけるのでかんたんにリクエスト処理がかける。ただ、連続処理をするとメモリを大量に使って止まる。なので、requestをasync awitを使って同期処理っぽくかいている。

 最近になってnode-fetchがいいという意見を見たいので試しにnode-fetchを使ってみて詰まったところを書いておく。

 

npmでnode-fetchをインストールして、下のnode-fetchのサンプルコードを貼り付けて実行したらエラー。awaitがなんたらのえらー。

const fetch = require('node-fetch');

const response = await fetch('https://github.com/');
const body = await response.text();

console.log(body);

 

非同期処理のために、関数化すると動いた。ついでにトライキャッチエラーも追加した。

(async () => {
try {
const response = await fetch('https://github.com/');
const json = await response.json();
console.log(json);
} catch (error) {
console.log(error);
}
})();

github.com

 

タイムアウト処理

requestのときはoptionにタイムアウト処理を入れれば、タイムアウトが実行できた。node-fetchではAbortController()を使うようである。ただ、node.jsのv15以降に追加された、AbortController()を使ってみたが動かなかった。どうやら、npmのabort-controllerを使うようだ。入れてもだめだった。

abort-controllerを使うにはnode.jsのバージョンが6, 8, 9, 10, 11, 12, 13.である必要があるみたい。もう少しわかりやすいところにかいていてくれれば、悩まずにすんだのだが。英語のエラー文面は流し読みしてしまう傾向がある。

Supported releases of Node.js are the latest release of 6, 8, 9, 10, 11, 12, 13.

 

 

サンプルコードはこれ。

Request cancellation with AbortSignal
You may cancel requests with AbortController. A suggested implementation is abort-controller.

An example of timing out a request after 150ms could be achieved as the following:

const fetch = require('node-fetch');
const AbortController = require('abort-controller');

const controller = new AbortController();
const timeout = setTimeout(() => {
controller.abort();
}, 150);

try {
const response = await fetch('https://example.com', {signal: controller.signal});
const data = await response.json();
} catch (error) {
if (error instanceof fetch.AbortError) {
console.log('request was aborted');
}
} finally {
clearTimeout(timeout);
}

 

オプションにタイムアウトを追加すると、タイムアウトエラーに持っていけるようだ。

var options = {
timeout: 1500
};

fetch('https://github.com/',options);

 

node-fetchで abort-controllerを利用せずにタイムアウトすると、いつまで立っても処理が終わらないようだ。

process.exit(0); で無理やり終わらせるのも手かな。

 

また、エラーで止まった場合にretryをどのように書くかというのも考えもの。

 で、エラーを出さなかったらループを抜けるとかいた。

loop2: for (let step = 0; step < 5; step++) {
try {
await requestPromise(options);
break loop2;
} catch (error) {
console.log(error);
}
}