Promise入门级介绍
本文是观看了慕课网上的进击的NodeJs(二)后写的小结,感谢Scott老师
- 本文只为了以简单,大概的形式了解promise
- JavaScript Promise迷你书(中文版)需要详细了解可以在这里查询
1. Promise到底是什么?
promise是抽象异步操作处理对象以及对其进行各种操作的组件
promise是ES6新增特性
用粗糙的话说:promise是让我们舒服的写回调的一种方式
2. 为什么要用promise
- 因为是ES6规范中的一个重要对象,学习没有坏处!
- promise是为了处理回调地狱的新的处理
- 让代码简洁,增加可读性的一种方式
3. promise 的属性和方法
首先介绍一下promise有几种状态:
new Promise(/ * executor * / function(resolve,reject){...});
- pedding: 一开始创建promise时的状态,不属于成功与失败
- Resolved(成功状态)
- rejected(失败)
这些状态只能从pedding到成功,或者pending到失败,不可逆,不可停止;
4. promise 的属性与方法
属性:
Promise.length
Length属性,其值始终为1(构造函数参数的数目)
Promise.prototype
表示 Promise 构造器的原型.
方法:
- Promise.all(iterable)
返回一个Promise,当可迭代参数中的所有promise都满足或拒绝时,只要可迭代参数中的一个promise拒绝就满足。如果返回的promise满足,则使用来自履行的promise中的值的数组来实现,其具有与可迭代中定义的顺序相同的顺序。如果返回的promise拒绝,它被拒绝的原因来自可迭代的第一个promise拒绝。此方法可用于聚合多个promise的结果。
- Promise.race(iterable)
返回一个promise,只要promise中的一个promise满足或拒绝,就满足或拒绝该promise,以及该promise中的值或原因。
- Promise.reject(reason)
返回一个Promise被拒绝,并给出的理由对象。
- Promise.resolve(value)
返回Promise一个与给定值解析的对象。如果该值是一个thenable(即有一个then方法),返回的承诺将“跟随 ”是thenable,采用其最终状态; 否则返回的promise将使用该值来完成。一般来说,如果你不知道一个值是一个承诺或没有,Promise.resolve(value)它反而和返回值作为一个承诺工作。
5. 怎么用promise
先从一个例子来了解一下回调地狱的感觉= =
这个例子是三个小球的移动的例子,以注释的方式来解释例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>promise animation</title>
<--这里是引入bluebird,我注释掉后一样可以使用Promise,因为现在的浏览器本身可以识别Promise 在node中要require('promise')-->
<!-- <script src="./node_modules/bluebird/js/browser/bluebird.js" charset="utf-8"></script> -->
<style media="screen">
.ball{
width: 40px;
height: 40px;
border-radius: 50%;
}
.ball1{
background: red;
}
.ball2{
background: blue;
}
.ball3{
background: green;
}
</style>
</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() //这里是短路表达式,cb存在?执行cb()
// }else{
// if (marginLeft < distance){
// marginLeft++;
// }else{
// marginLeft--;
// }
// ball.style.marginLeft = marginLeft +'px';
// animate(ball, distance, cb);
// }
// },13)
// }
//callback回调函数的嵌套
// animate(ball1, 100, function(){
// animate(ball2, 200, function(){
// animate(ball3, 300, function(){
// animate(ball3, 150, function(){
// animate(ball2, 150,function(){
// animate(ball1, 150, function(){
//
// });
// });
// });
// });
// });
// });
/* 这是以Promise的形式 */
var Promise = window.Promise;
function promiseAnimate(ball, distance){
//把promise对象返回
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()
})
}
//then有点类似类似链式调用,这种方式看着简洁,代码可读性高
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>
6. promise库(Scott老师推荐bluebird)
- 以下promise库大同小异,学习期间重点是学习promise用法,各个差异自行百度,最新的浏览器都支持了promise,学习的时候也可以不用引库
- bluebird
- Q
- then.js
- es6-promise
- ypromise
- async
- native-promise-only
- .....
7.PromiseA与A+不同点
- A+ 规范通过术语thenable来区分promise对象
- A+ 定义了onFulfilled/onRejected必须是作为函数来调用的,而且调用过程必须是异步
- A+ 严格定义了then 方法链式调用时onFulfilled/onRejected的调用顺序
8.Promise then方法
promise会保证回调的顺序,链式调用then方法参数里的回调函数会依次调用,这then方法不会立即执行,只有前面的promise成功后才会进行
promiseObj.then(onFulfilled,onRejjected){
onFunlilled = function(value){
return promiseObj2
}
inRejected = function(err){
}
}
9. 简单HTTPS服务器的搭建
HTTPS是在HTTP的多了一层SSL/TLS,多了一次握手从三次握手改成了四次握手,这里就不多聊,有兴趣可以多多百度,主要是为了学习怎么搭建一个HTTPS的本地服务器
var https = require('https');
var fs = require('fs');//注入读取文件
//key与cert
var options = {
key:fs.readFileSync('ssh_key.pem'),
cert:fs.readFileSync('ssh_cert.pem')
};
https
.createServer(options,function(req, res){
res.writeHead(200);
res.end('hello');
})
.listen(8080);
10. 用promise优化爬虫
在最新的版本里已经有了Promise这个函数了,老板本是没有这个函数的!要加第三方!
var http = require('http');
var cheerio = require('cheerio');//引入cheerio
//新版本内置Promise了
var baseUrl = 'http://www.imooc.com/learn/';
// var url = 'http://www.imooc.com/learn/348';
var videoIds = [348, 259, 197, 134, 75];
function filterChapters(html){
var $ = cheerio.load(html);//变成jq模样便于理解
var chapters = $('.chapter');
var title = $('#main .path span').text();
//由于该爬虫只能爬到源代码上的数据,而人数又是ajax获取的,所以人数拿不到
// courseData = {
// title:title,
// videos:[{
// chapterTitle:'',
// videos:[{
// title:'',
// id:''
// }]
// }]
// }
var courseData = {
title:title,
videos:[]
};
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(){
var video = $(this).find('.J-media-item');
var videoTitle = video.text();
var id = video.attr('href').split('video/')[1];
chapterData.videos.push({
title:videoTitle,
id:id
});
});
courseData.videos.push(chapterData);
});
return courseData;
}
function printCourseInfo(coursesData){
coursesData.forEach(function(courseData){
console.log('### ' + courseData.title + '\n');
courseData.videos.forEach(function(item){
var chapterTitle = item.chapterTitle;
// console.log(chapterTitle + '\n');
console.log(chapterTitle.replace(/\s+/g,"")+"\n");
item.videos.forEach(function(video){
// console.log('【' + video.id +'】' + video.title + '\n');
console.log("【"+ video.id.replace(/\s+/g,"") +"】"+video.title.replace(/\s+/g,"") +"\n");
});
});
});
}
function getPageAsync(url){
return new Promise(function(resolve, reject){//返回一个Promise对象
console.log('正在爬取 '+ url);
http.get(url,function(res){
var html = '';
res.on('data',function(data){//data事件
html += data;
});
res.on('end',function(){//end 事件
resolve(html);//成功获取
});
}).on('error',function(e){//error
reject(e);//失败
console.log('获取课程数据失败!');
});
});
}
var fetchCourseArray = [];//存放Promise对象的数组
videoIds.forEach(function(id){
fetchCourseArray.push(getPageAsync(baseUrl + id));
});
Promise
.all(fetchCourseArray)//等待所有的异步爬取结束以后利用then方法进行下一步
.then(function(pages){
var coursesData = [];
pages.forEach(function(html){
var courses = filterChapters(html);
coursesData.push(courses);
});
printCourseInfo(coursesData);
});