在 Node.js 中同步调用 api

Synchronous api calls in Node.js

我有一个每 10 秒运行一次的 cronjob。它为单个客户端请求机器并根据响应进行计算,然后必须在 for 循环中使用这些计算更新或创建文档。但是,代码中“***”之后的 api 调用不会发生,直到执行循环并且发送到 api 调用的数据是最后一台错误的机器的数据。我想通过这种方式或其他可能的方式解决这个问题。我的代码如下所示:

// index.js
const cron = require("node-cron");
const express = require("express");
const fs = require("fs");
const request = require("request");

app = express();

var clientId = 'ABCD';
var apiUrl = 'http://example.com:3001/';
var getMachines                     = apiUrl + 'getMachines/',
    updateMachine                   = apiUrl + 'updateMachine/',
    getControlRoomStatus            = apiUrl + 'getControlRoomStatus/',
    registerControlRoomStatus       = apiUrl + 'registerControlRoomStatus/',
    updateControlRoomStatus         = apiUrl + 'updateControlRoomStatus/';

cron.schedule("*/10 * * * * *", function() {
    APICall(getMachines, { 'clientId' : clientId }, 'POST', function(err, machines) {
        if (err) {
            console.log(err);
        } else {
            console.log('--------------------------------------------------------------------------------------------------');
            var allMachines = machines;
            var currentDateTime = IST();
            for (var i = 0; i < 2; i++) {
                var lastCycleTime = new Date(allMachines[i]['lastCycleTime']);
                var lastHeartbeat = new Date(allMachines[i]['lastHeartbeat']);
                var machineData;
                var controlRoomData;
                var machineId = {
                    'machineId' : allMachines[i]['machineId']
                };
                console.log(machineId);
                if (allMachines[i]['downtimeStatus'] == '0') {
                    if ((currentDateTime - lastCycleTime)>300000) {
                        if ((currentDateTime - lastHeartbeat)>300000) {
                            console.log(allMachines[i]['machineId'] ,' No Internet');
                            controlRoomData = {
                                'clientId': clientId,
                                'lastTimeStamp': allMachines[i]['lastCycleTime'], 
                                'status': 'Inactive',
                                'type': 'No Internet/Power'
                            };
                        } else {
                            console.log(allMachines[i]['machineId'] ,' No button pressed');
                            controlRoomData = {
                                'clientId': clientId,
                                'lastTimeStamp': allMachines[i]['lastCycleTime'], 
                                'status': 'Inactive',
                                'type': 'No Button Pressed'
                            };
                        }
                        machineData = {
                            'status' : 'Inactive'
                        };
                    } else {
                        console.log(allMachines[i]['machineId'] ,' Active');
                        machineData = {
                            'status' : 'Active'
                        };
                        controlRoomData = {
                            'clientId': clientId,
                            'lastTimeStamp': allMachines[i]['lastCycleTime'], 
                            'status': 'Active',
                            'type': 'N.A'
                        };
                    }
                } else {
                    if ((currentDateTime - lastHeartbeat)>300000) {
                        console.log(allMachines[i]['machineId'] ,' button pressed ',' No Internet');
                        controlRoomData = {
                            'clientId': clientId,
                            'lastTimeStamp': allMachines[i]['lastCycleTime'], 
                            'status': 'Inactive',
                            'type': 'No Internet/Power'
                        };
                    } else {
                        var downtimeLength = allMachines[i]['downtimeData'].length - 1;
                        console.log(allMachines[i]['machineId'] ,' button pressed ',allMachines[i]['downtimeData'][downtimeLength]['downtimeType']);
                        controlRoomData = {
                            'clientId': clientId,
                            'lastTimeStamp': allMachines[i]['lastCycleTime'], 
                            'status': 'Inactive',
                            'type': allMachines[i]['downtimeData'][downtimeLength]['downtimeType']
                        };
                    }
                    machineData = {
                        'status' : 'Inactive'
                    };
                }
                ***
                APICall(getControlRoomStatus, machineId, 'POST', function(err, controlRoom) {
                    if (err) {
                        console.log(err);
                    } else {
                        console.log(machineId,controlRoomData);
                        if (controlRoom == null ) {
                            APICall(registerControlRoomStatus, controlRoomData, 'POST', function(err, body) {
                                if (err) {
                                    console.log(err);
                                } else {
                                    // console.log(body);
                                }
                            });
                        } else {
                            var updateControlRooomUrl = (updateControlRoomStatus+''+controlRoom['_id']+'');
                            // console.log(updateControlRooomUrl);
                            APICall(updateControlRooomUrl, controlRoomData, 'PUT', function(err, body) {
                                if (err) {
                                    console.log(err);
                                } else {
                                    // console.log(body);
                                }
                            });
                        }
                    }
                });
                var updateMachineUrl = (updateMachine+''+allMachines[i]['_id']+'');
                // console.log(updateMachineUrl);
                APICall(updateMachineUrl, machineData, 'PUT', function(err, body) {
                    if (err) {
                        console.log(err);
                    } else {
                        console.log(i,machineId);
                        // console.log(body);
                    }
                });
            }
        }
    });
});

function APICall(url, requestData, method, callback) {
    request({
        url: url,
        form: requestData,
        method: method
    }, function (error, response, body) {
        if (error || response.statusCode !== 200) {
            return callback(error || {statusCode: response.statusCode});
        }
        callback(null, JSON.parse(body));  
    });
}

function IST(){
  var dateUTC = new Date();
  var dateUTC = dateUTC.getTime(); 
  var dateIST = new Date(dateUTC);

  dateIST.setHours(dateIST.getHours() + 5); 
  dateIST.setMinutes(dateIST.getMinutes() + 30);
  return dateIST;
}

app.listen(3128);

提前致谢。

您可以尝试以下套餐:

sync-request

您可以在 NPM 上找到它。

这是一个如何使用它的例子(来自文档):

var request = require('sync-request');
var res = request('GET', 'http://example.com');
console.log(res.getBody());

如文档中所述,不要在生产代码中使用它,因为这会严重阻塞您的服务器并且会大大降低速度(如果您 运行 您正在使用的 HTTP 服务器 express)。

如果你有异步代码并且你想在异步之后执行一些代码你也可以使用:

  • Observables(非原生需要使用包,例如RxJS
  • Promises(原生 ES6 JS)

我使用了不同的方法来做事,现在它正常工作了。我使用 'async' 并将 for 循环替换为以下内容:

var async = require('async');
...
async.map(allMachines , function(machine, callback) {
...
});
...