让我们将 Promise 示例与纯 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);
});
正如 Norbert Hartl 指出的那样,JSON.parse() 将在浏览器中挂起大字符串。所以我使用 setTimeout() 来延迟它的执行(在 10 毫秒的暂停之后)。这是 Kris Kowal 解决方案的一个示例。它允许当前的 Javascript 线程完成,释放浏览器来呈现 DOM 更改并在回调运行之前为用户滚动页面。
我希望commonjs的promise框架也使用setTimeout之类的东西,否则文章示例中后面的promise确实会像担心的那样同步运行。
我上面的替代方案看起来很丑陋,后面的过程需要进一步缩进。我重组了代码,这样我们就可以在一个层次上提供我们的流程链:
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 中传统的前向回调与 Promise 相当。然而,经过两次尝试,我似乎已经证明,参考原始示例中代码的简洁性,promise 是一个更优雅的解决方案!