什么是利益的'承诺'的抽象在CommonJS?
-
23-09-2019 - |
题
我读 这篇文章 与部分有关的承诺抽象似乎有点过于复杂,给我。以下是作为一个例子:
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);
});