一.一个牛逼闪闪的知识点Promise

  npm install bluebird

二.Promise实例

ball.html

<!doctype>
<!DOCTYPE html>
<html>
<head>
<title>Promise animation</title>
<style>
.ball {
width: 40px;
height: 40px;
border-radius: 20px;
}
.ball1 {
background: red;
}
.ball2 {
background: yellow;
}
.ball3 {
background: 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(){
//
})
})
})
})
})
})
</script>
</body>
</html>

使用Promise改造后,ball2.html如下:

<!doctype>
<!DOCTYPE html>
<html>
<head>
<title>Promise animation</title>
<style>
.ball {
width: 40px;
height: 40px;
border-radius: 20px;
}
.ball1 {
background: red;
}
.ball2 {
background: yellow;
}
.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') 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只需三点
1.Promise是JS针对异步操作场景的解决方案
  针对异步的场景,业界有很多解决方案,如回调、事件机制
  Promise是一个对象,同时它也一种规范,针对异步操作约定了统一的接口,表示一个异步操作的最终结果以同步的方式来写代码,执行的操作是异步的,但是又保证程序的执行顺序是同步的。
  原本是社区的一个规范的构想,被加入到ES6的语言标准里面,比如Chrom,Firefox浏览器已对它进行了实现。
2.Promise对象三种状态
  未完成(pending)
  已完成(fulfilled)
  失败(rejected)
  只能从未完成到已完成,或者从未完成到失败,不可逆的。
3.ES6的Promise语言标准、Promise/A+规范
  Promise/A+规范算是之前的Promise/A规范的升级版,规定了行为标准,扩展了原来的规范,并且覆盖了一些约定俗成的行为,总之,它就是一个更为标准的Promise能力和使用的规范。
  Promise/A与A+不同点
  a.A+规范通过术语thenable来区分promise对象
  b.A+定义onFulfilled/onRejected必须是作为函数来调用,而且调用过程必须是异步的
  c.A+严格定义了then方式链式调用时onFulfilled/onRejected的调用顺序
4.如何使用Promise then方法

promiseObj.then(onFulfilled, onRejected)
onFulfilled = function(value) {
  return promiseObj2
}
onRejected = function(err) {}

  Promise会保证then方法回调的顺序,依次调用,会等前面的promise方法执行完成后才会执行后面then中的方法。

  Promise最大的特点是:回调函数可以写成规范的链式的写法,程序流程可以很清楚。它的一整套接口可以实现很强大的功能,比如为多个异步操作部署一个回调函数,为多个回调函数中抛出的错误统一指定处理的方法等等。
5.在什么场景下使用
  只要是异步编程的地方,都可以使用Promise,但不能Promise而Promise,如业务场景是很简单的异步操作,维护很容易了,没必要引入一个Promise库来重构。
6.Promise库
  Promise库市面上有不少,如下所示:
  bluebird
  Q
  then.js
  es6-promise
  ypromise
  async
  nativeo-promise-only

四.重写爬虫,更优雅的异步编程
  https协议是基于ssl/tls的http协议,所有数据都是在ssl/tls协议的封装之上传输的。

  也就是说,https协议是在http协议的基础之上添加了ssl/tls握手及数据加密传输,因此,ssl/tls协议就是http和https最大区别。

  在搭建https服务器的时候,需要有一个ssl证书。

https.js

var https = require('https')
var fs = require('fs') 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 Imooc')
}).listen(8090)

重写爬虫,更优雅的异步编程,promise_crawler.js

