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 】
上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。