我读 这篇文章 与部分有关的承诺抽象似乎有点过于复杂,给我。以下是作为一个例子:

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);
    });
有帮助吗?

解决方案

虽然这是事实,这两个最终将完成同样的事情,不同的是,第二个实施例是不同步的。例如,考虑如果JSON.parse(...)原来是一个非常昂贵的操作,会发生什么;你必须挂起,直到一切都完了,这可能并不总是你想要的。

这就是承诺给你:推迟正确答案的计算,直到一个更方便的时间的强大能力。正如其名,构建“承诺”给你的结果在某些时候,只是不一定是现在。你可以阅读更多关于期货和承诺工作在更大范围的 这里

其他提示

让我们比较诺至例如纯的Javascript示例:

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

正如诺贝特Hartl的指出,JSON.parse()来将挂起浏览器对于大的字符串。所以我用的setTimeout()的延迟执行(10毫秒的停顿之后)。这是克里斯·科瓦尔的解决方案的一个例子。它允许电流的Javascript线程完成,从而释放了浏览器本DOM的改变和滚动页面为用户,回调运行之前。

我希望CommonJS的承诺框架也采用类似的setTimeout,否则在本文的例子中,承诺以后的确会同步运行的担心。

我替代上述小艾难看,与需要进一步缩进的后面的处理。我调整了代码,使我们可以为我们的生产链都在同一个水平:

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

我希望能证明,传统的向前传递的Javascript回调是几乎等同于承诺。后然而两次尝试我似乎已经示出,参照在最初的例子的代码的整洁,该承诺是一个更为完美的解决方案!

第二个片段是容易受到拒绝服务攻击,因为example.com/foo可以只返回无效JSON导致服务器崩溃。即使是空响应是无效的JSON(尽管有效JS)。这就像与眩光SQL注入孔mysql_*例子。

和承诺代码可以许多改善。这些是等于:

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

一个可能也加入的优势,第一个版本在第二个是,它分离的不同操作的细化链(功能没有被写入在地方或者)。第二个版本的混合这两个低级别的分析与应用程序的逻辑。具体来说,利用固体原则为准则,第二版,违反了两个 路电SRP.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top