var http = require('http')
var Promise = require('bluebird')
var cheerio = require('cheerio')
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) var chapters = $('.learnchapter') var title = $('#page_header .path span').text()
var number = parseInt($($('.info_num i')[0]).text().trim(), 10)
// var courseData = {
// title: title,
// number: number,
// videos: [{
// chapterTitle: '',
// videos: [
// title: '',
// id: ''
// ]
// }]
// } var courseData = {
title: title,
number: number,
videos: []
} chapters.each(function(item) {
var chapter = $(this)
var charterTitle = 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 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.number + ' 人学过 ' + courseData.title + '\n')
})
coursesData.forEach(function(courseData) {
console.log('###' + courseData.title + '\n')
courseData.videos.forEach(function(item) {
var chapterTitle = item.chapterTitle console.log(charterTitle + '\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() {
resolve(html)
})
}).on('error', function(e) {
reject(e)
console.log('获取课程数据出错!')
})
})
} var fetchCourseArray = []
videoIds.forEach(function(id) {
fetchCourseArray.push(getPageAsync(baseUrl + id))
}) Promise
.all(fetchCourseArray)
.then(function(pages) {
var coursesData = [] pages.forEach(function(html) {
var courses = filterChapters(html)
coursesData.push(courses)
}) coursesData.sort(function(a, b) {
return a.number < b.number
}) printCourseInfo(coursesData)
})

运行结果:

五.Nodejs API
1.横扫Nodejs API-Buffer的实例
  Buffer:用来处理二进制的数据。因为JS字符串是UTF-8的编码存储的,处理二进制的能力是很弱的,而网络层对于不同资源的请求、响应,甚至是文件都是二进制的方式来交互的,所以Node.js有这么一个接口,专门用于存放二进制数据的缓存区,并提供了一些方法来对缓存区数据进行进一步的处理。Buffer在Node.js中是要以全局访问的,不需要用require来加载。

> Buffer
{ [Function: Buffer]
poolSize: 8192,
from: [Function: from],
of: [Function: of],
alloc: [Function: alloc],
allocUnsafe: [Function: allocUnsafe],
allocUnsafeSlow: [Function: allocUnsafeSlow],
isBuffer: [Function: isBuffer],
compare: [Function: compare],
isEncoding: [Function: isEncoding],
concat: [Function: concat],
byteLength: [Function: byteLength],
[Symbol(kIsEncodingSymbol)]: [Function: isEncoding] }
> new Buffer('Hello Node.js')
<Buffer 48 65 6c 6c 6f 20 4e 6f 64 65 2e 6a 73>
> new Buffer('Hello Node.js', 'base64');
<Buffer 1d e9 65 a0 da 1d 7a 3b>
> var buf = new Buffer(8);
undefined
> buf.length
8
> var buf = new Buffer('12345678');console.log(buf);
<Buffer 31 32 33 34 35 36 37 38>
undefined
> var buf = new Buffer(7);buf.write('12345678');console.log(buf);
<Buffer 31 32 33 34 35 36 37>
undefined
> var buf = new Buffer([1,2,3,4]);console.log(buf);
<Buffer 01 02 03 04>
undefined
> console.log(buf[1])
2
undefined
> var buf = new Buffer([1,2.33,3.11,4]);console.log(buf);
<Buffer 01 02 03 04>
undefined
> console.log(buf[1])
2
undefined

a.buffer.write(string, offset=0, length, encoding='utf8')方法

> var buf = new Buffer('Hello 慕课网')
undefined
> buf.length
15
> buf.write('Hi 慕课网')
12
> buf.toString()
'Hi 慕课网网'
> buf.length
15
> buf.write(' ImoocImoocImooc', 2, 16)
13
> buf.toString()
'Hi ImoocImoocIm'

b.buffer.copy(target, tStart, sStart, sEnd=buffer.length)

> var buf = new Buffer('Hello Imooc')
undefined
> buf.length
11
> var buf2 = new Buffer(5)
undefined
> buf.copy(buf2)
5
> buf2.toString()
'Hello'
> buf.copy(buf2, 0, 6, 11)
5
> buf2.toString()
'Imooc'

c.buffer.js源码

