了解Javascript和node.js中的callback

我是一个很长时间的PHP(CodeIgniter和WordPress)开发人员,最近才想学习其他几种语言。 我开始学习Ruby(Rails和Sinatra),Python(w / Flask框架)和Javascript以及node.js。

我决定创build一个我能想到的最基本的应用程序,一个URL扩展器,使用这些语言。 我已经成功地创build了每种语言的工作版本,除了node.js和Javascript之外。

我知道我的问题,我知道它与callback有关。 我知道我做得不对 我得到了callback的基本概念,但我无法弄清楚如何解决我创build的这个混乱。

这是我的整个代码 :

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

服务器启动,当有请求时,它调用扩展function,该function返回terminal中的扩展URL。 我试图让它在浏览器中打印。

任何帮助表示赞赏。 提前致谢。

你犯了一些瑕疵。

您应该重写扩展以传入url并传入callback。任何执行asynchronous操作的函数通常在节点中都有签名(data, callback) 。 这基本上允许你说我想要这个function做一些事情,然后告诉我什么时候完成。

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

这里的callback预期会有(err, data)的签名,几乎所有的callback节点都有。 我们还添加了error handling,这是必须的。

我们现在改变onRequest来实际调用扩展

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

在这里,我们添加了error handling逻辑,还解压缩了从查询string展开的实际url。

通常, doSomething<data, callback<err, result>>在node.js中工作得很好。

这与let result = doSomething<data> mayThrow err ,除非是asynchronous的,否则在正常的阻塞语言中会let result = doSomething<data> mayThrow err

请注意,将ServerResponse对象传递给函数的另一种select是不被赞成的,这样做会在扩展函数和服务器响应之间创build不必要的硬连接。

扩展函数只能扩展一个url并返回展开的url,它本身没有业务做IO。

完整的代码

callback只是一个单词来描述一个函数,我们传递给其他代码来调用其他代码。

在你的例子中, onRequest是一个callback函数,它被传递给createServer以便在收到请求时被调用。

我认为你遇到的问题是你期望expand()可以访问onRequest函数可以访问的所有相同的variables/参数。 事实并非如此。

您需要将response对象传递给expand() 。 由于expand调用为http.get调用创build了一个新的callbacklongURL ,因此它将有权访问您传入的response对象。

 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."); } 

您不是将响应作为参数发送给扩展函数,而是在expand()函数可以写入任何内容之前调用response.end(),这里是更正后的版本:

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