我的脚本正在从API接收数据并自动存储在MongoDB中。 我需要创建一个至少2秒的延迟,然后再接收一个又一个数据。 问题是我的剧本第二次就停止工作了。 假设我的脚本每小时工作一次,我在14.00启用脚本-它工作,在15.00停止。 我开始研究这个问题,并指出循环中的setTimeout()
存在问题。
这是我在For Loop#js中使用settimeout(
)时发现的一篇文章
这一行是一个节点调度包,它基本上每15分钟调用一次脚本(如果有人想知道是这样的话)
const j = schedule.scheduleJob('*/15 * * * *', callIt)
我的目标:我如何改变我的代码仍然有2秒的延迟和工作循环。 是否有任何替代setTimeout()
的方法,可能我只需要将setTimeout()
放在代码中的另一个位置,或者甚至有某种类型的包我可以添加额外的。
有问题的代码区域:
var symbols = ["ZRXBTC", "ETHBTC", "ETCBTC", "KAVABTC", "AEBTC"]
];
let cnt = 0;
const callIt = () => {
fetch(`https://api.binance.com/api/v3/klines?symbol=${symbols[cnt]}&interval=30m&limit=1`)
.then(res => res.json())
.then(data => {
const btcusdtdata = data.map(d => {
return {
Open: parseFloat(d[1]),
High: parseFloat(d[2]),
Low: parseFloat(d[3]),
Close: parseFloat(d[4]),
Volume: parseFloat(d[5]),
Timespan: 30,
}
});
console.log(btcusdtdata);
saveToDatebase(btcusdtdata);
cnt++;
if (cnt < symbols.length) setTimeout(callIt, 2000)
})
.catch((err) => {
console.log(err);
})
};
全码
var requestPromise = require('request-promise');
const { MongoClient } = require('mongodb');
const schedule = require('node-schedule');
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
const fetch = require("node-fetch");
var symbols = ["ZRXBTC", "ETHBTC", "ETCBTC", "KAVABTC", "AEBTC"]
];
let cnt = 0;
const callIt = () => {
fetch(`https://api.binance.com/api/v3/klines?symbol=${symbols[cnt]}&interval=30m&limit=1`)
.then(res => res.json())
.then(data => {
const btcusdtdata = data.map(d => {
return {
Open: parseFloat(d[1]),
High: parseFloat(d[2]),
Low: parseFloat(d[3]),
Close: parseFloat(d[4]),
Volume: parseFloat(d[5]),
Timespan: 30,
}
});
console.log(btcusdtdata);
saveToDatebase(btcusdtdata);
cnt++;
if (cnt < symbols.length) setTimeout(callIt, 2000)
})
.catch((err) => {
console.log(err);
})
};
const j = schedule.scheduleJob('*/15 * * * *', callIt)
const saveToDatebase = function(BTCdata) {
const url = 'mongodb+srv://username:password@cluster0-1kunr.mongodb.net/<dbname>?retryWrites=true&w=majority';
var today = new Date();
var date = today.getFullYear() + '-' + (today.getMonth() + 1) + '-' + today.getDate();
var time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
var dateTime = date + ' ' + time;
MongoClient.connect(url, { useNewUrlParser: true, useUnifiedTopology: true }, (err, db) => {
if (err) throw err;
const dbo = db.db('CryptoCurrencies');
const myobj = { Name: symbols[cnt - 1], Array: BTCdata, Date: dateTime };
dbo.collection(`${symbols[cnt - 1]}`).insertOne(myobj, (error, res) => {
if (error) throw error;
console.log('1 document inserted');
db.close();
});
});
};
编辑1:为了更正确,我将更精确地指定任务。 我的node-schedule包假设每15分钟调用一次脚本,而我希望每2秒调用一次数组中的属性。 我需要调用属性从数组每2秒,否则我将收到IP禁令从Binance API调用API到much/fast。
编辑2好的。 setInterval()
不是我的解决方案。 因为我需要每15分钟调用一次脚本,所以它应该经过array,当它从array调用所有属性时,它应该停止。 在setInterval()
中,调用数组中的所有属性后,再次启动它,不幸的是,这不是我需要的。
编辑3:我测试了下面答案中的几个选项,所有这些选项都让我发现了相同的问题,即脚本无法第二次启动,或者脚本立即开始工作,或者即使数组属性结束后仍然重复。 还是谢谢你的回答,但我的问题还是一个。
目前我正在尝试使用async/await方法。 但我收到一个错误,Await只在异步函数中有效
这是一个来自@YoavMatchulsky的完整代码解决方案。 脚本开始工作,但我没有收到任何数据什么的。 就像工作一样--但什么都没发生。 没有差错,什么都没有。
var requestPromise = require('request-promise');
const { MongoClient } = require('mongodb');
const schedule = require('node-schedule');
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
const fetch = require("node-fetch");
const symbols = ["ZRXBTC", "ETHBTC", "ETCBTC", "KAVABTC", "AEBTC"];
const sleep = async(timeout) => {
return new Promise(resolve => {
setTimeout(resolve, timeout);
});
}
const callIt = async(symbol) => {
return fetch(`https://api.binance.com/api/v3/klines?symbol=${symbol}&interval=30m&limit=1`)
.then(res => res.json())
.then(data => async() => {
const btcusdtdata = data.map(d => {
return {
Open: parseFloat(d[1]),
High: parseFloat(d[2]),
Low: parseFloat(d[3]),
Close: parseFloat(d[4]),
Volume: parseFloat(d[5]),
Timespan: 30,
}
});
console.log(btcusdtdata);
await saveToDatebase(btcusdtdata);
})
.catch((err) => {
console.log(err);
})
};
const saveToDatebase = async function(BTCdata) {
return new Promise((resolve, reject) => {
const url = 'mongodb+srv://username:password@cluster0-1kunr.mongodb.net/<dbname>?retryWrites=true&w=majority';
var today = new Date();
var date = today.getFullYear() + '-' + (today.getMonth() + 1) + '-' + today.getDate();
var time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
var dateTime = date + ' ' + time;
MongoClient.connect(url, { useNewUrlParser: true, useUnifiedTopology: true }, (err, db) => {
if (err) {
return reject(err);
}
const dbo = db.db('CryptoCurrencies');
const myobj = { Name: symbols[cnt - 1], Array: BTCdata, Date: dateTime };
dbo.collection(`${symbols[cnt - 1]}`).insertOne(myobj, (error, res) => {
if (error) {
return reject(error);
}
console.log('1 document inserted');
db.close();
resolve();
});
});
});
};
const run = async() => {
let cnt = 0;
while (cnt < symbols.length) {
await callIt(symbols[cnt]);
await sleep(2000);
cnt++;
}
}
const j = schedule.scheduleJob('*/2 * * * *', run);
请尝试使用setInterval。
setInterval(callIt,2000年);
但将其置于callIt函数之外。
https://developer.mozilla.org/en-us/docs/web/api/windoworworkerglobalscope/setinterval
下面是一个async/await
解决方案:
const callIt = async () => {
try {
let res = await fetch(
`https://api.binance.com/api/v3/klines?symbol=${symbols[cnt]}&interval=30m&limit=1`
);
let data = await res.json();
const btcusdtdata = data.map(d => {
return {
Open: parseFloat(d[1]),
High: parseFloat(d[2]),
Low: parseFloat(d[3]),
Close: parseFloat(d[4]),
Volume: parseFloat(d[5]),
Timespan: 30
};
});
console.log(btcusdtdata);
saveToDatebase(btcusdtdata);
cnt++;
if (cnt < symbols.length) {
await sleep(2000);
callIt();
}
} catch (err) {
console.log(err);
}
};
function sleep(ms) {
return new Promise(res => setTimeout(res, ms));
}
有什么替代setTimeout()的方法吗
假设您只想每2秒执行一些代码,而不是使用循环,使用具有2秒延迟的settInterval
。
setInterval(() => {
// code here will run every 2 seconds
}, 2000);
我需要每15分钟调用一次脚本,它应该经过数组,当它从数组调用所有属性时,它应该停止
下面是一个代码示例,它每15秒调用run
函数,并以2秒的延迟访问每个数组元素。
第一个setInterval
函数每15秒调用一次run
函数,第二个setInterval
函数在run
函数中以2秒的延迟访问每个数组元素。 访问完所有数组元素后,取消此间隔。
null
const symbols = ["ZRXBTC", "ETHBTC", "ETCBTC", "KAVABTC", "AEBTC"];
console.log('wait 15 seconds before run function is called');
setInterval(() => {
run();
}, 15000);
function run() {
console.log('running code after 15 seconds interval');
let index = 0;
const id = setInterval(() => {
console.log(symbols[index]);
index++;
if (index >= symbols.length) {
console.log('all array indexes accessed');
clearInterval(id);
}
}, 2000);
}