var buffer = process.binding('buffer');
process.binding它是一个桥梁,javaScript代码就可以和C++代码进行交互,这条语句获取到C++里面实现的buffer模块 > var buf = new Buffer('imooc');
undefined
> var str = buf.toString('base64');
undefined
> str
'aW1vb2M='
> var buf = new Buffer('aW1vb2M=', 'base64')
undefined
> var str = buf.toString()
undefined
> str
'imooc'
> var buf = new Buffer('aW1vb2M=', 'base64')
undefined
> var str = buf.toString('hex')
undefined
> str
'696d6f6f63'
> var buf = new Buffer('696d6f6f63', 'hex')
undefined
> var str = buf.toString('utf8')
undefined
> str
'imooc'
>

2.buffer实例buffer_image.js

var fs = require('fs')

fs.readFile('logo.png', function(err, origin_buffer) {
console.log(Buffer.isBuffer(origin_buffer)) fs.writeFile('logo_buffer.png', origin_buffer, function(err) {
if(err) {
console.log(err)
}
}) //var base64Image = new Buffer(origin_buffer).toString('base64')
var base64Image = origin_buffer.toString('base64') console.log(base64Image) var decodedImage = new Buffer(base64Image, 'base64') console.log(Buffer.compare(origin_buffer, decodedImage)) fs.writeFile('logo_decoded.png', decodedImage, function(err) {
if(err) {
console.log(err)
}
})
}) //把打印出来的base64Image,然后 data:image/png;base64,base64Image串,把data:image/png;base64,base64Image串拷贝到网页图片的url()的这个括号中,就可以查看到这张图片。

运行结果:

在当前目录下将会看到logo_buffer.png和logo_decoded.png两个文件。

当然,可以把输入的base64的串拷贝出来,然后在编辑器中编写如下所示:data:image/png;base64,输出的base64的串,可以把这整个串拷贝,如放到慕课网的背景url中,也能达到和慕课网本身图片一样的效果。

3.Stream流

stream_copy_logo.js

var fs = require('fs')
var source = fs.readFileSync('logo.png') fs.writeFileSync('stream_copy_logo.png', source)

运行后,在当前目录下产生stream_copy_logo.png文件,且和logo.png一样。

stream_event.js

var fs = require('fs')

var readStream = fs.createReadStream('stream_copy_logo.js')

readStream.on('data', function(chunk) {
console.log('data emits')
console.log(Buffer.isBuffer(chunk))
console.log(chunk.toString('utf8'))
}).on('readable', function() {
console.log('data readable')
}).on('end', function() {
console.log('data ends')
}).on('close', function() {
console.log('data close')
}).on('error', function(e) {
console.log('data read error' + e)
})

运行结果:

stream_event02.js,流的暂停和重启

var fs = require('fs')

var readStream = fs.createReadStream('stream_copy_logo.js')
var n = 0 readStream.on('data', function(chunk) {
n++
console.log('data emits')
console.log(Buffer.isBuffer(chunk))
//console.log(chunk.toString('utf8'))
readStream.pause()
console.log('data pause')
setTimeout(function() {
console.log('data pause end')
readStream.resume()
}, 3000)
}).on('readable', function() {
console.log('data readable')
}).on('end', function() {
console.log(n)
console.log('data ends')
}).on('close', function() {
console.log('data close')
}).on('error', function(e) {
console.log('data read error' + e)
})

运行结果:

stream_copy_logo2.js,重构复制文件的代码

var fs = require('fs')

var readStream = fs.createReadStream('1.mp4')
var writeStream = fs.createWriteStream('1-stream.mp4') readStream.on('data', function(chunk) {
//数组还在缓存区
if(writeStream.write(chunk) === false) {
console.log('still cached')
readStream.pause()
}
}) readStream.on('end', function() {
writeStream.end()
}) //对于writeStream来说,有一个drain事件,表明数据已经消费完了(写到目标了)
writeStream.on('drain', function() {
console.log('data drains')
//告诉readStream可以来读了
readStream.resume()
})

运行结果:

