如何在异步方法外部获取body值?求Node.js异步编程最佳实践
Hey there! Let's break down your problem step by step and demystify those callback, Promise, and async/await concepts you're confused about.
Right now, when you run console.log(x), you're getting undefined—and that's totally expected! Your test function is asynchronous, meaning it doesn't immediately return the result of the Trello API call. The API request runs in the background, and the callback you passed to test only executes once the response comes back. By the time console.log(x) runs, that callback hasn't fired yet, so x is just the (non-existent) return value of test.
Here's how you can actually use the body value for other methods:
var request = require('request'); var boardsCall = { method: 'GET', url: 'https://api.trello.com/1/organizations/xxxxxxxxxx/boards?filter=open&fields=id,name', qs: { key: 'xxxxxxxxxxxxxxxx', token: 'xxxxxxxxxxxxxxxxxxxxxxxxx' } }; function test(options, callback) { request(options, function(error, response, body) { if (error) { return callback(error); } // Add error handling for JSON parsing just in case try { const parsedBody = JSON.parse(body); callback(null, parsedBody); } catch (parseError) { callback(parseError); } }) } // To use the body outside, you have to work within the async flow test(boardsCall, function(err, body) { if (err) { console.log('Error fetching boards:', err); return; } // Now you can use `body` here for your follow-up methods console.log('Fetched boards:', body); doSomethingWithBoards(body); // Call your next function with the data }); // Example of a follow-up method function doSomethingWithBoards(boards) { console.log(`Processing ${boards.length} open boards`); // Add your logic here—like filtering boards, updating something, etc. }
Let's break down each concept with simple terms and examples:
Callbacks
Callbacks are just functions you pass to another function to run after an async task finishes. They work, but they get messy fast if you have multiple async operations nested (this is called "callback hell"—think 5+ levels of indentation). Your original code uses callbacks, which is why you can't just grab the result synchronously.
Promises
Promises are objects that represent the eventual success or failure of an async operation. They let you chain operations instead of nesting them, making code cleaner. Let's rewrite your test function to return a Promise:
var request = require('request'); function test(options) { return new Promise((resolve, reject) => { request(options, function(error, response, body) { if (error) { return reject(error); // Reject the promise if there's an error } try { const parsedBody = JSON.parse(body); resolve(parsedBody); // Resolve with the parsed data if successful } catch (parseError) { reject(parseError); } }); }); } // Using the Promise version test(boardsCall) .then(body => { console.log('Fetched boards:', body); doSomethingWithBoards(body); }) .catch(err => { console.log('Error:', err); });
Promises let you chain .then() calls for sequential async tasks, or use Promise.all() to run multiple tasks in parallel.
Async/Await
This is just syntactic sugar for Promises—it makes async code look and behave like synchronous code, which is way easier to read and debug. You mark a function with async, then use await to pause the function until the Promise resolves.
Here's the async/await version of your code:
var request = require('request'); function test(options) { return new Promise((resolve, reject) => { request(options, function(error, response, body) { if (error) { return reject(error); } try { const parsedBody = JSON.parse(body); resolve(parsedBody); } catch (parseError) { reject(parseError); } }); }); } // Wrap async logic in an async function async function fetchAndProcessBoards() { try { const body = await test(boardsCall); // Wait for the Promise to resolve console.log('Fetched boards:', body); doSomethingWithBoards(body); return body; // This returns a Promise with the body value } catch (err) { console.log('Error:', err); throw err; // Let external code handle the error if needed } } // Call the async function fetchAndProcessBoards() .then(body => { // You can still use .then() if you need the value elsewhere console.log('Got boards from fetchAndProcessBoards:', body); }) .catch(err => { // Handle any errors that bubbled up }); // Or use await in another async function async function main() { try { const boards = await fetchAndProcessBoards(); // Do more stuff with boards here, synchronously-looking code! console.log('Main function using boards:', boards); } catch (err) { console.log('Main error:', err); } } main();
Here are the key rules to follow for clean, maintainable async code:
- Always use Async/Await over raw callbacks or Promises: It's the most readable and easiest to debug.
- Never ignore errors: Use
try/catchfor async/await,.catch()for Promises, and always check theerrparameter in callbacks. Unhandled errors can crash your app! - Avoid callback hell: If you're stuck with callbacks, split logic into separate functions instead of nesting them. Or convert callbacks to Promises (like we did with
test). - Use
Promise.all()for parallel tasks: If you need to fetch multiple unrelated things at once,Promise.all([task1(), task2()])runs them in parallel instead of waiting for each one to finish sequentially. - Ditch
requestfor modern HTTP clients: Therequestlibrary is deprecated. Useaxiosornode-fetchinstead—they natively support Promises, so you don't have to wrap them like we did withrequest. Here's a quick example with axios:const axios = require('axios'); async function fetchBoards() { try { const response = await axios.get('https://api.trello.com/1/organizations/xxxxxxxxxx/boards', { params: { filter: 'open', fields: 'id,name', key: 'xxxxxxxxxxxxxxxx', token: 'xxxxxxxxxxxxxxxxxxxxxxxxx' } }); return response.data; // Axios automatically parses JSON! } catch (err) { console.log('Error:', err.response?.data || err.message); throw err; } } - Keep async functions focused: Each async function should do one thing well. This makes your code easier to test and maintain.
内容的提问来源于stack exchange,提问作者jhonathan myers

