Understanding callbacks in Javascript and node.js

I am a longtime PHP developer (CodeIgniter and WordPress) who just recently wanted to learn several other languages. I started learning Ruby (on Rails and Sinatra), Python (w / Flask framework) and Javascript with node.js.

I decided to create the most basic application that I can think of, a URL extender, using each of these languages. I managed to create a working version in every language except node.js and Javascript.

I know my problem, I know that it is related to callbacks. I know that I am not doing it right. I get the basic idea of ​​callbacks, but I just can't figure out how to fix this mess that I created.

This is my whole code :

var http = require('http'); var url = require('url'); function expand() { var short = url.parse('http://t.co/wbDrgquZ'); var options = { host: short.hostname, port: 80, path: short.pathname }; function longURL(response) { console.log(response.headers.location); } http.get(options, longURL); } function start() { function onRequest(request, response) { console.log("Request received."); response.writeHead(200, { "Content-Type": "text/plain" }); response.write("Hello World"); expand(); response.end(); } http.createServer(onRequest).listen(8888); console.log("Server has started."); } start(); 

The server starts up, and when the request is executed, it calls the expand function, which returns the extended URL in the terminal. I am trying to print it in a browser.

Any help is appreciated. Thanks in advance.

+2
source share
3 answers

You made a few flaws.

You must rewrite the extension to pass the URL and pass the callback. Any function that does something asynchronous usually has a signature (data, callback) in node. This basically lets you say that I want this function to do something, and then let me know when it will be done.

 function expand(urlToParse, callback) { // note we pass in the url this time var short = url.parse(urlToParse); var options = { host: short.hostname, port: 80, path: short.pathname }; // note we store the clientRequest object temporarily var clientRequest = http.get(options, extractRealURL); // Always attach the error handler and forward any errors clientRequest.on("error", forwardError); function extractRealURL(res) { callback(null, res.headers.location); } function forwardError(error) { callback(err); } } 

Here it is expected that the callback will have a signature (err, data) , which has almost all the callbacks in the node. We also added error handling, which is mandatory.

Now we will change onRequest to actually expose normally

 function onRequest(request, response) { // parse the incoming url. true flag unpacks the query string var parsedUrl = url.parse(request.url, true), // extract the querystring url. // http://localhost:8888/?url=http://t.co/wbDrgquZ urlToExpand = parsedUrl.query.url; // call expand with the url and a callback expand(urlToExpand, writeResponse); function writeResponse(error, newUrl) { // handle the error case properly if (error) { response.writeHead(500, { 'Content-Type': 'text/plain'}); // early return to avoid an else block return response.end(error.message); } response.writeHead(200, { 'Content-Type': 'text/plain'}); // write the new url to the response response.end(newUrl); } } 

Here we added the error handling logic, and also unpacked the actual url for the extension from the query string.

Usually the doSomething<data, callback<err, result>> pattern works very well in node.js.

This is the same as let result = doSomething<data> mayThrow err , which you expect in your usual locking languages ​​except asynchronous.

Note that an alternative way to pass a ServerResponse object to a function is not satisfied, thereby creating an unnecessary hard link between the extension function and the server response.

The extension function should only expand the URL and return the expanded URL; it does not have a business doing IO itself.

Full code

+6
source

A callback is just a word that describes a function that we pass to another code to call this other code.

In your example, onRequest is a callback function that is passed to createServer to be called whenever a request is received.

I think the problem is that you expect expand() gain access to all the same variables / parameters that the onRequest function has access to. This is not true.

You need to pass the response object to expand() . Since the expand call creates a new longURL for the http.get call, it will have access to the response object that you passed.

 function expand( resp ) { // receive the original response object, and end the response when ready var short = url.parse('http://t.co/wbDrgquZ'); var options = { host: short.hostname, port: 80, path: short.pathname }; function longURL( response ) { console.log(response.headers.location); resp.end( response.headers.location ); // end the original response } http.get(options, longURL); } function start() { function onRequest(request, response) { console.log("Request received."); response.writeHead(200, { "Content-Type": "text/plain" }); response.write("Hello World"); expand( response ); // pass this response object to expand } http.createServer(onRequest).listen(8888); console.log("Server has started."); } 
+3
source

You did not send the answer as a parameter to the spread function, and you also called response.end () before the expand () function could write anything, here is the corrected version:

 var http = require('http'); var url = require('url'); function expand(res) { var short = url.parse('http://t.co/wbDrgquZ'); var options = { host: short.hostname, port: 80, path: short.pathname }; function longURL(response){ console.log(response.headers.location); res.end("<br />" + response.headers.location); } http.get(options, longURL); } function start() { function onRequest(request, response) { console.log("Request received."); response.writeHead(200, {"Content-Type": "text/html"}); response.write("Hello World"); expand(response); } http.createServer(onRequest).listen(8888); console.log("Server has started."); } start(); 
0
source

Source: https://habr.com/ru/post/1499867/


All Articles