Promise
是異步編程的一種解決方案,比傳統的異步解決方案【回調函數】和【事件】更合理、更強大。現已被 ES6 歸入進規範中;Promise
解決了「回調地獄」的痛點;Promise.length
length
屬性,其值老是爲 1 (構造器參數的數目).Promise.prototype
Promise
構造器的原型.Promise.resolve(value)
value
決定的Promise
對象。thenable
(即,帶有then
方法的對象),返回的Promise
對象的最終狀態由 then 方法執行決定;value
爲空,基本類型或者不帶then
方法的對象),返回的Promise
對象狀態爲fulfilled(resolved)
,而且將該value
傳遞給對應的then
方法;Promise
對象,使用Promise.resolve(value)
來返回一個Promise
對象,這樣就能將該value
以Promise
對象形式使用;Promise.reject(reason)
Promise
對象,並將給定的失敗信息傳遞給對應的處理方法Promise.race(iterable)
iterable
參數裏的任意一個子promise
被成功或失敗後(即第一個執行完的promise
),父promise
立刻也會用子promise
的成功返回值或失敗詳情做爲參數調用父promise
綁定的相應句柄,並返回該promise
對象Promise.allSettled(iterable)
promise
結果Promise.all(iterable)
promise
對象,promise
對象在iterable
參數對象裏全部的promise
對象都成功的時候纔會觸發成功iterable
裏面的promise
對象失敗則當即觸發該promise
對象的失敗promise
對象在觸發成功狀態之後,會把一個包含iterable
裏全部promise
返回值的數組做爲成功回調的返回值,順序跟iterable
的順序保持一致;promise
對象觸發了失敗狀態,它會把iterable
裏第一個觸發失敗的promise
對象的錯誤信息做爲它的失敗錯誤信息。Promise.all
方法常被用於處理多個promise
對象的狀態集合。Promise.prototype.constructor
Promise
函數Promise.prototype.then(onFulfilled, onRejected)
fulfillment
)和拒絕(rejection
)回調到當前 promise
, 返回一個新的 promise
, 將以回調的返回值來 resolve
;onFulfilled
中拋出的異常;Promise.prototype.catch(onRejected)
rejection
) 回調到當前 promise
, 返回一個新的promise
。promise
將以它的返回值來 resolve,不然若是當前promise
進入fulfilled
狀態,則以當前promise
的完成結果做爲新promise
的完成結果.Promise.prototype.finally(onFinally)
promise
對象,而且在原promise
對象解析完畢後,返回一個新的promise
對象。promise
運行完畢後被調用,不管當前promise
的狀態是完成(fulfilled
)仍是失敗(rejected
)• process.nextTick
和 promise.then
都屬於 微任務(microtask
),而 setImmediate
、setTimeout
、setInterval
屬於 宏任務(macrotask
),事件循環先執行宏任務,再執行全部微任務 • Promise
構造函數是同步執行的,promise.then
中的函數是異步執行的javascript
const promise = new Promise((resolve, reject) => {
// 構造函數同步執行
console.log(1);
resolve();
console.log(2);
});
promise.then(() => {
// 異步執行
console.log(3);
});
console.log(4);
// ------------執行結果-------------
1;
2;
4;
3;
複製代碼
promise
有 3 種狀態:pending
、resolved(fulfilled)
或 rejected
。狀態改變只能是 pending
->resolved
或者 pending
->rejected
,狀態一旦改變則不能再變。
pending
: 初始狀態,既不是成功,也不是失敗狀態。resolved
(fulfilled
): 意味着操做成功完成。rejected
: 意味着操做失敗。const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 1000)
});
const p2 = promise1.then(() => {
throw new Error('error!!!')
});
console.log('promise1', p1);
console.log('promise2', p2);
setTimeout(() => {
console.log('promise1', p1)
console.log('promise2', p2)
}, 2000);
// ------------執行結果-------------
promise1 Promise {<pending>}
promise2 Promise {<pending>}
Uncaught (in promise) Error: error!!!
at <anonymous>:7:9
Promise.then (async)
promise1 Promise {<resolved>: "success"}
promise2 Promise {<rejected>: Error: error!!!
at <anonymous>:7:9}
複製代碼
resolve
或 reject
只有第一次執行有效,屢次調用沒有任何做用new Promise((resolve, reject) => {
resolve("resolve1");
reject("reject");
resolve("resolve2");
})
.then((res) => {
console.log("then: ", res);
})
.catch((err) => {
console.log("catch: ", err);
});
// ------------執行結果-------------
then: resolve1;
複製代碼
promise
每次調用 .then
或者.catch
都會返回一個新的 promise
,從而實現了鏈式調用const p1 = Promise.resolve(1); // 返回 Promise
// 返回 Promise
const p2 = p1
.then((res) => {
console.log(res);
return 2;
})
.catch((err) => {
return 3;
});
// 返回 Promise
const p3 = p2.then((res) => {
console.log(res);
});
// ------------執行結果-------------
1;
2;
複製代碼
promise
的 .then
或者 .catch
能夠被調用屢次,但這裏 Promise
構造函數只執行一次。
promise
內部狀態一經改變,而且有了一個值,那麼後續每次調用 .then
或者 .catch
都會直接拿到該值const p5 = new Promise((resolve, reject) => {
// 構造函數只執行一次
setTimeout(() => {
console.log('start')
resolve('success'); // 第一次生效
resolve('success1'); // 執行無效
}, 1000)
})
p5.then((res) => {
console.log('promise1', res);
});
p5.then((res) => {
console.log('promise2', res)
});
// ------------執行結果-------------
start
promise1 success
promise2 success
複製代碼
.then
能夠接收兩個參數,第一個是處理成功的函數,第二個是處理錯誤的函數。
.catch
是 .then
第二個參數的簡便寫法;.then
的第二個處理錯誤的函數捕獲不了第一個處理成功的函數拋出的錯誤,然後續的 .catch
能夠捕獲以前的錯誤Promise.resolve().then(function success1 (res) {
throw new Error('error'); // 第一個 then 拋出 error 下一個 then 才能接收
}, function fail1 (e) {
console.error('error1: ', e)
}).then(function success2 (res) {}, function fail2 (e) {
// 接收上一個 then 拋出的 error
console.error('error2: ', e)
});
// ------------執行結果-------------
error2: Error: error
at success1 (<anonymous>:2:11) 複製代碼
.then
或者 .catch
的參數指望是函數,傳入非函數則會發生值穿透Promise.resolve(1)
.then(2) // 這一步會穿透
.then(Promise.resolve(3)) // 這裏 Promise.resolve(3) 爲 Promise 對象,這一步也會穿透
.then(console.log); // 這裏接收到第一次 resolve 的 1
// ------------執行結果-------------
1;
複製代碼
function Promise(fn) {}
// 中斷拋出結果集
Promise.resolve = function (value) {};
// 中斷拋出異常
Promise.reject = function (reason) {};
// 返回多個promise集合請求中最快返回的結果
Promise.race = function (iterable) {};
// 返回多個promise集合全部不論正常或者異常的結果集
Promise.allSettled = function (iterable) {};
// 返回多個promise集合全部正常的結果集,有錯誤則中斷返回該錯誤結果
Promise.all = function (iterable) {};
// 原型方法 then, 返回新的promise造成鏈式調用
Promise.prototype.then = function (onResolved, onRejected) {};
// 原型方法 catch, 拋出異常
Promise.prototype.catch = function (onError) {};
// 原型方法 promise 正常或者異常以後的最後一次處理
Promise.prototype.finally = function (onFinally) {};
複製代碼
function resolve(value) {
var _this = this;
// 狀態不爲 pending 則不執行,這裏避免屢次觸發
if (_this._status !== "pending") return;
setTimeout(function () {
_this._status = "fulfilled";
_this._value = value;
_this._onResolvedFns.forEach(function (cb) {
cb && cb();
});
});
}
function reject(error) {
var _this = this;
// 狀態不爲 pending 則不執行,這裏避免屢次觸發
if (_this._status !== "pending") return;
setTimeout(function () {
_this._status = "rejected";
_this._error = error;
_this._onRejectedFns.forEach(function (cb) {
cb && cb();
});
});
}
function isFunction(func) {
return typeof func === "function";
}
function isObject(func) {
return typeof func === "object";
}
function Promise(fn) {
if (!isObject(this)) {
throw new TypeError("Promise 必須是 new 實例化的對象");
}
if (!isFunction(fn)) {
throw new TypeError("Promise 構造函數入參必須是函數");
}
// 狀態 pending/fulfilled/rejected
this._status = "pending"; // 默認 pending
this._value = null; // 值
this._error = null; // 異常
// 成功的回調
this._onResolvedFns = [];
// 失敗的回調
this._onRejectedFns = [];
try {
// 綁定當前上下文
fn(resolve.bind(this), reject.bind(this));
} catch (e) {
reject(e);
}
}
複製代碼
Promise.prototype.then
鏈式回調/** * 解析 promise * 若回調爲 promise 實例,則繼續流式解析 * * @param {*} promise * @param {*} result 回調結果 * @param {*} resolve * @param {*} reject */
function resolvePromise(promise, result, resolve, reject) {
// 循環引用檢測
if (promise === result) return reject(new TypeError("循環引用"));
if (result instanceof Promise) {
result.then(function (newResult) {
resolvePromise(promise, newResult, resolve, reject);
}, reject);
} else if (isObject(result) || isFunction(result)) {
if (result === null) return resolve(result);
var then;
try {
then = result.then;
} catch (error) {
return reject(error);
}
if (!isFunction(then)) return resolve(result);
var called = false; // 調用鎖
try {
var _thenLock = function (cb) {
// 防止再次調用
if (called) return;
called = true; // 標記鎖
cb && cb();
};
// then 流式調用
then.call(
result,
function (nextResult) {
_thenLock(function () {
resolvePromise(promise, nextResult, resolve, reject);
});
},
function (r) {
//只要失敗了就失敗了
_thenLock(function () {
reject(r);
});
}
);
} catch (e) {
_thenLock(function () {
reject(e);
});
}
} else {
resolve(result);
}
}
// 原型方法 then, 返回新的promise造成鏈式調用
Promise.prototype.then = function (onResolved, onRejected) {
// then 接收兩個函數,若果不是函數則直接形成值穿透,即上一個 then 的值繼續向下走
onResolved = isFunction(onResolved)
? onResolved
: function (y) {
return y;
};
onRejected = isFunction(onRejected)
? onRejected
: function (err) {
throw err;
};
var _this = this;
var promise = new Promise(function (resolve, reject) {
if (_this._status === "pending") {
// pending 狀態
// 存放成功回調
_this._onResolvedFns.push(function () {
setTimeout(function () {
try {
resolvePromise(promise, onResolved(_this._value), resolve, reject);
} catch (error) {
reject(error);
}
});
});
// 存放失敗的回調
_this._onRejectedFns.push(function () {
setTimeout(function () {
try {
resolvePromise(promise, onRejected(_this._error), resolve, reject);
} catch (error) {
reject(error);
}
});
});
} else {
setTimeout(function () {
try {
// fulfilled / rejected 狀態 解析回調
resolvePromise(
promise,
_this._status === "fulfilled"
? onResolved(_this._value)
: onRejected(_this._error),
resolve,
reject
);
} catch (error) {
reject(error);
}
});
}
});
return promise;
};
複製代碼
Promise.prototype.catch
異常捕獲// 原型方法 catch, 拋出異常
Promise.prototype.catch = function (onError) {
// catch 方法就是then方法沒有成功的簡寫
return this.then(null, onError);
};
複製代碼
Promise.prototype.finally
結束調用// 原型方法 promise 正常或者異常以後的最後一次處理
Promise.prototype.finally = function (onFinally) {
var _finally = Promise.resolve(onFinally());
return this.then(
function (value) {
return _finally.then(function () {
return value;
});
},
function (error) {
return _finally.then(function () {
throw error;
});
}
);
};
複製代碼
Promise.resolve
// 中斷拋出結果集
Promise.resolve = function (value) {
return new Promise(function (resolve) {
resolve(value);
});
};
複製代碼
Promise.reject
// 中斷拋出異常
Promise.reject = function (reason) {
return new Promise(function (resolve, reject) {
reject(reason);
});
};
複製代碼
Promise.all
// 返回多個promise集合全部正常的結果集,有錯誤則中斷返回該錯誤結果
Promise.all = function (iterable) {
return new Promise(function (resolve, reject) {
var array = Array.prototype.slice.call(iterable);
if (!array.length) return resolve([]);
var results = [];
var count = 0;
for (var i = 0; i < array.length; i++) {
(function (i) {
Promise.resolve(array[i])
.then(function (res) {
results[i] = res;
count++;
if (count === array.length) {
resolve(results);
}
})
.catch(function (error) {
reject(error);
});
})(i);
}
});
};
複製代碼
Promise.race
// 返回多個promise集合請求中最快返回的結果
Promise.race = function (iterable) {
return new Promise(function (resolve, reject) {
// 淺拷貝
var array = Array.prototype.slice.call(iterable);
for (var i = 0; i < array.length; i++) {
Promise.resolve(array[i]).then(resolve, reject);
}
});
};
複製代碼
Promise.allSettled
// 返回多個promise集合全部不論正常或者異常的結果集
Promise.allSettled = function (iterable) {
return new Promise(function (resolve, reject) {
var array = Array.prototype.slice.call(iterable);
if (!array.length) return resolve([]);
var results = [];
var count = 0;
for (var i = 0; i < array.length; i++) {
(function (i) {
Promise.resolve(array[i]).finally(function (value) {
results[i] = res;
count++;
if (count === array.length) {
resolve(results);
}
});
})(i);
}
});
};
複製代碼
Promise/A+
測試promises-tests
測試包promise.spec.js
var Promise = require("./promise");
Promise.deferred = function () {
var result = {};
result.promise = new Promise(function (resolve, reject) {
result.resolve = resolve;
result.reject = reject;
});
return result;
};
module.exports = Promise;
複製代碼
promises-tests promise.spec.js
function resolve(value) {
var _this = this;
// 狀態不爲 pending 則不執行,這裏避免屢次觸發
if (_this._status !== "pending") return;
setTimeout(function () {
_this._status = "fulfilled";
_this._value = value;
_this._onResolvedFns.forEach(function (cb) {
cb && cb();
});
});
}
function reject(error) {
var _this = this;
// 狀態不爲 pending 則不執行,這裏避免屢次觸發
if (_this._status !== "pending") return;
setTimeout(function () {
_this._status = "rejected";
_this._error = error;
_this._onRejectedFns.forEach(function (cb) {
cb && cb();
});
});
}
function isFunction(func) {
return typeof func === "function";
}
function isObject(func) {
return typeof func === "object";
}
/** * 解析 promise * 若回調爲 promise 實例,則繼續流式解析 * * @param {*} promise * @param {*} result 回調結果 * @param {*} resolve * @param {*} reject */
function resolvePromise(promise, result, resolve, reject) {
// 循環引用檢測
if (promise === result) return reject(new TypeError("循環引用"));
if (result instanceof Promise) {
result.then(function (newResult) {
resolvePromise(promise, newResult, resolve, reject);
}, reject);
} else if (isObject(result) || isFunction(result)) {
if (result === null) return resolve(result);
var then;
try {
then = result.then;
} catch (error) {
return reject(error);
}
if (!isFunction(then)) return resolve(result);
var called = false; // 調用鎖
try {
var _thenLock = function (cb) {
// 防止再次調用
if (called) return;
called = true; // 標記鎖
cb && cb();
};
// then 流式調用
then.call(
result,
function (nextResult) {
_thenLock(function () {
resolvePromise(promise, nextResult, resolve, reject);
});
},
function (r) {
//只要失敗了就失敗了
_thenLock(function () {
reject(r);
});
}
);
} catch (e) {
_thenLock(function () {
reject(e);
});
}
} else {
resolve(result);
}
}
function Promise(fn) {
if (!isObject(this)) {
throw new TypeError("Promise 必須是 new 實例化的對象");
}
if (!isFunction(fn)) {
throw new TypeError("Promise 構造函數入參必須是函數");
}
// 狀態 pending/fulfilled/rejected
this._status = "pending"; // 默認 pending
this._value = null; // 值
this._error = null; // 異常
// 成功的回調
this._onResolvedFns = [];
// 失敗的回調
this._onRejectedFns = [];
try {
// 綁定當前上下文
fn(resolve.bind(this), reject.bind(this));
} catch (e) {
reject(e);
}
}
// 原型方法 then, 返回新的promise造成鏈式調用
Promise.prototype.then = function (onResolved, onRejected) {
// then 接收兩個函數,若果不是函數則直接形成值穿透,即上一個 then 的值繼續向下走
onResolved = isFunction(onResolved)
? onResolved
: function (y) {
return y;
};
onRejected = isFunction(onRejected)
? onRejected
: function (err) {
throw err;
};
var _this = this;
var promise = new Promise(function (resolve, reject) {
if (_this._status === "pending") {
// pending 狀態
// 存放成功回調
_this._onResolvedFns.push(function () {
setTimeout(function () {
try {
resolvePromise(promise, onResolved(_this._value), resolve, reject);
} catch (error) {
reject(error);
}
});
});
// 存放失敗的回調
_this._onRejectedFns.push(function () {
setTimeout(function () {
try {
resolvePromise(promise, onRejected(_this._error), resolve, reject);
} catch (error) {
reject(error);
}
});
});
} else {
setTimeout(function () {
try {
// fulfilled / rejected 狀態 解析回調
resolvePromise(
promise,
_this._status === "fulfilled"
? onResolved(_this._value)
: onRejected(_this._error),
resolve,
reject
);
} catch (error) {
reject(error);
}
});
}
});
return promise;
};
// 原型方法 catch, 拋出異常
Promise.prototype.catch = function (onError) {
// catch 方法就是then方法沒有成功的簡寫
return this.then(null, onError);
};
// 原型方法 promise 正常或者異常以後的最後一次處理
Promise.prototype.finally = function (onFinally) {
var _finally = Promise.resolve(onFinally());
return this.then(
function (value) {
return _finally.then(function () {
return value;
});
},
function (error) {
return _finally.then(function () {
throw error;
});
}
);
};
// 中斷拋出結果集
Promise.resolve = function (value) {
return new Promise(function (resolve) {
resolve(value);
});
};
// 中斷拋出異常
Promise.reject = function (reason) {
return new Promise(function (resolve, reject) {
reject(reason);
});
};
// 返回多個promise集合請求中最快返回的結果
Promise.race = function (iterable) {
return new Promise(function (resolve, reject) {
// 淺拷貝
var array = Array.prototype.slice.call(iterable);
for (var i = 0; i < array.length; i++) {
Promise.resolve(array[i]).then(resolve, reject);
}
});
};
// 返回多個promise集合全部不論正常或者異常的結果集
Promise.allSettled = function (iterable) {
return new Promise(function (resolve, reject) {
var array = Array.prototype.slice.call(iterable);
if (!array.length) return resolve([]);
var results = [];
var count = 0;
for (var i = 0; i < array.length; i++) {
(function (i) {
Promise.resolve(array[i]).finally(function (value) {
results[i] = res;
count++;
if (count === array.length) {
resolve(results);
}
});
})(i);
}
});
};
// 返回多個promise集合全部正常的結果集,有錯誤則中斷返回該錯誤結果
Promise.all = function (iterable) {
return new Promise(function (resolve, reject) {
var array = Array.prototype.slice.call(iterable);
if (!array.length) return resolve([]);
var results = [];
var count = 0;
for (var i = 0; i < array.length; i++) {
(function (i) {
Promise.resolve(array[i])
.then(function (res) {
results[i] = res;
count++;
if (count === array.length) {
resolve(results);
}
})
.catch(function (error) {
reject(error);
});
})(i);
}
});
};
module.exports = Promise;
複製代碼
以上是對 promise 的學習紀要,但願可以幫助到你們,若有不對的地方,但願你們不吝指正,謝謝。java