道可道,非常道——詳解promise
阿新 • • 發佈:2018-03-28
efi sym 上下 參與 else llb sta 捕獲異常 defined
promise 出來已久,以前一直使用,沒有仔細剖析原理,最近在復習es6的知識,寫一下自己對於promise的理解。
promise是es6的一種異步編程解決方案,避免頻繁的回調函數,增強代碼的可閱讀性。
寫法很簡單:
let p2 = new Promise((reslove, reject) => { reslove(1) }) console.log(p2.then(res => { alert(res) }))
Promise是內置的構造函數,reslove、reject是固定的,只能這麽寫。reslove()表示成功,reject()表示失敗。
方法:
- then() then是Promise的核心方法,是用來獲取異步的返回結果。有兩個參數用來獲取reslove 或 reject 的值。
- catch() 用來捕獲異常。
- all() 多個promise,所有的參與的promise對象全部執行完才會出結果。參數為類數組對象。
- race() 參數為類數組對象,任何一個參與的promise對象執行完,就會出結果。
以上為常用的四個方法。
代碼:
/* * * promise * 異步編程的一種解決方案。 * * */ const promise = new Promise(function (reslove, reject) { console.log(‘開始‘) setTimeout(function () { reslove(2) }, 3000) }) promise.then(function (value) { return 3; }).then(function (value) { }) // let p = new Promise((reslove, reject) => { setTimeout(()=>{ let a = Math.random(); if (a>0.5) { //reslove(a); // 這裏說白了是就是調用下面的then中的函數 a reslove.call(null, a) // 這樣也行 } else { reject(a) // 調用b } reject(a) // 調用b }, 1000) }) p.then(res => { // 假設這是函數a return res; }, rej => { // 函數b return rej; }).then(success => { // 鏈式調用的重點是前邊的then必須return 否則 為undefined return success; }, fail => { return fail; }) // then() then方法是掛在Promise.prototype上的 console.log(Promise.prototype) // Promise {constructor: ?, then: ?, catch: ?, finally: ?, Symbol(Symbol.toStringTag): "Promise"} // catch() 相當於 then(null, reject) p.then(rel => { console.log(rel) return rel; },rej => { console.log(rej + ‘小‘) return rej; }).then(rel => { // 前一個then返回成功或失敗都在這裏 因為執行catch()後返回一個新的實例該實例該實例執行完之後會變為reslove ,因此後邊的catch始終執行不到 console.log(rel) alert(2) }).catch(rej => { // 這句是走不到的 console.log(rej) alert(1) console.log(‘二小‘) }) // finally() 狀態成功或失敗 都會執行此操作 let p1 = new Promise((reslove, reject) => { console.log(this) // window 箭頭函數本身沒有this 因此this指向定義箭頭函數時的上下文 reslove(1); }) p1.then(res => { console.log(‘success‘) }).finally(res => { console.log(‘finally‘) }) // all() 所有實例的狀態都改變完才改變 let p2 = new Promise((reslove, reject) => { setTimeout(() => { alert(1) reslove(1) } ,1000) }) let p3 = new Promise((reslove, reject) => { setTimeout(() => { alert(2) reslove(2) } ,2000) }) let p4 = new Promise((reslove, reject) => { setTimeout(() => { alert(3) reject(3) } ,3000) }) Promise.all([p2, p3]).then(res => { console.log(res) // [1, 2] }) Promise.all([p2, p3, p4]).then(res => { console.log(res) }).catch(rej => { console.log(rej) // 3 只要有一個reject 就走這裏 不走上邊的then 返回的永遠是第一個reject的promise實例 }) // race() Promise.race([p2, p3]).then(res => { console.log(res) // 1 })
下面是手寫的實現promise的原理:
// 實現 promise function MyPromise(fn){ // fn 為 new Promise(fn) let _this = this; _this.status = ‘pending‘; _this.resloveValue = null; // 成功時的數據 _this.rejectValue = null; // 失敗時的數據 _this.resloveFnCallbacks = []; _this.rejectFnCallbacks = []; function reslove(value) { if (_this.status == ‘pending‘) { _this.status = ‘resloved‘; _this.resloveValue = value; _this.resloveFnCallbacks.forEach(fn => fn()) } } function reject(value) { if (_this.status == ‘pending‘) { _this.status = ‘rejected‘; _this.rejectValue = value; _this.rejectFnCallbacks.forEach(fn => fn()) } } // 捕獲異常 try{ fn(reslove, reject) } catch (e) { reject(e) } } // then() 應該接受兩個參數 成功 或 失敗的 回調 MyPromise.prototype.then = function (resloveFn, rejectFn) { let _this = this; let promise2; // then 返回的promise // 參數非函數轉為函數 resloveFn = typeof resloveFn === ‘function‘? resloveFn: (function (value) { return value; }) rejectFn = typeof rejectFn === ‘function‘? rejectFn: function (err) { throw err; } if(this.status == ‘resloved‘) { // 成功 alert(3) promise2 = new MyPromise((reslove, reject) => { setTimeout(() => { let x = resloveFn(this.resloveValue); resolvePromise(promise2, x, reslove, reject); }) }) } if(this.status == ‘rejected‘) { // 失敗 rejectFn(this.rejectValue) } if (this.status == ‘pending‘) { this.resloveFnCallbacks.push(function(){ resloveFn(_this.resloveValue) }) this.rejectFnCallbacks.push(function(){ rejectFn(_this.rejectValue) }) } return promise2; // resolvePromise function resolvePromise(promise2, x, reslove, reject) { let called; // 是否調用過 // 判斷上一次then返回的值 實質上下一個then只需要一個值便可以,所以我們就是要將上一個的peomise中的值提取出來 // then 返回promise只是為了鏈式調用,then本身需要一個實際的值,並不需要promise if (x != null && (typeof x === ‘object‘ || typeof x === ‘function‘)) { try { let then = x.then; // 保存x的then方法 這種是x是對象 if (typeof then === ‘function‘) { then.call(x, function (y) { if (called) return; called = true; resolvePromise(promise2, y, reslove, reject) }, function (rej) { if (called) return; called = true; reject(rej) }) } else { // x 是普通對象直接返回就行 reslove(x); } } catch (e) { if (called) return; called = true; reject(e) } } else { // x 是普通值 reslove(x) } } } // 將promise let p6 = new MyPromise(function(reslove, reject) { reslove(2) }) p6.then(function(res){ return res; }).then(function(res){ alert(res) })
參考鏈接:https://juejin.im/post/5ab20c58f265da23a228fe0f
道可道,非常道——詳解promise