使用 Javascript Fetch API 对异步获取的数据进行排序

问题描述 投票:0回答:4

以下名为 runQuery 的 javascript 函数是 @Brad 给我的 它使用 fetch API 从 NodeJS 服务器获取数据。
效果很好!它从服务器返回数据。

现在我正在尝试在所有数据返回后对数据进行排序。

以下代码运行时没有错误,但在使用最终的 console.log 命令查看时返回未排序的数据。
这是因为由于 runQuery 是异步的,因此排序函数正在处理空数组,因此它不执行任何操作。然后,在 runQuery 有机会完成工作后,console.log 显示填充的数组(未排序)。

有人可以帮我理解如何在所有数据发送到浏览器后对结果进行排序吗? 谢谢,约翰

附注该项目的所有工作代码都在

here共享

// 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)
    
javascript sorting asynchronous async-await fetch-api
4个回答
1
投票
看起来您并没有在寻找任何流媒体。就写吧

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);
    

0
投票
我在

此处找到的网页的帮助下解决了这个问题 然而,我选择 @Bergi 的答案作为解决方案,因为代码更短、更优雅,而且因为 Bergi 提出了等待获取完成会削弱使用流的好处的观点。

这个问题的所有工作代码都可以在

这个链接的函数下找到: app.loadUsersListPage = async function(){做一些事情}

注意上面的关键字 async - 这是完成这项工作所必需的。

该操作从 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。


0
投票
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(); });
    

0
投票
sortBtn.addEventListener('更改',(e)=>{

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) }
})

© www.soinside.com 2019 - 2024. All rights reserved.