代码之家  ›  专栏  ›  技术社区  ›  Darrell Brogdon

CommonJS中“承诺”抽象的好处是什么?

  •  13
  • Darrell Brogdon  · 技术社区  · 16 年前

    我在看书 this article

    requestSomeData("http://example.com/foo") // returns a promise for the response
        .then(function(response){ // ‘then’ is used to provide a promise handler
            return JSON.parse(response.body); // parse the body
        }) // returns a promise for the parsed body
        .then(function(data){
            return data.price; // get the price
        }) // returns a promise for the price
        .then(function(price){ // print out the price when it is fulfilled
            print("The price is " + price);
        });
    

    在我看来,以下几行代码可以提供相同的结果:

    requestSomeData("http://example.com/foo")
        .requestHandler(function(response){
            // parse the body
            var data  = JSON.parse(response.body);
    
            // get the price
            var price = data.price;
    
            // print out the price
            print("The price is " + price);
        });
    
    4 回复  |  直到 16 年前
        1
  •  17
  •   John Feminella    16 年前

    虽然两者最终都将完成相同的事情,但区别在于第二个示例不是异步的。例如,考虑一下如果发生了什么 JSON.parse(...)

    这就是承诺带给你的:将正确答案的计算推迟到更方便的时候的强大能力。顾名思义,这个结构“承诺”会在某个时刻给出结果,只是现在不一定。你可以阅读更多关于未来和更大规模工作的承诺 here .

        2
  •  3
  •   TraversMcTravers    14 年前

    // First we need a convenience function for W3C's fiddly XMLHttpRequest.
    // It works a little differently from the promise framework.  Instead of 
    // returning a promise to which we can attach a handler later with .then(),
    // the function accepts the handler function as an argument named 'callback'.
    
    function requestSomeDataAndCall(url, callback) {
        var req = new XMLHttpRequest();
        req.onreadystatechange = resHandler;
        req.open("GET", url, false);
        req.send();
        function resHandler() {
            if (this.readyState==4 && this.status==200) {
                callback(this);
            } else {
                // todo: Handle error.
            }
        }
    }
    
    requestSomeDataAndCall("http://example.com/foo", function(res){
        setTimeout(function(){
            var data = JSON.parse(res.responseText);
            setTimeout(function(){
                var price = data.price;
                setTimeout(function(){
                    print("The price is "+price);
                },10);
            },10);
        },10);
    });
    

    正如Norbert Hartl指出的那样,JSON.parse()将挂起浏览器以查找大字符串。因此,我使用setTimeout()延迟它的执行(暂停10毫秒后)。这是Kris Kowal解决方案的一个例子。它允许当前Javascript线程完成,在回调运行之前释放浏览器以显示DOM更改并为用户滚动页面。

    我上面的替代方案看起来很难看,后面的过程需要进一步缩进。我重组了代码,以便我们可以在一个级别提供我们的流程链:

    function makeResolver(chain) {
        function climbChain(input) {
            var fn = chain.shift();      // This particular implementation
            setTimeout(function(){       // alters the chain array.
                var output = fn(input);
                if (chain.length>0) {
                    climbChain(output);
                }
            },10);
        }
        return climbChain;
    }
    
    var processChain = [
        function(response){
            return JSON.parse(response.body);
        },
        function(data){
            return data.price; // get the price
        },
        function(price){
          print("The price is " + price);
        }
    ];
    
    var climber = makeResolver(promiseChain);
    requestSomeDataAndCall("http://example.com/foo", climber);
    

        3
  •  1
  •   Esailija    12 年前

    第二个代码段容易受到拒绝服务攻击,因为example.com/foo只会返回无效的json以使服务器崩溃。即使是空响应也是无效的JSON(尽管是有效的JS)。就像 mysql_* 具有明显SQL注入漏洞的示例。

    承诺代码也可以改进很多。这些是平等的:

    requestSomeData("http://example.com/foo") // returns a promise for the response
        .then(function(response){ // ‘then’ is used to provide a promise handler
            // parse the body
            var data  = JSON.parse(response.body);
    
            // get the price
            var price = data.price;
    
            // print out the price
            print("The price is " + price);
        });
    

    requestSomeData("http://example.com/foo")
        .requestHandler(function(response){
            try {
                var data = JSON.parse(response.body);
            }
            catch(e) {
                return;
            }
    
            // get the price
            var price = data.price;
    
            // print out the price
            print("The price is " + price);
        });
    

    如果我们想要处理错误,那么它们是相等的:

    requestSomeData("http://example.com/foo") // returns a promise for the response
        .then(function(response){ // ‘then’ is used to provide a promise handler
            // parse the body
            var data  = JSON.parse(response.body);
    
            // get the price
            var price = data.price;
    
            // print out the price
            print("The price is " + price);
        }).catch(SyntaxError, function(e) {
            console.error(e);
        });
    

    以及:

    requestSomeData("http://example.com/foo")
        .requestHandler(function(response){
            try {
                var data = JSON.parse(response.body);
            }
            catch(e) {
                //If the above had a typo like `respons.body`
                //then without this check the ReferenceError would be swallowed
                //so this check is kept to have as close equality as possible with
                //the promise code
                if(e instanceof SyntaxError) {
                    console.error(e);
                    return;
                }
                else {
                    throw e;
                }
            }
    
            // get the price
            var price = data.price;
    
            // print out the price
            print("The price is " + price);
        });
    
        4
  •  0
  •   Fredrik Blomqvist    13 年前