為啥要說 promise ? 因為這是前端必須要掌握的一個知識,吹逼必備 同學們,開始上課了! 首先說說 Promise 是什麼? Promise 是JavaScript的第一個非同步標準模型,一個包含傳遞信息與狀態的對象,emmm...它的英語意思是承諾. so 它擁有的特點也有承諾的意思(兄弟們, ...
為啥要說 promise ?
因為這是前端必須要掌握的一個知識,吹逼必備
同學們,開始上課了!
首先說說 Promise 是什麼?
Promise 是JavaScript的第一個非同步標準模型,一個包含傳遞信息與狀態的對象,emmm...它的英語意思是承諾.
so 它擁有的特點也有承諾的意思(兄弟們,拿好筆記本,劃重點):
- 對象的狀態不受外界影響,Promise 表示一個非同步的操作,它有三個狀態 Pending (進行時)、Reslove (已完成)、Rejected (失敗),只有非同步操作的結果,可以決定當前是哪一種狀態
- 一旦狀態改變就不會再接受改變,任何時候都可以得到這個結果。 Promise 對象的狀態改變,只有兩種可能,從 Pending 變為 Resolved 或者 Rejected。 只要這兩種情況發生,狀態就不會再改變了,就算狀態改變了,你再對 Promise 對象添加回調,也會立即得到結果,這和事件 event 不同,事件的特點是一點你錯過了它,再去監聽也不會得到結果的
那 Promise 為什麼會出現呢?
Promise 之前的非同步
先上一張圖讓大家感受下
Promise之前的時候,我們用三個手段解決非同步問題
- 回調函數
- 觀察者模式(又稱發佈訂閱模式)
- 事件機制
回調函數是最簡單的非同步方式,它比較容易理解和部署,也是我們最常使用的,但是缺點也很明顯,不利於代碼的閱讀和維護,流程混亂。
觀察者模式和事件機制不多說,就是適用於多次同類型的非同步,不適用一次性的非同步
而 Promise 可以將非同步操作以同步操作的流程表達出來,
- 避免了層層回調函數。
- 如果使用回調函數, 你並不能知道對方是否執行你的回調函數,或太晚太早執行
- 錯誤也是非同步,會隱式傳遞給reject
老哥,說了這麼多,怎麼用啊?
先來個最簡單的Prmise
const p = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('你好,兄弟') //設置成resolve狀態 即是成功
},1e3)
})
p.then(res=>{
console.log(res) // 1s後輸出 ==> 你好,兄弟
})
是不是看起來 so easy ?
下麵我們來實現一下最簡單的 Promise。 Promise只是一個普通的構造函數,用es3的語法也可以實現
所以在ie6都可以用,不過我們就使用es6的class來實現了
class myPromise {
constructor(fn) {
this.state = 'PENDING';
this.message = '';
this.fns = [];
fn(this.resolve.bind(this), this.reject.bind(this));
}
resolve(res) {
this.state = 'FULFILLED';
this.message = res;
this._onChange();
}
reject(err) {
this.state = 'REJECTED';
this.message = err;
this._onChange();
}
then(onResolved, onRejected) {
let self = this;
return new myPromise((resolve, reject) => {
self.fns.push([onResolved, onRejected, resolve, reject]);
self._onChange();
});
}
_onChange() {
this.state !== 'PENDING' &&
this.fns.forEach(v => {
this._change(v);
});
}
_change(arr) {
let onResolved = arr[0],
onRejected = arr[1],
resolve = arr[2],
reject = arr[3];
switch (this.state) {
case 'FULFILLED':
if (typeof onResolved === 'function') {
resolve(onResolved.call(null, this.message));
} else {
resolve(this.message);
}
break;
case 'REJECTED':
if (typeof onRejected === 'function') {
resolve(onRejected.call(null, this.message));
} else {
reject(this.message);
}
break;
default:
break;
}
}
}
//老哥們註意,這隻是我自己寫的一個簡略的 Promise , 並不是真正的 Promise 的實現
const p = new myPromise((resolve, reject) => {
setTimeout(() => {
resolve('你好,兄弟'); //1s後設置成resolve狀態 即是成功
}, 1e3);
});
p.then(res => {
console.log(res); // 1s後輸出 ==> 你好,兄弟
return '1';
})
.then(res => {
console.log(res); // 1s後輸出 ==> '1'
})
.then(res => {
console.log(res); // 1s後輸出 ==> undefined
});
Promise.resolve / reject
Promise 還提供一個快速實例化 Promise ,可以傳入參數並且馬上觸發 Promise 鏈的執行
Promise.resolve = data =>
new Promise((resolve, reject) => {
resolve(data);
});
Promise.reject = err =>
new Promise((resolve, reject) => {
reject(err);
});
Promise.all / race
Promise 還提供 all / race 用來處理數據的併發和競爭,要求是傳一個 Promise 數組作為參數,然後返回一個新的 Promise
all 是全部處理後再統一處理
Promise.all = arr =>
new Promise((resolve, reject) => {
let c = 0,
l = arr.length,
result = [];
l === 0 && resolve(result);
arr.forEach(pro => {
Promise.resolve(pro).then(res => {
result.push(res);
c++;
c === l && resolve(result);
},
err => {
reject(err);
}
);
});
});
race 則是誰非同步時間短誰就會被處理
Promise.race = arr =>
new Promise((resolve, reject) => {
arr.forEach(pro => {
Promise.resolve(pro).then(resolve, reject);
});
});
Promise.then / catch
Promise 的 then 函數我們也知道是怎麼用的,它始終以當前的結果返回一個新的Promise
而之前我們說到 Promise 的錯誤是非同步的 也直接調用到 reject,
那我們在 resolve 或者 reject 出現錯誤應該怎麼做呢? Promise 還提供一個catch 用來捕捉錯誤
Promise.catch = reject => this.then(undefined,reject)
怎麼用呢?
const p = new Promise((resolve, reject) => {
//執行操作
//..略
});
p.then(resolve, reject)
.then(resolve, reject)
.then(resolve, reject)
.catch(err => {
//如果以上出現錯誤會直接傳遞到此處執行錯誤處理
});
Promise 和 setTimeout
說是非同步,那麼和我們最原始的 setTimeout 有什麼區別呢?
先讓我們看一道面試題目
console.log('a');
setTimeout(() => {
console.log('b');
});
console.log('c');
new Promise((resolve, reject) => {
console.log('d');
resolve('e');
}).then(res => {
console.log(res);
});
console.log('f');
輸出順序是什麼呢 ?
a => c => d => f => e => b
這裡就要關係到js的 EventLoop 機制了,這裡並不細說,只是拋個引子,有興趣的朋友可以去看看相關文章
結尾
到這裡就結束了,老哥們,要去搬磚了
如果發現文章有什麼問題,可以留言哦