异步流程处理
promise
promise 可以說是很常用的異步處理方法
比如我們使用promise封裝一個canvas截圖的方法
clip (resolve, reject) {// 截屏 獲取圖片urlreturn 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 = thisself.status = 'pending'self.success // 成功的原因self.failure // 失敗的原因// 事件池self.resolvePool = []self.rejectPool = []function resolve (data) {if (self.status == 'rejected') returnself.status = 'resolved'self.success = data// 執行隊列self.resolvePool.forEach(function (cb){cb(self.success)})}function reject (data) {if (self.status == 'resolved') returnself.status = 'rejected'self.failure = data// 執行隊列self.rejectPool.forEach(function (cb){cb(self.failure)})}// new一個實例就會立即執行這個promiseexecutor(resolve, reject) }// then Promise.prototype.then = function (onFulfilled, onRejected) {let self = thislet promiseStatus = self.statusif (promiseStatus == 'resolved') {onFulfilled(self.success)}if (promiseStatus == 'rejected') {onRejected(self.failure)}// 很有可能此時狀態為 pendingif (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 = 0let len = ary.lengthreturn {next: function () {// 調用next方法 返回 {value, done} 并且指針移動位置let done = ~~index == ~~len// 如果指針位置移動到末尾 則返回undefined 否則返回當前位置成員let value = done ? 'undefined' : ary[index]index++return {value, done}}} }復制代碼generator
- generator 函數生成一個迭代器
可以看到 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
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 】
相關資料
-
bluebird
-
promise A+
-
Tterator
-
async
-
await
總結
- 上一篇: AS 常用快捷键
- 下一篇: spring cloud学习进阶篇:Sp