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