理解 Javascript 和 node.js 中的回调 [英] Understanding callbacks in Javascript and node.js

查看:17
本文介绍了理解 Javascript 和 node.js 中的回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 PHP(CodeIgniter 和 WordPress)的长期开发者,最近才想学习一些其他语言.我已经开始学习 Ruby(on Rails 和 Sinatra)、Python(带 Flask 框架)和使用 node.js 的 Javascript.

I'm a long time PHP (CodeIgniter & WordPress) developer that only recently wanted to learn a few other languages. I've set out to learn Ruby (on Rails, and Sinatra), Python (w/ Flask framework) and Javascript with node.js.

我决定使用这些语言中的每一种来创建我能想到的最基本的应用程序,即 URL 扩展器.除了 node.js 和 Javascript,我已经设法用每种语言创建了一个工作版本.

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

我有点知道我的问题,我知道它与回调有关.我知道我做得不对.我了解了回调的基本概念,但我就是不知道如何解决我造成的这个混乱.

I kinda know my problem, I know it is related to callbacks. I know I'm not doing it right. I get the basic idea of callbacks, but I just cannot figure out how to fix this mess I have created.

这是我的完整代码:

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

服务器启动,当有请求时,它调用expand函数,在终端返回扩展后的URL.我正在尝试让它在浏览器中打印.

The server starts, and when a request is made, it calls the expand function which returns the expanded URL in the terminal. I'm trying to get it to print in the browser.

感谢任何帮助.提前致谢.

Any help is appreciated. Thanks in advance.

推荐答案

你犯了一些缺陷.

您应该重写 expand 以传入 url 并传入回调.任何执行异步操作的函数通常在 node.js 中具有签名 (data, callback) .这基本上允许你说我想让这个函数做一些事情,然后告诉我什么时候完成.

You should rewrite expand to pass the url in and pass a callback in. Any function that does anything asynchronous generally has the signature (data, callback) in node. This basically allows you to say I want this function to do something then tell me when it's 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);    
    }
}

这里的回调应该有 (err, data) 的签名,节点中几乎所有的回调都有.我们还添加了必须的错误处理.

Here the callback is expected to have the signature of (err, data) which almost all callbacks in node have. We've also added error handling which is a must.

我们现在更改 onRequest 以实际正确调用 expand

We now change onRequest to actually call expand properly

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

这里我们添加了错误处理逻辑,并解压了实际的 url 以从查询字符串中展开.

Here we have added error handling logic and also unpacked the actual url to expand from the query string.

通常 doSomething> 的模式在 node.js 中效果很好.

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

let result = doSomething 完全一样mayThrow err 是您在普通阻塞语言中期望的,除非它是异步的.

It's the exact same as let result = doSomething<data> mayThrow err that you expect in your normal blocking languages except it's asynchronous.

请注意,将 ServerResponse 对象传递给函数的替代选项是不受欢迎的,这样做会在扩展函数和服务器响应之间创建不必要的硬耦合.

Note that the alternative option of passing the ServerResponse object into the function is frowned upon, by doing so your creating unnecessary hard coupling between the expand function and the server response.

expand函数应该只展开一个url并返回展开后的url,它本身没有做IO的业务.

The expand function should only expand an url and return the expanded url, it has no business doing IO itself.

完整代码

这篇关于理解 Javascript 和 node.js 中的回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