[英]Node.js - Javascript - Returning Async Variables
I am working on a discord bot that will take random values from a Google Spreadsheet I have created.我正在开发一个不和谐机器人,它将从我创建的 Google 电子表格中获取随机值。 I have written my accessSpreadsheet.js file so that it will fetch data from Google Sheets, this is done asynchronously.
我已经编写了我的 accessSpreadsheet.js 文件,以便它可以从 Google Sheets 中获取数据,这是异步完成的。 I can console.log out the data I want from the async functions but I cannot set other variables by returning the asynchronous data, it instead returns undefined.
我可以通过 console.log 从异步函数中注销我想要的数据,但是我不能通过返回异步数据来设置其他变量,而是返回 undefined。
To start I have a discord.js that accepts input from Discord and calls my giRandom function and replys to the user with the output.首先,我有一个 discord.js,它接受来自 Discord 的输入并调用我的 giRandom 函数并用输出回复用户。
if(input === "!0"){
var output = giRandom("1"); //this seed just guarantees a "true" outcome for testing the boolSet function (located below)
msg.reply(output); //Output's the returned giRandom data (currently replies but output is null)
}
Discord is calling the following function from giRandom.js Everything seems to work here until we reach var output = builder(seed_data);
Discord 正在从 giRandom.js 调用以下函数 在我们到达
var output = builder(seed_data);
之前,一切似乎都在这里工作var output = builder(seed_data);
//Returns a random number when fed a seed
function giRandom(seed) {
//Seperate random seed js file. Working properly.
var seedrandom = require('seedrandom');
var rng = seedrandom(seed);
var seed_Data = seedData(rng()); //Function below
var output = builder(seed_Data); //Function below //Returning Undefined
return output; //Returns output to discord.js (msg.reply(output))
}
exports.giRandom = giRandom; //located at end of file, not in a function
My giRandom function is calling seedData and builder functions (both located within giRandom.js)我的 giRandom 函数正在调用 seedData 和 builder 函数(都位于 giRandom.js 中)
seedData function种子数据函数
//Takes the seed generated by seedrandom (something like 0.1189181568115987) and seperates each digit into an array, ignoring NaN digits (in this case the decimal point)
function seedData(data){
var counter = 0; //used to determine amount of NaN digits
//Counts each NaN in inputArray
var inputArray = Array.from(data.toString()).map(Number);
for (var i = 0; i < inputArray.length; i++) {
if (inputArray[i] >= 0) { //Checks for NaN
if (debug) {
console.log("inputArray[" + i + "] | " + inputArray[i]);
}
} else { //If NaN counter++
counter++;
}
}
var outputArray = new Array(counter); //Creates output array with correct size for all NaN values
counter = 0; //Reset counter to 0
//Creates outputArray containing all seed digits
for (var i = 0; i < inputArray.length; i++) {
if (inputArray[i] >= 0) {
outputArray[counter] = inputArray[i];
counter++;
}
}
//Debug function to view output values
for (var i = 0; i < outputArray.length; i++) {
if (debug) {
console.log("outputArray[" + i + "] | " + outputArray[i]);
}
}
return outputArray; //returns outputArray to seed_Data in giRandom function
}
builder function建造者功能
//Takes seed_Data from giRandom function and determines the value's output
function builder(data) {
//Booleans, determine if each category returns a value based on boolSet() (function below)
var raceBool;
//data[0] is always a value of 0. 16 Total Usable values 1-17
raceBool = boolSet(data[1]);
if (raceBool == true) {
var raceData = sheetToArray(1);
console.log("raceData | " + raceData);
return raceData; //Returning undefined
}
}
My builder function is calling boolSet and sheetToArray functions (both located within giRandom.js)我的构建器函数正在调用 boolSet 和 sheetToArray 函数(均位于 giRandom.js 中)
boolSet function boolSet 函数
//Each seed digit can be 0-9. If the digit passed (boolData) matches the value for valueTrue, valueFalse, or valuePick the output will be set accordingly. (Currently will always output True)
function boolSet(boolData) {
var valueTrue = [0, 1, 2, 3];
var valueFalse = [4, 5, 6, 7];
var valuePick = [8, 9];
//Loop through valueTrue and compare with boolData
for (var i = 0; i <= valueTrue.length; i++) {
if (boolData == valueTrue[i]) {
if (debug) {
console.log("boolData | " + boolData + " | true");
}
return true;
}
}
//Loop through valueFalse and compare with boolData
for (var i = 0; i <= valueFalse.length; i++) {
if (boolData == valueFalse[i]) {
if (debug) {
console.log("boolData | " + boolData + " | false");
}
return false;
}
}
//If !true && !false, must be "pick". This value will allow the end user to choose their data (in this case race)
return "pick";
}
sheetToArray function sheetToArray 函数
//takes an int for sheetNum that determines which sheet in the project to load
function sheetToArray(sheetNum){
var sheetArray = []; //Array that holds all rows of a particular worksheet, used to build spreadsheetArray
var cellArray = []; //Array that holds all cells in a particular row of the worksheet used to build sheetArray
var rowArrayCount = 1; //Counter to determine rows in cells forEach loop
/*I believe this is where my problem probably lies*/
//Calling async function accessSpreadsheet from spreadsheet.js
accessSpreadsheet(sheetNum).then(function (arr) {
var cells = arr;
//loop through all cells in current sheet
cells.forEach(cell => {
if (cell.row > rowArrayCount) { //True determines that data is now on the next row of current sheet
rowArrayCount++;
sheetArray.push(cellArray); //push last row to sheetArray
cellArray = []; //reset cellArray for new row
}
cellArray.push(cell._value); //push final row to cellArray
})//Exit forEach
sheetArray.push(cellArray); //push all rows to sheetArray
var raceLength = sheetArray.length; //Returns value correctly
console.log("raceLength | " + raceLength); //Returns value correctly
console.log("sheetArray | " + sheetArray); //Returns value correctly
return sheetArray; //Returns undefined
})
}
To access Google Sheets I have a seperate js file.要访问 Google 表格,我有一个单独的 js 文件。 This is where the asynchronous function accessSpreadsheet() is
这是异步函数 accessSpreadsheet() 所在的位置
accessSpreadsheet.js accessSpreadsheet.js
//Google Sheet Access Const
const GoogleSpreadsheet = require('google-spreadsheet');
const { promisify } = require('util');
const creds = require('./client_secret.json');
const doc = new GoogleSpreadsheet('**************'); //Google sheet we have access to (removed for security)
module.exports = accessSpreadsheet = async (sheetNum) => {
await promisify(doc.useServiceAccountAuth)(creds);
const info = await promisify(doc.getInfo)();
const sheet = info.worksheets[sheetNum];
//Async get sheet's cells without an offset
const cells = await promisify(sheet.getCells)({
offset: 0
})
return cells;
}
Basics of javascript promises : javascript 承诺的基础知识:
accessSpreadsheet definition is something like accessSpreadsheet 定义类似于
async accessSpreadsheet(args...){
//Do stuff
return something;
}
or like :或喜欢:
accessSpreadsheet(args...){
return Promise(function (resolve,reject){
// Do stuff
resolve(return_value)
})
}
Because of javascript being event-driven you cannot make it wait for i/o as it is detrimental to the user experience.由于 javascript 是事件驱动的,您不能让它等待 i/o,因为它不利于用户体验。
So you can solve your problem either by making all of your code async and using the await keyword to wait for accessSpreadsheet.因此,您可以通过使所有代码异步并使用 await 关键字等待 accessSpreadsheet 来解决您的问题。
Like this :像这样 :
await accessSpreadsheet()
which will wait for accessSpreadsheet to return before going to the next line.这将在进入下一行之前等待 accessSpreadsheet 返回。
This is a basic race condition scenario with promises.这是一个带有 promise 的基本竞争条件场景。
You should remove vain promisification :您应该删除无效的承诺:
const info = await promisify(doc.getInfo)();
can be written :可以写成:
const info = doc.getInfo();
and log the errors :并记录错误:
accessSpreadsheet(sheetNum).then(function (arr) {
// somecode
}).catch(console.error)
This will probably make your life easier这可能会让你的生活更轻松
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.