Axiosによる閉鎖の使用


最近、私はサブスクリプション/支払いゲートウェイとの統合に取り組んでいます.(それは簡単ではなかったけど、それは他のポストです.)
私はゲートウェイからのイベントを繰り返しトリガせずに自分のWebフックコードをテストできるようになりたかった.私は、JSON形式で入って来るイベントを保存しました.そして、それはすばらしいです、しかし、もちろん、私は格納されたイベントをとって、彼らと何かをする必要がありました.
私は、私がどこから始めたか、そして、私が終わりまでどのようになったかについてメモをすることがおもしろいかもしれないと思いました.私は道に沿って作った間違いが含まれているので、少し読んで、“それは動作しません!”たぶん、次の段落で出てきたのです.

開始
単純な起動-オブジェクトの配列にファイルを読み取り、ループを介して各イベントからの詳細のカップルを印刷するので、我々はそれが大丈夫ロード知っている.
テストコードとして使用するつもりですthe Sync version of readFile コードをシンプルに保つにはコールバックはなく、readFileSync まっすぐに JSON.parse , 以下のように:
const fs = require('fs');

function run() {
    const json = JSON.parse(fs.readFileSync(__dirname + "/events.json"))

    for (const event of json) {
        console.log("event: ", event.id, event.event_type);
    }
}

run()

確かに、我々は我々が期待するものを得る.
$ node post-events.js
event: 1 Hello
event: 2 World

それは動作しますが、ループは本当に迅速にイベントを投稿する予定です.私は彼らをスペースを好むでしょう-それは、そのように受信コードを見るのがより簡単にします、そして、私はこの点でそれをテストしようとしていません.

徐々に送信する
setTimeout うまく実行される関数をキューイングするためにうまく動作します.待ち時間の最も簡単なことは、配列の位置を使用することです.The for...of Constructionはインデックスを与えませんので、別のメソッドを使用する必要があります.
forEach アイテムとインデックスの両方を与えることができますので、それを使用しましょう.これは、変更ループ-ファイルの読み取りとJSON構文解析は同じままですので、私はそれを繰り返すことはありません.
json.forEach((event, index) => {
    console.log(`Event ${event.id}: ${event.event_type}`);
    console.log(`Will delay ${(index + 1) * 1000} ms`);
})

ええと、私たちは良いです.
$ node post-events.js
Event 1: Hello
Would delay 1000 ms
Event 2: World
Would delay 2000 ms


スケジューリング
現在、我々はちょうど予定する何かを必要とします.試しましょうthe simplest thing まず、各イベントに対して、event イベントIDを出力するパラメータとして.
json.forEach((event, index) => {
    const timeout = (index + 1) * 1000;
    console.log(`Event ${event.id}: ${event.event_type}`);
    console.log(`Will delay ${timeout} ms`);
    setTimeout(event => console.log("Posting", event.id), timeout);
})

および
$ node post-events.js
Event 1: Hello
Will delay 1000 ms
Event 2: World
Will delay 2000 ms
post-events.js:10
        setTimeout(event => console.log("Posting", event.id), timeout);
                                                         ^
TypeError: Cannot read property 'id' of undefined
    at Timeout._onTimeout (post-events.js:10:52)
    at listOnTimeout (node:internal/timers:557:17)
    at processTimers (node:internal/timers:500:7)

それについて考えると、それは意味をなします、そして、私は本当によりよく知っていなければなりませんでした.
The event 関数が実行されたときにパラメータが読み込まれます.タイムアウトのため、ループが終了した後に関数が実行されますevent もはや定義されていません.

閉鎖
私たちができることは、Aとして知られているものを作り出すことですclosure . クロージャは本質的に、それが作成されたときに存在する環境と一緒に機能する.幸いにもJavascriptは簡単です.
function makeFunc(event) {
    console.log("Making func for", event);
    return async function() {
        console.log("Posting", event.event_type);
    }
}

ループのもう一つのバージョン
json.forEach((event, index) => {
    const timeout = (index + 1) * 1000;
    console.log(`Setting timeout for Event ${event.id}; delay ${timeout} ms.`);
    setTimeout(event => makeFunc(event), timeout);
})


$ node post-events.js
Setting timeout for Event 1; delay 1000 ms.
Setting timeout for Event 2; delay 2000 ms.
Making func for undefined
Making func for undefined

よく…何かが間違っている.何が起こったのですかevent => makeFunc(event) , への呼び出しmakeFunc すぐに起こったが、遅れていました-それは我々に以前と同じ問題を与えます.すぐに呼び出しましょう.
json.forEach((event, index) => {
    const timeout = (index + 1) * 1000;
    console.log(`Setting timeout for Event ${event.id}; delay ${timeout} ms.`);
    setTimeout(makeFunc(event), timeout);
})

を参照してください.
$ node post-events.js
Setting timeout for Event 1; delay 1000 ms.
Making func for { id: 1, event_type: 'Hello' }
Setting timeout for Event 2; delay 2000 ms.
Making func for { id: 2, event_type: 'World' }
Posting Hello
Posting World


ポストリクエスト
それはそれのようです.HTTPエンドポイントへのポストを行うためにaxiosを使用します.
const fs = require('fs');
const axios = require("axios");

const client = axios.create()

function makeFunc(event) {
    return async function() {
        console.log("Posting", event.event_type);
        const res = await client.post("http://localhost:8000/", event);
        if (res.isAxiosError) {
            console.error("Error posting");
        }
    }
}

function run() {
    const json = JSON.parse(fs.readFileSync(__dirname + "/events.json"))

    json.forEach((event, index) => {
        const timeout = (index + 1) * 1000;
        console.log(`Setting timeout for Event ${event.id}; delay ${timeout} ms.`);
        setTimeout(makeFunc(event), timeout);
    })
}

run()


出力を見る
あなたのようなサービスを使用することができますrequestbin どのような記事を確認する簡単な方法として.このために使用することを決めたfiatjaf’s requestbin - それは小さくて簡単です.
そして、ここでは-正しいデータ、および私たちが期待したように間隔を2分の間隔.
$ ./requestbin -port 8000
Listening for requests at 0.0.0.0:8000

=== 18:00:00 ===
POST / HTTP/1.1
Host: localhost:8000
User-Agent: axios/0.21.1
Content-Length: 29
Accept: application/json, text/plain, */*
Connection: close
Content-Type: application/json;charset=utf-8

{"id":1,"event_type":"Hello"}

=== 18:00:01 ===
POST / HTTP/1.1
Host: localhost:8000
User-Agent: axios/0.21.1
Content-Length: 29
Accept: application/json, text/plain, */*
Connection: close
Content-Type: application/json;charset=utf-8

{"id":2,"event_type":"World"}

誰かを助けてくれることを願っています.