promise
promise 可以说是很常用的异步处理方法
比如我们使用promise封装一个canvas截图的方法
clip (resolve, reject) {
// 截屏 获取图片url
return new Promise((resolve, reject) => {
html2canvas(document.getElementById('view'), {
canvas: canvas,
onrendered: (canvas) => {
let getImg = canvas.toDataURL('image/png')
resolve(getImg)
}
})
})
}
复制代码
实现一个简单的promise
function Promise (executor) {
let self = this
self.status = 'pending'
self.success // 成功的原因
self.failure // 失败的原因
// 事件池
self.resolvePool = []
self.rejectPool = []
function resolve (data) {
if (self.status == 'rejected') return
self.status = 'resolved'
self.success = data
// 执行队列
self.resolvePool.forEach(function (cb){
cb(self.success)
})
}
function reject (data) {
if (self.status == 'resolved') return
self.status = 'rejected'
self.failure = data
// 执行队列
self.rejectPool.forEach(function (cb){
cb(self.failure)
})
}
// new一个实例就会立即执行这个promise
executor(resolve, reject)
}
// then
Promise.prototype.then = function (onFulfilled, onRejected) {
let self = this
let promiseStatus = self.status
if (promiseStatus == 'resolved') {
onFulfilled(self.success)
}
if (promiseStatus == 'rejected') {
onRejected(self.failure)
}
// 很有可能此时状态为 pending
if (promiseStatus == 'pending') {
// 放入事件池中等待执行
self.resolvePool.push(function () {
onFulfilled(self.success)
})
self.rejectPool.push(function () {
onRejected(self.failure)
})
}
}
复制代码
Iterator
let target = beIteraor({name: 'mxx', address: 'beijing'})
target.next()
target.next()
复制代码
Iterator 是一个迭代器对象 每次从集合中取出一项 并且跟踪当前序列所在位置
通过使用next方法 返回一个包含value和done两个属性的对象
{value: 当前对象成员, done: Boolean}
复制代码
Iterator 简易实现
let target = beIteraor(['mxx', 'beijing'])
let a = target.next()
let b = target.next()
let c = target.next()
// { value: 'mxx', done: false } { value: 'beijing', done: false } { value: 'undefined', done: true }
// 返回一个具有next方法的对象
function beIteraor(ary) {
let index = 0
let len = ary.length
return {
next: function () {
// 调用next方法 返回 {value, done} 并且指针移动位置
let done = ~~index == ~~len
// 如果指针位置移动到末尾 则返回undefined 否则返回当前位置成员
let value = done ? 'undefined' : ary[index]
index++
return {value, done}
}
}
}
复制代码
generator
- generator 函数生成一个迭代器
<!-- 函数 注: 这里的read函数直接返回文件中内容 -->
function * getCont () {
let name = yield 'youchangjing'
let address = yield 'beijing'
return name + address
}
<!-- 如何执行 -->
let getC = getCont()
getC.next() // {value: 'youchangjing', done: false}
getC.next() // {value: 'beijing' , done: false}
getC.next() // {value: undefined , done: true}
复制代码
可以看到 generator 函数调用和普通函数一样 fn() 即可 但是函数并不会执行 只有当调用next方法 才能执行到第一个状态
generator 是分段执行的 yield表示暂停执行 next方法恢复函数执行
目前来说 浏览器对 generator 支持情况还是很不错的
co
如果 yield 后面是一个 promise 函数 可以配合co 库来使用
<!-- read函数 -- 封装的一个简易的promise -->
function read(dir) {
return new Promise((resolve, reject) => {
fs.readFile(dir, 'utf-8', (err, cont) => {
if (err) reject(err)
resolve(cont)
})
})
}
<!-- generator -->
function * getCont () {
let name = yield read('name.js')
let address = yield read('address.js')
return name + address
}
<!-- 配合co库 -->
co(getCont()).then(function (cont) {
console.log(cont)
})
复制代码
简单的CO实现原理
-
co 的参数是一个迭代器
-
co 返回的是promise 返回的promise 接受 generator 函数的 value
-
co 内部可以使 generator 函数 一直执行到 done 为TRUE
function co(iterator) {
return new Promise(function (resolve, reject) {
function next(cont) {
let {value, done} = iterator.next(cont)
<!-- value 也是一个promise -->
if (done) {
<!-- 如果 done 为TRUE 则将value 传入 resolve -->
resolve(value)
} else {
<!-- done 为FALSE 则执行其then 方法 用于获取其data传递给 next -->
value.then(function (data) {
next(data)
<!-- next 递归 -->
}, reject)
}
}
next()
})
}
复制代码
async await
async await 可以看做 co + generator 的语法糖
虽然co库可以帮我们自行处理generator 但是又要使用yield 又要封装promise 也是有点麻烦 所以转向 ES7 中的 async await
目前 async await 在Bable, Node 7+ 中被支持
async function getCont() {
let people = await read('./file.js')
let who = await read('./who.js')
return people + who
}
getCont().then((data) => console.log(data))
复制代码
- async 返回 promise
await
await 顾名思义 等待。那他在等待什么呢。 这个取决于await 后面跟着的内容
await 'mxx'
<!-- 等待非promise -->
await IamPromise()
<!-- 等待 promise -->
复制代码
如果 await 等待的不是一个 promise 那么await表达式的运算结果就是 它等到的东西 (其实await会将其转为一个立即resolve的promise对象)
如果 await 等待的是promise 那么他会阻塞后面的代码 等着Promise 对象 resolve 然后得到其值作为 await表达式的运算结果
function getRank () {
return 12345
}
async function getType () {
let name = await read('who.js')
<!-- read为promise -->
console.log(name)
let rank = await getRank()
<!-- getRank 为普通函数 -->
console.log(rank)
}
复制代码
- 如果我们在普通函数中使用await会被阻塞吗
好吧~~ 直接报错了
错误捕获
async 中有两种错误处理方式
1 可以在 async 函数中 使用try catch
async 中对try catch方法做了处理 使其可以捕获异步的错误
async function () {
try {
} catch (e) {
console.log(e)
}
}
复制代码
2 在then中进行错误捕获
getCont().then().catch((e) => console.log(e))
复制代码
如果async函数中使用了try catch 那么后面的then方法将会进入成功态 【相当于promise返回的是 undefined 】