Readable:可读流,负责读取外部的数据,并把数据缓存到内部的Buffer数组
  Writable:可写流,负责消费数据,从可读流里获取到数据,然后对得到的数据块进行处理
  Duplex:双工流,实现了Readable、Writable两个接口,如TcpSocket
  Transform:转换流,也是双工的,可读可写,实现了Readable、Writable两个接口,但不保留数据

request_logo.js

var http = require('http')
var fs = require('fs')
var request = require('request') http.createServer(function(req, res){
// fs.readFile('logo.png', function(err, data) {
// if(err) {
// res.end('file not exist!')
// }else {
// res.writeHeader(200, {'Context-Type': 'text/html'})
// res.end(data)
// }
// }) //pipe方法会自动帮我们监听data和end事件,图片文件中每一小段数据都会源源不断地发送给客户端,除此以外它还可以自动控制后端压力,这样在客户端连接缓慢时,node可以将尽可能少的缓存放到内存里面,通过对内存空间的调度就能自动控制流量,从而避免目标被快速读取的流而淹没
//并且数据在pipe时,只有pipe链末端的目标流真正需要数据时,数据才会从源头被取出来。所以是被动消费。
//fs.createReadStream('logo.png').pipe(res) request('https://www.imooc.com/static/img/index/logo.png').pipe(res)
}).listen(8090)

运行node request_logo.js后,在浏览器中输入http://localhost:8090,就能展示logo图片。

pipe_video.js

var fs = require('fs')

fs.createReadStream('1.mp4').pipe(fs.createWriteStream('1-pipe.mp4'))

运行后就会在当前目录下新产生1-pipe.mp4,和1.mp4一模一样。

stream_read_write.js

var Readable = require('stream').Readable
var Writable = require('stream').Writable var readStream = new Readable()
var writStream = new Writable() readStream.push('I ')
readStream.push('Love ')
readStream.push('Imooc\n')
readStream.push(null) writStream._write = function(chunk, encode, cb) {
console.log(chunk.toString())
cb()
} readStream.pipe(writStream)

运行结果:

custom_stream.js

var stream = require('stream')
var util = require('util') function ReadStream() {
stream.Readable.call(this)
} util.inherits(ReadStream, stream.Readable) ReadStream.prototype._read = function() {
this.push('I ')
this.push('Love ')
this.push('Imooc\n')
this.push(null)
} function WritStream() {
stream.Writable.call(this)
this._cached = new Buffer('')
} util.inherits(WritStream, stream.Writable) WritStream.prototype._write = function(chunk, encode, cb) {
console.log(chunk.toString())
cb()
} function TransformStream() {
stream.Transform.call(this)
} util.inherits(TransformStream, stream.Transform) TransformStream.prototype._transform = function(chunk, encode, cb) {
this.push(chunk)
cb()
} TransformStream.prototype._flush = function(cb) {
this.push('Oh Yeah!')
cb()
} var rs = new ReadStream()
var ws = new WritStream()
var ts = new TransformStream() rs.pipe(ts).pipe(ws)

运行结果:

学习视频《进击Node.js基础(二)》。

