Node.js之Promise
2015年发布了ES6标准,所谓 Promise,就是ES6标准的一个对象,用来传递异步操作的消息。它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个事件提供统一的 API,可供进一步处理。
有了 Promise 对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise 对象提供统一的接口,使得控制异步操作更加容易。
var promise = new Promise(function(resolve, reject) {
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
promise.then(function(value) {
// success
}, function(value) {
// failure
});
Promise函数接受一个函数作为参数,该函数的两个参数分别是 resolve 方法和 reject 方法。
如果异步操作成功,则用 resolve 方法将 Promise 对象的状态,从「未完成」变为「成功」(即从 pending 变为 resolved);
如果异步操作失败,则用 reject 方法将 Promise 对象的状态,从「未完成」变为「失败」(即从 pending 变为 rejected)。
小范例:
<!DOCTYPE> <html lang="en"> <head> <meta charset="UTF-8"> <title>promise animation</title> <style type="text/css"> .ball{ width: 40px; height:40px; border-radius: 20px; } .ball1{ background-color: red; } .ball2{ background-color: yellow; } .ball3{ background-color: green; } </style> <script src="node_modules/bluebird/js/browser/bluebird.js"></script> </head> <body> <div class="ball ball1" style="margin-left:0;"></div> <div class="ball ball2" style="margin-left:0;"></div> <div class="ball ball3" style="margin-left:0;"></div> <script type="text/javascript"> var ball1=document.querySelector('.ball1'); var ball2=document.querySelector('.ball2'); var ball3=document.querySelector('.ball3'); function animate(ball,distance,cb){ setTimeout(function(){ var marginLeft=parseInt(ball.style.marginLeft,10); if(marginLeft===distance){ cb&&cb(); }else{ if(marginLeft<distance){marginLeft++;} else{marginLeft--;} ball.style.marginLeft=marginLeft; animate(ball,distance,cb); //不断重复做这件事知道球移动到我们期望的位置 } },13) } // animate(ball1,100,function(){ // animate(ball2,200,function(){ // animate(ball3,300,function(){ // animate(ball3,150,function(){ // animate(ball2,150,function(){ // animate(ball1,150,function(){ // }) // }) // }) // }) // }) // }) var Promise=window.Promise; function promiseAnimate(ball,distance){ return new Promise(function(resolve,reject){ function _animate(){ setTimeout(function(){ var marginLeft=parseInt(ball.style.marginLeft,10) if(marginLeft===distance){ resolve() }else{ if(marginLeft<distance){ marginLeft++ }else{ marginLeft-- } ball.style.marginLeft=marginLeft+'px' _animate() } },13) } _animate() }) } promiseAnimate(ball1,100) .then(function(){ return promiseAnimate(ball2,200) }) .then(function(){ return promiseAnimate(ball3,300) }) .then(function(){ return promiseAnimate(ball3,150) }) .then(function(){ return promiseAnimate(ball2,150) }) .then(function(){ return promiseAnimate(ball1,150) }) </script> </body> </html>
关于Promise需要学习以下几点:
Promise的三种状态:
示例二,网络小爬虫
var http=require('http') var cheerio=require('cheerio') var baseUrl='http://www.imooc.com/learn/' var videoIds=[348,259,197,134,75] //var url='http://119.29.109.156:8080/ServerTest01/' //each 和 forEach区别在于each可以改变数组中的数据 function filterChapters(html){ var $=cheerio.load(html) var chapters=$('.chapter') var title=$('.hd .l').text() var number=parseInt($($('.meta-value strong')[3]).text().trim(),10) /*courseData={ title:title, number:number, videos: [{ chapterTitle:'' videos:[ title:'' id:'' ] }] }*/ var courseData={ videos:[], number:number, title:title } //将课程名和学习人数进行写入 courseData.title=title courseData.number=number chapters.each(function(item){ var chapter=$(this) var chapterTitle=chapter.find('strong').text() var videos=chapter.find('.video').children('li') var chapterData={ chapterTitle:chapterTitle, videos:[] } videos.each(function(item){ var video=$(this).find('.studyvideo') var videoTitle=video.text() var videoid=video.attr('href').split('video/')[1] chapterData.videos.push({ title:videoTitle, id:videoid }) }) courseData.videos.push(chapterData) }) return courseData } function printCourseInfo (coursesData) { console.log('printCourseInfo') coursesData.forEach(function(courseData){ console.log(courseData.number+' 人学过 '+courseData.title+'\n') }) coursesData.forEach(function(courseData){ console.log('### '+courseData.title+'\n') courseData.videos.forEach(function(item){ var chapterTitle=item.chapterTitle console.log(chapterTitle+'\n') item.videos.forEach(function(video){ console.log(' ['+video.id+'] '+video.title+'\n') }) }) }) } function getPageAsync(url){ return new Promise(function(resolve,reject){ console.log('正在爬取 '+url) http.get(url,function(res){ var html='' res.on('data',function(data){ html += data }) res.on('end',function(){ console.log('爬取 '+ url+' 成功') resolve(html) }) }).on('error',function(e){ reject(e) console.log('获取课程数据出错') }) }) } //存放所有课程的html的一个数组 var fentchCourseArray=[] videoIds.forEach(function(id){ fentchCourseArray.push(getPageAsync(baseUrl+id)) }) Promise .all(fentchCourseArray) .then(function(pages){ var coursesData=[] pages.forEach(function(html){ console.log("1111") var courses=filterChapters(html) coursesData.push(courses) }) coursesData.sort(function(a,b){ return a.number<b.number }) printCourseInfo(coursesData) })