以下名为 runQuery 的 javascript 函数是 @Brad 给我的
它使用 fetch API 从 NodeJS 服务器获取数据。
效果很好!它从服务器返回数据。
以下代码运行时没有错误,但在使用最终的 console.log 命令查看时返回未排序的数据。
这是因为由于 runQuery 是异步的,因此排序函数正在处理空数组,因此它不执行任何操作。然后,在 runQuery 有机会完成工作后,console.log 显示填充的数组(未排序)。
附注该项目的所有工作代码都在
// Run the query defined in the textarea on the form.
runQuery(document.querySelector(".queryExpressionTextArea").value).then(function()
{
// Sort the recordsArray which was populated after running the query.
recordsArray.sort(function(a, b)
{
//Sort by email
if (a.email > b.email) return -1;
if (a.email < b.email) return 1;
if (a.email === b.email) return 0;
})
console.log(recordsArray);
});
async function runQuery(queryExpression)
{
// Define a client function that calls for data from the server.
const fetchPromise = fetch('api/aUsers' + queryExpression)
.then
(
(res) =>
{
// Verify that we have some sort of 2xx response that we can use
if (!res.ok)
{
// throw res;
console.log("Error trying to load the list of users: ");
}
// If no content, immediately resolve, don't try to parse JSON
if (res.status === 204)
{
return;
}
// Initialize variable to hold chunks of data as they come across.
let textBuffer = '';
// Process the stream.
return res.body
// Decode as UTF-8 Text
.pipeThrough
(
new TextDecoderStream()
)
// Split on lines
.pipeThrough
(
new TransformStream
(
{
transform(chunk, controller)
{
textBuffer += chunk;
// Split the string of records on the new line character and store the result in an array named lines.
const lines = textBuffer.split('\n');
// Cycle through all elements in the array except for the last one which is only holding a new line character.
for (const line of lines.slice(0, -1))
{
// Put the element from the array into the controller que.
controller.enqueue(line);
} // End of: for (const line ...)
// Put the last element from the array (the new line character) into the textBuffer but don't put it in the que.
textBuffer = lines.slice(-1)[0];
}, // End of: Transform(chunk, controller){do stuff}
flush(controller)
{
if (textBuffer)
{
controller.enqueue(textBuffer);
} // End of: if (textBuffer)
} // End of: flush(controller){do stuff}
} // End of: parameters for new TransformStream
) // End of: call to constructor new TransformStream
) // End of: parameters for pipeThrough - Split on lines
// Parse JSON objects
.pipeThrough
(
new TransformStream
(
{
transform(line, controller)
{
if (line)
{
controller.enqueue
(
JSON.parse(line)
); //End of: call to controller.enqueue function
} // End of: if (line)
} // End of: transform function
} // End of: parameter object for new TransformStream
) // End of: new TransformStream parameters
); // End of: parameters for .pipeThrough - Parse JSON objects
} // End of: .then callback function instruction for fetch
); // End of: .then callback parameters for fetch
// Call to function which asks server for data.
const res = await fetchPromise;
const reader = res.getReader();
function read()
{
reader.read()
.then
(
({value, done}) =>
{
if (value)
{
// Your record object (value) will be here.
// This is a key/value pair for each field in the record.
//*************************
// This array has global scope.
// I want to sort this array only after all the data has been returned.
// In other words - only after this asynchronous function has finished running.
recordsArray.push(value);
//*************************
// If I were to uncomment the sort function in this position then
// we will see the records sorted correctly in the final console.log.
// I don't want to do this because then the sort function will
// run every time a record is returned rather than one time after
// all the records have been retrieved.
//recordsArray.sort(function(a, b)
//{
// //Sort by email
// if (a.email > b.email) return -1;
// if (a.email < b.email) return 1;
// if (a.email === b.email) return 0;
//})
} // End of: if(value){do stuff}
if (done) {return;}
read();
} // End of: the actual anonymous callback arrow function.
); // End of: .then callback after read function completes.
} // End of: function definition: function read(){do stuff}
// Call the "read" function defined above when the submit query button is pressed.
read()
}; // End of: async function runQuery(queryExpression)
async function runQuery(queryExpression) {
const res = await fetch('api/aUsers' + queryExpression);
// Verify that we have some sort of 2xx response that we can use
if (!res.ok) {
console.log("Error trying to load the list of users: ");
throw res;
}
// If no content, immediately resolve, don't try to parse JSON
if (res.status === 204) {
return [];
}
const content = await res.text();
const lines = content.split("\n");
return lines.map(line => JSON.parse(line));
}
然后
const recordsArray = await runQuery(document.querySelector(".queryExpressionTextArea").value);
recordsArray.sort(function(a, b) {
return (a.email < b.email) - (a.email > b.email);
})
console.log(recordsArray);
此处找到的网页的帮助下解决了这个问题
然而,我选择 @Bergi 的答案作为解决方案,因为代码更短、更优雅,而且因为 Bergi 提出了等待获取完成会削弱使用流的好处的观点。
这个链接的函数下找到:
app.loadUsersListPage = async function(){做一些事情}
该操作从 loadUsersListPage 的一个名为 onClickEventBehaviorOfSubmitQueryButton 的子函数开始。
为了使这一切正常工作,对该功能进行了以下更改。请注意它与原始问题中的代码有何不同。
// Run the query defined in the textarea on the form.
let recordsArray = await runQuery(document.querySelector(".queryExpressionTextArea").value)
// Sort the recordsArray which was populated after running the query.
recordsArray.sort(function(a, b)
{
//Sort by email
if (a.email > b.email) return -1;
if (a.email < b.email) return 1;
if (a.email === b.email) return 0;
})
console.log(recordsArray);
上面的代码调用下面的代码,该代码也被更改以使其全部正常工作。
请注意整个函数中关键字 async 和 wait 的使用。
另请注意函数底部的代码已更改,以便在从服务器接收到所有数据之前不会将数据返回到排序函数。
async function runQuery(queryExpression)
{
// Define a client function that calls for data from the server.
// !!!
const fetchPromise = await fetch('api/aUsers' + queryExpression)
.then
(
(res) =>
{
// Verify that we have some sort of 2xx response that we can use
if (!res.ok)
{
// throw res;
// Show the createCheck CTA
document.getElementById("createNewRecordCTA").style.display = 'block';
document.getElementById("createNewRecordCTA2").style.display = 'block';
document.getElementById("createNewRecordCTA3").style.display = 'block';
console.log("Error trying to load the list of users: ");
}
// If no content, immediately resolve, don't try to parse JSON
if (res.status === 204)
{
return;
}
// Initialize variable to hold chunks of data as they come across.
let textBuffer = '';
// Process the stream.
return res.body
// Decode as UTF-8 Text
.pipeThrough
(
new TextDecoderStream()
)
// Split on lines
.pipeThrough
(
new TransformStream
(
{
transform(chunk, controller)
{
textBuffer += chunk;
// Split the string of records on the new line character and store the result in an array named lines.
const lines = textBuffer.split('\n');
// Cycle through all elements in the array except for the last one which is only holding a new line character.
for (const line of lines.slice(0, -1))
{
// Put the element from the array into the controller que.
controller.enqueue(line);
} // End of: for (const line ...)
// Put the last element from the array (the new line character) into the textBuffer but don't put it in the que.
textBuffer = lines.slice(-1)[0];
}, // End of: Transform(chunk, controller){do stuff}
flush(controller)
{
if (textBuffer)
{
controller.enqueue(textBuffer);
} // End of: if (textBuffer)
} // End of: flush(controller){do stuff}
} // End of: parameters for new TransformStream
) // End of: call to constructor new TransformStream
) // End of: parameters for pipeThrough - Split on lines
// Parse JSON objects
.pipeThrough
(
new TransformStream
(
{
transform(line, controller)
{
if (line)
{
controller.enqueue
(
JSON.parse(line)
); //End of: call to controller.enqueue function
} // End of: if (line)
} // End of: transform function
} // End of: parameter object for new TransformStream
) // End of: new TransformStream parameters
); // End of: parameters for .pipeThrough - Parse JSON objects
} // End of: .then callback function instruction for fetch
); // End of: .then callback parameters for fetch
// Below the code has been changed so that data is not returned until the entire fetch has been completed.
// Call to function which asks server for data.
const res = await fetchPromise;
const reader = res.getReader();
let result = await reader.read();
let fetchedArray = [];
while (!result.done) {
const value = result.value;
fetchedArray.push(value);
// get the next result
result = await reader.read();
}
return fetchedArray;
}; // End of: async function runQuery(queryExpression)
感谢大家帮助我解决这个问题。
显然,如果我希望实现我的目标,我需要研究 async/await 和 Promise。
enter code here
searchInput.addEventListener("input", function (e) {
filteredArr = copyArr;
filteredArr = filteredArr.filter((el) =>
el.title.toLocaleLowerCase().includes(e.target.value.toLocaleLowerCase())
);
getAllCards();
});
sortBtn.addEventListener("change", function (e) {
if (e.target.value === "za") {
filteredArr.sort((a, b) => a.price - b.price);
} else if (e.target.value === "az") {
filteredArr.sort((a, b) => b.price - a.price);
} else {
filteredArr = []
}
getAllCards();
});
let infoClone = [...info];
if(e.target.value == 'a-z'){
let sortAz = infoClone.sort((a,b)=>a.first_name.localeCompare(b.first_name));
writeNames(sortAz)
}else if(e.target.value == 'z-a'){
let sortZa = infoClone.sort((a,b)=> b.first_name.localeCompare(a.first_name));
writeNames(sortZa)
}else{
writeNames(info)
}
})