进击Node.js基础(二)的更多相关文章

  1. 10慕课网《进击Node.js基础(一)》初识promise

    首先用最简单的方式实现一个动画效果 <!doctype> <html> <head> <title>Promise animation</titl ...

  2. 07慕课网《进击Node.js基础(一)》HTTP小爬虫

    获取HTML页面 var http = require('http') var url='http://www.imooc.com/learn/348' http.get(url,function(r ...

  3. 03慕课网《进击Node.js基础(一)》API-URL网址解析

    url url.parse(url,query,host);解析域名 url必须,地址字符串 query可选 host 可选:在不清楚协议时正确解析 querystring 字符串和对象之间互相解析 ...

  4. 01慕课网《进击Node.js基础(一)》Node.js安装,创建例子

    版本:偶数位为稳定版本,基数为非稳定版本 - 0.6.x - 0.7.x    - 0.8.x -0.9.x    -0.10.x  -0.11.x 概念:Node.js采用谷歌浏览器的V8引擎,用C ...

  5. 进击Node.js基础(一)

    一.前言 1:Node.js本质上是用chrome浏览器 v8引擎 使用c++编写的JS运行环境 2:相比于JS没有浏览器安全级的限制,额外提供了一些系统级的API:文件读写,进程管理,网络通信等. ...

  6. 02慕课网《进击Node.js基础(一)》——CommonJs标准

    是一套规范管理模块 每个js 为一个模块,多个模块作为一个包 node.js和Couchdb是对其的实现: 不同于jQuery 模块:定义.标识.引用(地址/模块名称) 模块类型: 核心模块http ...

  7. 进击Node.js基础(二)promise

    一.Promise—Promise似乎是ES6中的规范 PROMISE的语言标准,PROMISE/A+规范,如何使用,在什么场景下使用 Promise时JS对异步操作场景提出的解决方案(回调,观察者模 ...

  8. node.js 基础二 开启服务器监听

    1.server.js 2.监听 一 server.js 二 监听 运行server.js后,浏览器打开:http://localhost:8888/ //====================== ...

  9. 05慕课网《进击Node.js基础(一)》HTTP概念进阶(同步/异步)

    HTTP模块介绍 支持http协议的更多特性 不缓存请求和响应 API比较底层处理流相关,信息解析 HTTP相关概念 回调 将函数作为参数传到执行函数中,参数函数在执行函数中嵌套执行 function ...

随机推荐

  1. spring mvc后台如何处理ajax的请求,并返回json

    spring mvc中有一个注解:@ResponseBody,把这个注解放到ajax请求对应的@RequestMapping(xxx)方法上,在方法体内部,把要返回的json赋给一个String类型的 ...

  2. Hibernate多对多双向关联需要注意的问题(实例说话)

    以Student和Course为例,一个学生可以选多门课程,一门课程也可以被多个学生选取: 持久化类Student: package bean; import java.util.Set; publi ...

  3. 【转】Swig使用指南

    如何使用 API swig.init({ allowErrors: false, autoescape: true, cache: true, encoding: 'utf8', filters: { ...

  4. ArgumentException: 已添加了具有相同键的项。

    此问题出现在asp.net mvc 5 中,前端向后端请求数据,方法的参数是模型,比如 Add(Student m), 结果浏览器显示的状态是500并返回错误提示ArgumentException,如 ...

  5. Oracle数据库多行记录转换一行并排序函数

    Oracle数据库多行记录转换一行并排序方法 在ORACLE数据库查询中,我们通常会要求用到将多行记录转换成一行并排序,这时候我们自然会想到Oracle的一个“wx_concat”函数,可以将多行记录 ...

  6. leetcode 之突然不做了

    最近心情也不好,学不会的东西太多,以前能懂为什么,现在完全不知道为什么,只能依葫芦画瓢了,所以我写出了的代码到底是会了吗?还是瓢画的好? 热血之三分钟热度小张发现leetcode里会做的好像都做了,剩 ...

  7. .net Aspose.pdf 转html 去除版权

    时光偷走的,永远都是我们眼皮底下看不见的珍贵. 1. 资源文件 a)     Aspose.pdf.18.12.0.nupkg  链接:https://pan.baidu.com/s/171_OWOf ...

  8. GSS1 - Can you answer these queries I(线段树)

    前言 线段树菜鸡报告,stO ZCDHJ Orz,GSS基本上都切完了. Solution 考虑一下用线段树维护一段区间左边连续的Max,右边的连续Max,中间的连续Max还有总和,发现这些东西可以相 ...

  9. Java并发编程读书笔记(一)

    ----------------------------------------------<Java并发编程实战>读书笔记-------------------------------- ...

  10. Uliweb之 ORM基本使用(Sqlalchemy)

    参考:http://limodou.github.io/uliweb-doc/zh_CN/db/orm.html#title_1-2 ORM基本使用¶ 使用要求¶ 需要安装sqlalchemy 0.7 ...