1.什麼是Promise
Promise是非同步程式設計的一種解決方案,比回撥更合理更強大。從語法上來說,Promise是一個物件,從它可以獲取非同步操作的資訊。 Promise物件有以下兩個特點:
- 物件的狀態不受外界影響。Promise物件代表一個非同步操作,有三種狀態:pending、fulfilled和rejected。只有非同步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態
- 一旦狀態改變,就不會再改變。Promise物件的狀態的改變只有兩種可能 從pending變為fulfilled和從pending變為rejected
2.實現要點
1.promise的呼叫方式是鏈式呼叫,每次then方法會生成一個新的Promise例項
2.每個Promise例項自身維護一個回撥處理處理佇列。
3.具體實現
1.promise 建構函式 這一步將初始化Promise內部狀態,並立即執行executor
function Promise(executor) {
let self = this;
self.status = 'pending';
self.value = undefined;
self.reason = undefined;
self.onResolved = [];
self.onRejected = [];
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
複製程式碼
2.then函式
每次promise執行then後都會返回一個新的promise;每次返回新的Promise物件(因為promise狀態確定後 就是不能更改);then方方法中的成功或失敗是一個可選引數
onfulfilled = typeof onfulfilled == 'function' ? onfulfilled : val => val;
onrejected = typeof onrejected === 'function' ? onrejected : err => {
throw err;
}
let self = this;
let promise2;
promise2 = new Promise((resolve, reject) => {
if (self.status === 'resolved') {
setTimeout(() => {
try {
let x = onfulfilled(self.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (self.status === 'rejected') {
setTimeout(() => {
try {
let x = onrejected(self.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (self.status === 'pending') {
self.onResolved.push(function () {
setTimeout(() => {
try {
let x = onfulfilled(self.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
self.onRejected.push(function () {
setTimeout(() => {
try {
let x = onrejected(self.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
}
})
return promise2;
複製程式碼
3.catch函式
catch 會捕獲到沒有捕獲的異常
Promise.prototype.catch = function (onrejected) {
return this.then(null, onrejected)
}
複製程式碼
4.Promise相關方法實現
-
Promise.resolve
Promise.resolve(value)方法也會返回一個新的 Promise 例項,該例項的狀態為rejected。
Promise.resolve = function (value) { return new Promise((resolve, reject) => { resolve(value); }) } 複製程式碼
-
Promise.reject
Promise.reject(reason)方法也會返回一個新的 Promise 例項,該例項的狀態為rejected。
Promise.reject = function (reason) { return new Promise((resolve, reject) => { reject(reason) }) } 複製程式碼
-
Promise.race
const p = Promise.race([p1,p2,p3]) 複製程式碼
Promise.race方法同樣是將多個 Promise 例項,包裝成一個新的 Promise 例項。 上面程式碼中,只要p1、p2、p3之中有一個例項率先改變狀態,p的狀態就跟著改變。那個率先改變的 Promise 例項的返回值,就傳遞給p的回撥函式
Promise.race = function (promises) { return new Promise((resolve, reject) => { for (let i = 0; i < promises.length; i++) { let p = promises[i]; p.then(resolve, reject); } }) } 複製程式碼
4.Promise.all
Promise.all 方法用於將多個 Promise 例項,包裝成一個新的 Promise 例項。只有例項陣列中的例項狀態均變為 fulfilled,外層例項才會變成 fulfilled,此時例項陣列的返回值組成一個陣列,傳遞給外層例項的回撥函式。例項陣列中有一個被 rejected,外層例項的狀態就變成 rejected,此時第一個被 reject 的例項的返回值,會傳遞給外層例項的回撥函式。
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
let results = []; let i = 0;
function processData(index, data) {
results[index] = data;
if (++i === promises.length) {
resolve(results);
}
}
for (let i = 0; i < promises.length; i++) {
let p = promises[i];
p.then((data) => {
processData(i, data);
}, reject);
}
})
}
複製程式碼
結語
promise 可以解決回撥地獄的問題;多個非同步請求可以同步最終結果;程式碼寫起來更有流程感。 第一次寫文章,不太會寫,希望慢慢的會有進步,理解和思考問題也會更深層次。