Promise
Promise
参考
http://lucifier129.github.io/nodeppt/20150528/promise.htm
http://efe.baidu.com/blog/promises-anti-pattern/
http://www.html5rocks.com/zh/tutorials/es6/promises/#toc-api
使用浏览器的Promise
将一个非Promise变成Promise
function get(url) {
// 返回一个新的 Promise
return new Promise(function(resolve, reject) {
// 经典 XHR 操作
var req = new XMLHttpRequest();
req.open('GET', url);
req.onload = function() {
// 当发生 404 等状况的时候调用此函数
// 所以先检查状态码
if (req.status == 200) {
// 以响应文本为结果,完成此 Promise
resolve(req.response);
} else {
// 否则就以状态码为结果否定掉此 Promise
// (提供一个有意义的 Error 对象)
reject(Error(req.statusText));
}
};
// 网络异常的处理方法
req.onerror = function() {
reject(Error("Network Error"));
};
// 发出请求
req.send();
});
}
story = get('story.json');
story.then(function(res){
return JSON.parse(res);
}).then(function(obj){
console.log(obj);
});
再来一个例子
我把ajax的例子放在前面是因为我觉得 ajax的使用场景会更容易理解
var getData = function(){
var data;
setTimeout(function(){
data = 'data';
},0);
return data;
}
console.log(getData()); //undefined //显然这样是得不到结果的
//所以我们必须传入一个回调函数
var getData = function(callback){
var data;
setTimeout(function(){
data = 'data';
callback(data);
},0);
}
getData(function(data){
console.log(data)
});
改成Promise
var getData = function(){
var promise = new Promise(function(resolve, reject){
setTimeout(function(){
resolve('data');
},0);
});
return promise;
}
getData().then(function(data){
console.log(data);
});
关于defer
下面是用Q.js 的defer
http://efe.baidu.com/blog/promises-anti-pattern/ 这里建议不在使用defer
尽管这个写法在https://github.com/kriskowal/q 中可以看到
function load(url) {
var deferred = Q.defer();
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if (req.readyState === 4) {
deferred.resolve(req.responseText);
}
}
req.open('GET', url, true);
req.send();
return deferred.promise;
}
load('story.json').then(function(data) {
console.log(data);
});
最好这么用 (这里实际上就是告诉你如何用Q.js包装出一个Promise)
原文中有这么一句
Q.Promise
This is an alternative promise-creation API that has the same power as the deferred concept, but without introducing another conceptual entity.
function load(url){
return Q.Promise(function (resolve, reject) {
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if (req.readyState === 4) {
resolve(req.responseText);
}
}
req.open('GET', url, true);
req.send();
});
}
load('story.json').then(function(data) {
console.log(data);
});
链式操作
比如我需要等意见事情做完了再做另一件事情
最容易想到的
get('story.json').then(function(data){
get('story.txt').then(function(data2){
get('xxx').then(function(data3){
//.....
})
})
});
突然觉得不对 不是说Promise是用来解决嵌套的问题嘛 这看起来还是在嵌套啊
我们需要return一个promise对象 这才是真正解决深层嵌套
get('story.json').then(function(data){
return get('story.txt');
}).then(function(rs){
console.log(rs); //虽然前一个Promise返回的是一个Promise对象 但是这里的rs并不是一个Promise 而是前面的Promise对象resolve的结果 //也就是story.txt中的内容
return get('xxx');
}).then(function(xxx){
return get('dot');
}).then(function(dot){
//...
})
当然了 假如你需要某次回调中得到所有异步的结果 你可以用第一种嵌套形式
或者使用Promise.all
Promise.all
var p1 = Promise.resolve(1),
p2 = Promise.resolve(2),
p3 = Promise.resolve(3);
Promise.all([p1, p2, p3]).then(function (results) {
console.log(results); // [1, 2, 3]
});
//Promise.all 常用在 forEach 中
//比如
get('story.json').then(function(story){
var promiseArr = story.chapters.map(function(chapter){
return get(chapter.url);
});
return Promise.all(promiseArr);
}).then(function(resultsArr){
//resultsArr 是一个数组
})
再来一个例子 这里使用的是q.js 中的Promise all
var promises = urls.map(function(url){
return Q.promise(function(resolve, reject){
superagent.get(url).end(function(err,res){
resolve({
url: url,
text: res.text
});
});
});
});
Q.all(promises).then(function(arr){
arr = arr.map(function(item){
var $ = cheerio.load(item.text);
return {
href: item.url,
title: $('.topic_full_title').html() ? $('.topic_full_title').html() : '',
comment: $('.reply_content').eq(0).text() ? $('.reply_content').eq(0).text() : ''
}
});
console.log(arr);
})