js進階教程之promise全方位解析和異步編程
Promise 是 JavaScript 異步編程的核心解決方案,也是前端工程師進階必備的核心知識點。本文將全方位介紹 Promise,涵蓋從基礎(chǔ)概念到高級應(yīng)用,再到面試實戰(zhàn)的全鏈路知識。
一、Promises/A+ 規(guī)范基礎(chǔ)
1. Promise 的狀態(tài)
Promise 是一個??狀態(tài)機??,有且僅有三種狀態(tài):
- ??pending(等待中)??:初始狀態(tài),既不是成功也不是失敗。
- ??fulfilled(已成功)??:操作成功完成,通過
resolve()觸發(fā)。 - ??rejected(已失?。??:操作失敗,通過
reject()觸發(fā)。
?? ??狀態(tài)不可逆??:一旦從 pending 變?yōu)?fulfilled 或 rejected,狀態(tài)將永久固定,不可再次改變。
2. then 方法:核心機制
then是 Promise 的核心方法,用于注冊狀態(tài)變更后的回調(diào)函數(shù):
- ??接收兩個回調(diào)??:
- 第一個參數(shù):
onFulfilled(狀態(tài)變?yōu)?fulfilled 時執(zhí)行)。 - 第二個參數(shù):
onRejected(狀態(tài)變?yōu)?rejected 時執(zhí)行,可選)。
- 第一個參數(shù):
- ?回調(diào)返回值?
若回調(diào)返回普通值(非 Promise),則新 Promise 以該值 fulfilled。
- 若回調(diào)拋出異常,則新 Promise 以該異常 rejected。
- 若回調(diào)返回另一個 Promise,則當前 Promise 會??跟隨該返回 Promise 的狀態(tài)??(鏈式調(diào)用的核心)。
const p = new Promise((resolve) => resolve(10));
p.then(
(value) => {
console.log(value); // 10(onFulfilled 回調(diào))
return value * 2; // 返回普通值 → 新 Promise 以 20 fulfilled
},
(err) => console.error(err) // 不會執(zhí)行(原 Promise 未失?。?
).then((newValue) => {
console.log(newValue); // 20(跟隨返回的隱式 Promise)
});3. Promise 解析過程(核心機制)
當 then的回調(diào)返回一個 ??新的 Promise(記作 P)?? 時,當前 Promise 會暫停自身的狀態(tài)變更,轉(zhuǎn)而??監(jiān)聽 P 的狀態(tài)??:
- 若 P 變?yōu)?fulfilled,則當前 Promise 以 P 的結(jié)果 fulfilled;
- 若 P 變?yōu)?rejected,則當前 Promise 以 P 的錯誤 rejected。
?? ??鏈式調(diào)用的本質(zhì)??:通過解析過程實現(xiàn)多個異步操作的依次執(zhí)行(前一個操作的結(jié)果作為下一個操作的輸入)。
二、傳統(tǒng)異步任務(wù)處理的痛點
1. 回調(diào)函數(shù)模式
早期 JavaScript 通過嵌套回調(diào)處理異步(例如 AJAX 請求):
getData(function(result1) {
processResult1(result1, function(result2) {
saveResult2(result2, function(result3) {
// 嵌套層級加深 → 代碼難以維護
});
});
});2. 回調(diào)地獄(Callback Hell)
多層嵌套回調(diào)會導致代碼橫向擴展(縮進層級過深),出現(xiàn)“金字塔”結(jié)構(gòu)的代碼,可讀性差、錯誤處理困難、難以復用邏輯。
?? ??Promise 的誕生??:為了解決回調(diào)地獄問題,提供更扁平化的異步代碼組織方式。
三、Promise 詳解
1. 什么是 Promise?
- ??本質(zhì)??:一個構(gòu)造函數(shù)(類),通過
new Promise(executor)實例化。 - 核心機制??:
- executor 是一個同步執(zhí)行的回調(diào)函數(shù),接收兩個參數(shù):
resolve(標記成功)和reject(標記失敗)。 - Promise 內(nèi)部通過狀態(tài)機管理異步操作的結(jié)果,外部通過
then/catch/finally監(jiān)聽狀態(tài)變更。
- executor 是一個同步執(zhí)行的回調(diào)函數(shù),接收兩個參數(shù):
const promise = new Promise((resolve, reject) => {
setTimeout(() => resolve('異步操作成功'), 1000); // 1秒后標記成功
});2. resolve 的參數(shù)規(guī)則
resolve可接受多種類型的參數(shù),處理邏輯不同:
參數(shù)類型 | 行為 |
|---|---|
普通值(如字符串、數(shù)字) | 當前 Promise 以該值 fulfilled。 |
另一個 Promise | 當前 Promise 會跟隨該 Promise 的狀態(tài)(鏈式調(diào)用的基礎(chǔ))。 |
Thenable 對象(含 then 方法的對象) | 會嘗試調(diào)用其 then 方法,將其轉(zhuǎn)換為標準 Promise 行為。 |
// 示例 1:普通值
Promise.resolve(42).then(v => console.log(v)); // 42
// 示例 2:返回另一個 Promise
Promise.resolve(Promise.resolve('嵌套 Promise')).then(v => console.log(v)); // 嵌套 Promise
// 示例 3:Thenable 對象
const thenable = { then(resolve) { resolve('Thenable 轉(zhuǎn)換成功'); } };
Promise.resolve(thenable).then(v => console.log(v)); // Thenable 轉(zhuǎn)換成功3. Promise 的實例方法
(1) then 方法
- ??參數(shù)??:
onFulfilled(成功回調(diào),可選)、onRejected(失敗回調(diào),可選)。 - ??返回值??:一個新的 Promise(支持鏈式調(diào)用)。
- ??回調(diào)返回值??:決定新 Promise 的狀態(tài)(如返回普通值、Promise 或拋出異常)。
Promise.resolve(1) .then(val => val + 1) // 返回普通值 2 → 新 Promise 以 2 fulfilled .then(val => console.log(val)); // 2
(2) 多次調(diào)用 then
- 每次調(diào)用
then都會注冊新的回調(diào),??按注冊順序依次執(zhí)行??(即使前一個回調(diào)異步延遲)。 - 多個
then可以分別處理同一 Promise 的成功狀態(tài)。
const p = Promise.resolve(10); p.then(v => console.log(v)); // 10 p.then(v => console.log(v + 5)); // 15
(3) catch 方法
- ??作用??:專門捕獲 Promise 鏈中的錯誤(相當于
then(null, onRejected))。 - ??參數(shù)??:錯誤處理回調(diào)(接收錯誤對象)。
- ??特性??:可捕獲當前 Promise 或鏈中上游未處理的 rejected 狀態(tài)。
Promise.reject(new Error('操作失敗'))
.catch(err => console.error('捕獲錯誤:', err.message)); // 捕獲錯誤: 操作失敗(4) finally 方法
- ??作用??:無論 Promise 成功或失敗,都會執(zhí)行的清理邏輯(如關(guān)閉加載動畫)。
- ??參數(shù)??:無參數(shù)回調(diào)(無法獲取 Promise 的結(jié)果或錯誤)。
- ??特性??:不會改變原 Promise 的狀態(tài)或結(jié)果。
Promise.resolve('成功')
.finally(() => console.log('無論如何都會執(zhí)行')) // 無論如何都會執(zhí)行
.then(v => console.log(v)); // 成功4. Promise 的類方法
(1) Promise.resolve / Promise.reject
- ??作用??:快速創(chuàng)建已 resolved/rejected 的 Promise。
- ??參數(shù)??:與
resolve/reject方法一致。
Promise.resolve('直接成功').then(v => console.log(v)); // 直接成功
Promise.reject('直接失敗').catch(e => console.error(e)); // 直接失敗(2) Promise.all
- ??作用??:并行執(zhí)行多個 Promise,??全部成功時返回結(jié)果數(shù)組??,??任一失敗立即 rejected??。
- ??參數(shù)??:Promise 數(shù)組。
- 適用場景??:同時發(fā)起多個獨立異步請求,需全部完成后再處理結(jié)果。
Promise.all([
Promise.resolve(1),
Promise.resolve(2),
]).then(([res1, res2]) => console.log(res1, res2)); // 1 2
Promise.all([
Promise.resolve(1),
Promise.reject('失敗'),
]).catch(e => console.error(e)); // 失敗(3) Promise.allSettled
- 作用??:并行執(zhí)行多個 Promise,??等待所有完成(無論成功/失?。??,返回每個 Promise 的狀態(tài)和結(jié)果。
- ??參數(shù)??:Promise 數(shù)組。
- ??適用場景??:需要知道所有異步操作的最終狀態(tài)(如批量提交后統(tǒng)計成功/失敗數(shù)量)。
Promise.allSettled([
Promise.resolve(1),
Promise.reject('失敗'),
]).then(results => {
results.forEach(r => console.log(r.status, r.value || r.reason));
// fulfilled 1
// rejected 失敗
});(4) Promise.race
- ??作用??:并行執(zhí)行多個 Promise,??返回第一個 settled(成功/失?。┑?Promise 結(jié)果??。
- ??參數(shù)??:Promise 數(shù)組。
- 適用場景??:超時控制(如請求超時后取消操作)。
Promise.race([
Promise.resolve('快的'),
new Promise(resolve => setTimeout(() => resolve('慢的'), 1000)),
]).then(v => console.log(v)); // 快的(5) Promise.any
- ??作用??:并行執(zhí)行多個 Promise,??返回第一個成功的 Promise 結(jié)果??,??全部失敗時拋出 AggregateError??。
- ??參數(shù)??:Promise 數(shù)組。
- ??適用場景??:多備用數(shù)據(jù)源(如主接口失敗后嘗試備用接口)。
Promise.any([
Promise.reject('失敗1'),
Promise.resolve('成功'),
]).then(v => console.log(v)); // 成功四、手寫 Promise 實現(xiàn)(核心邏輯)
手寫 Promise 是深入理解其原理的最佳方式,需實現(xiàn)以下核心方法(可通過 Jest 編寫單元測試驗證):
- ??構(gòu)造函數(shù)(constructor)??:接收 executor,管理狀態(tài)和結(jié)果。
- ??then/catch/finally??:注冊回調(diào)并處理鏈式調(diào)用。
- 類方法(resolve/reject/all/allSettled/race/any)??:靜態(tài)工具方法。
?? ??關(guān)鍵點??:狀態(tài)不可逆、then 的鏈式調(diào)用(返回新 Promise)、異步執(zhí)行回調(diào)(通過微任務(wù)隊列,如
queueMicrotask)。
下面是一個完整的手寫 Promise 實現(xiàn)(支持 Promises/A+ 規(guī)范),包含核心方法(constructor、then、catch、finally)及靜態(tài)方法(resolve、reject、all、allSettled、race、any),并附帶對應(yīng)的 Jest 單元測試代碼。
1.Promise 實現(xiàn) (myPromise.js)
// 定義 Promise 的三種狀態(tài)
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MyPromise {
constructor(executor) {
this.state = PENDING; // 初始狀態(tài)為 pending
this.value = undefined; // 成功時的值
this.reason = undefined; // 失敗時的原因
this.onFulfilledCallbacks = []; // 成功的回調(diào)隊列
this.onRejectedCallbacks = []; // 失敗的回調(diào)隊列
// 定義 resolve 函數(shù)
const resolve = (value) => {
// 只有 pending 狀態(tài)可以改變
if (this.state === PENDING) {
this.state = FULFILLED;
this.value = value;
// 執(zhí)行所有成功的回調(diào)
this.onFulfilledCallbacks.forEach(fn => fn());
}
};
// 定義 reject 函數(shù)
const reject = (reason) => {
// 只有 pending 狀態(tài)可以改變
if (this.state === PENDING) {
this.state = REJECTED;
this.reason = reason;
// 執(zhí)行所有失敗的回調(diào)
this.onRejectedCallbacks.forEach(fn => fn());
}
};
try {
// 立即執(zhí)行 executor
executor(resolve, reject);
} catch (error) {
// 如果 executor 執(zhí)行出錯,直接 reject
reject(error);
}
}
// then 方法
then(onFulfilled, onRejected) {
// 處理 then 的參數(shù)不是函數(shù)的情況
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason; };
// 返回一個新的 Promise 以實現(xiàn)鏈式調(diào)用
const promise2 = new MyPromise((resolve, reject) => {
// 如果狀態(tài)是 fulfilled
if (this.state === FULFILLED) {
// 使用 setTimeout 模擬微任務(wù)
setTimeout(() => {
try {
const x = onFulfilled(this.value);
// 解析 promise2 和 x 的關(guān)系
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
} else if (this.state === REJECTED) {
// 如果狀態(tài)是 rejected
setTimeout(() => {
try {
const x = onRejected(this.reason);
// 解析 promise2 和 x 的關(guān)系
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
} else if (this.state === PENDING) {
// 如果狀態(tài)是 pending,將回調(diào)函數(shù)存入隊列
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
}
});
return promise2;
}
// 解析 promise 和 x 的關(guān)系
resolvePromise(promise2, x, resolve, reject) {
// 如果 promise2 和 x 是同一個對象,拋出 TypeError
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
// 如果 x 是一個 Promise
if (x instanceof MyPromise) {
x.then(resolve, reject);
} else {
// 如果 x 是一個普通值
resolve(x);
}
}
// catch 方法
catch(onRejected) {
return this.then(null, onRejected);
}
// finally 方法
finally(callback) {
return this.then(
value => MyPromise.resolve(callback()).then(() => value),
reason => MyPromise.resolve(callback()).then(() => { throw reason; })
);
}
// 靜態(tài) resolve 方法
static resolve(value) {
// 如果 value 是一個 Promise,直接返回
if (value instanceof MyPromise) {
return value;
}
// 否則返回一個新的 resolved Promise
return new MyPromise(resolve => resolve(value));
}
// 靜態(tài) reject 方法
static reject(reason) {
return new MyPromise((_, reject) => reject(reason));
}
// 靜態(tài) all 方法
static all(promises) {
return new MyPromise((resolve, reject) => {
const results = [];
let completed = 0;
const promiseCount = promises.length;
if (promiseCount === 0) {
resolve(results);
return;
}
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
value => {
results[index] = value;
completed++;
if (completed === promiseCount) {
resolve(results);
}
},
reason => {
reject(reason);
}
);
});
});
}
// 靜態(tài) allSettled 方法
static allSettled(promises) {
return new MyPromise((resolve) => {
const results = [];
let completed = 0;
const promiseCount = promises.length;
if (promiseCount === 0) {
resolve(results);
return;
}
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
value => {
results[index] = { status: FULFILLED, value };
completed++;
if (completed === promiseCount) {
resolve(results);
}
},
reason => {
results[index] = { status: REJECTED, reason };
completed++;
if (completed === promiseCount) {
resolve(results);
}
}
);
});
});
}
// 靜態(tài) race 方法
static race(promises) {
return new MyPromise((resolve, reject) => {
promises.forEach(promise => {
MyPromise.resolve(promise).then(resolve, reject);
});
});
}
// 靜態(tài) any 方法
static any(promises) {
return new MyPromise((resolve, reject) => {
const errors = [];
let rejectedCount = 0;
const promiseCount = promises.length;
if (promiseCount === 0) {
reject(new AggregateError(errors, 'All promises were rejected'));
return;
}
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
value => {
resolve(value);
},
reason => {
errors[index] = reason;
rejectedCount++;
if (rejectedCount === promiseCount) {
reject(new AggregateError(errors, 'All promises were rejected'));
}
}
);
});
});
}
}
module.exports = MyPromise;2.Jest 單元測試 (myPromise.test.js)
const MyPromise = require('./myPromise');
describe('MyPromise', () => {
// 測試構(gòu)造函數(shù)和基本功能
describe('Constructor', () => {
test('should execute executor immediately', () => {
let executed = false;
new MyPromise(() => {
executed = true;
});
expect(executed).toBe(true);
});
test('should handle resolve in executor', (done) => {
new MyPromise((resolve) => {
resolve('success');
}).then((value) => {
expect(value).toBe('success');
done();
});
});
test('should handle reject in executor', (done) => {
new MyPromise((_, reject) => {
reject('error');
}).catch((reason) => {
expect(reason).toBe('error');
done();
});
});
test('should catch executor errors', (done) => {
new MyPromise(() => {
throw new Error('executor error');
}).catch((error) => {
expect(error.message).toBe('executor error');
done();
});
});
});
// 測試 then 方法
describe('then', () => {
test('should handle fulfilled promise', (done) => {
new MyPromise((resolve) => {
resolve('fulfilled');
}).then((value) => {
expect(value).toBe('fulfilled');
done();
});
});
test('should handle rejected promise', (done) => {
new MyPromise((_, reject) => {
reject('rejected');
}).then(null, (reason) => {
expect(reason).toBe('rejected');
done();
});
});
test('should chain then calls', (done) => {
new MyPromise((resolve) => {
resolve(1);
})
.then((value) => {
expect(value).toBe(1);
return value + 1;
})
.then((value) => {
expect(value).toBe(2);
return value + 1;
})
.then((value) => {
expect(value).toBe(3);
done();
});
});
test('should handle async then callbacks', (done) => {
let first = false;
new MyPromise((resolve) => {
resolve(1);
})
.then((value) => {
first = true;
return value + 1;
})
.then((value) => {
expect(first).toBe(true);
expect(value).toBe(2);
done();
});
});
test('should use default onFulfilled if not a function', (done) => {
new MyPromise((resolve) => {
resolve(1);
}).then(null).then((value) => {
expect(value).toBe(1);
done();
});
});
test('should use default onRejected if not a function', (done) => {
new MyPromise((_, reject) => {
reject(1);
}).then(null, null).catch((reason) => {
expect(reason).toBe(1);
done();
});
});
});
// 測試 catch 方法
describe('catch', () => {
test('should catch rejected promise', (done) => {
new MyPromise((_, reject) => {
reject('error');
}).catch((reason) => {
expect(reason).toBe('error');
done();
});
});
test('should chain catch calls', (done) => {
new MyPromise((_, reject) => {
reject('first error');
})
.catch((reason) => {
expect(reason).toBe('first error');
return 'recovered';
})
.then((value) => {
expect(value).toBe('recovered');
done();
});
});
});
// 測試 finally 方法
describe('finally', () => {
test('should execute finally callback', (done) => {
let called = false;
new MyPromise((resolve) => {
resolve('value');
})
.finally(() => {
called = true;
})
.then((value) => {
expect(called).toBe(true);
expect(value).toBe('value');
done();
});
});
test('should pass through value', (done) => {
new MyPromise((resolve) => {
resolve('value');
})
.finally(() => {})
.then((value) => {
expect(value).toBe('value');
done();
});
});
test('should pass through reason', (done) => {
new MyPromise((_, reject) => {
reject('reason');
})
.finally(() => {})
.catch((reason) => {
expect(reason).toBe('reason');
done();
});
});
test('should handle finally callback with return value', (done) => {
new MyPromise((resolve) => {
resolve(1);
})
.finally(() => {
return 2;
})
.then((value) => {
expect(value).toBe(1);
done();
});
});
test('should handle finally callback with promise', (done) => {
new MyPromise((resolve) => {
resolve(1);
})
.finally(() => {
return new MyPromise((resolve) => {
resolve(2);
});
})
.then((value) => {
expect(value).toBe(1);
done();
});
});
});
// 測試靜態(tài)方法 resolve
describe('static resolve', () => {
test('should resolve with a value', (done) => {
MyPromise.resolve('value').then((value) => {
expect(value).toBe('value');
done();
});
});
test('should resolve with a promise', (done) => {
const p = new MyPromise((resolve) => {
resolve('promise value');
});
MyPromise.resolve(p).then((value) => {
expect(value).toBe('promise value');
done();
});
});
});
// 測試靜態(tài)方法 reject
describe('static reject', () => {
test('should reject with a reason', (done) => {
MyPromise.reject('reason').catch((reason) => {
expect(reason).toBe('reason');
done();
});
});
});
// 測試靜態(tài)方法 all
describe('static all', () => {
test('should resolve with an array of values', (done) => {
const p1 = MyPromise.resolve(1);
const p2 = MyPromise.resolve(2);
const p3 = MyPromise.resolve(3);
MyPromise.all([p1, p2, p3]).then((values) => {
expect(values).toEqual([1, 2, 3]);
done();
});
});
test('should reject if any promise rejects', (done) => {
const p1 = MyPromise.resolve(1);
const p2 = MyPromise.reject('error');
const p3 = MyPromise.resolve(3);
MyPromise.all([p1, p2, p3]).catch((reason) => {
expect(reason).toBe('error');
done();
});
});
test('should resolve with empty array', (done) => {
MyPromise.all([]).then((values) => {
expect(values).toEqual([]);
done();
});
});
});
// 測試靜態(tài)方法 allSettled
describe('static allSettled', () => {
test('should resolve with all settled results', (done) => {
const p1 = MyPromise.resolve(1);
const p2 = MyPromise.reject('error');
const p3 = MyPromise.resolve(3);
MyPromise.allSettled([p1, p2, p3]).then((results) => {
expect(results).toEqual([
{ status: 'fulfilled', value: 1 },
{ status: 'rejected', reason: 'error' },
{ status: 'fulfilled', value: 3 }
]);
done();
});
});
test('should resolve with empty array', (done) => {
MyPromise.allSettled([]).then((results) => {
expect(results).toEqual([]);
done();
});
});
});
// 測試靜態(tài)方法 race
describe('static race', () => {
test('should resolve with the first resolved promise', (done) => {
const p1 = new MyPromise((resolve) => {
setTimeout(() => resolve(1), 100);
});
const p2 = MyPromise.resolve(2);
MyPromise.race([p1, p2]).then((value) => {
expect(value).toBe(2);
done();
});
});
test('should reject with the first rejected promise', (done) => {
const p1 = new MyPromise((_, reject) => {
setTimeout(() => reject('error'), 100);
});
const p2 = MyPromise.reject('quick error');
MyPromise.race([p1, p2]).catch((reason) => {
expect(reason).toBe('quick error');
done();
});
});
});
// 測試靜態(tài)方法 any
describe('static any', () => {
test('should resolve with the first resolved promise', (done) => {
const p1 = new MyPromise((resolve) => {
setTimeout(() => resolve(1), 100);
});
const p2 = MyPromise.resolve(2);
MyPromise.any([p1, p2]).then((value) => {
expect(value).toBe(2);
done();
});
});
test('should reject with all rejected promises if all are rejected', (done) => {
const p1 = MyPromise.reject('error1');
const p2 = MyPromise.reject('error2');
MyPromise.any([p1, p2]).catch((error) => {
expect(error.errors).toEqual(['error1', 'error2']);
expect(error.message).toBe('All promises were rejected');
done();
});
});
test('should reject with AggregateError if all are rejected', (done) => {
const p1 = MyPromise.reject('error1');
const p2 = MyPromise.reject('error2');
MyPromise.any([p1, p2]).catch((error) => {
expect(error instanceof Error).toBe(true);
expect(error.message).toBe('All promises were rejected');
// 注意:這里簡化了 AggregateError 的實現(xiàn),實際可能需要更復雜的檢查
done();
});
});
});
});使用說明
- 將 Promise 實現(xiàn)代碼保存為
myPromise.js - 將測試代碼保存為
myPromise.test.js - 確保已安裝 Jest (
npm install --save-dev jest) - 在 package.json 中添加測試腳本:
"scripts": {
"test": "jest"
} 5. 運行測試:npm test
實現(xiàn)說明
這個 Promise 實現(xiàn)包含了以下特性:
- 基本功能??:
- 三種狀態(tài):pending、fulfilled、rejected
- 構(gòu)造函數(shù)接收 executor 函數(shù)
- 異步執(zhí)行回調(diào)(使用 setTimeout 模擬微任務(wù))
- 實例方法??:
then(): 支持鏈式調(diào)用,處理成功和失敗情況catch(): 捕獲錯誤finally(): 無論成功失敗都會執(zhí)行
- ??靜態(tài)方法??:
resolve(): 創(chuàng)建一個已解決的 Promisereject(): 創(chuàng)建一個已拒絕的 Promiseall(): 所有 Promise 都成功時返回結(jié)果數(shù)組allSettled(): 所有 Promise 都完成后返回結(jié)果狀態(tài)數(shù)組race(): 返回第一個完成的 Promise 結(jié)果any(): 返回第一個成功的 Promise,或所有都失敗時拋出錯誤
五、async/await 介紹
1. 特點
- ??語法糖??:基于 Promise 的語法糖,讓異步代碼看起來像同步代碼。
- 本質(zhì)??:
async函數(shù)返回 Promise,await用于暫停執(zhí)行直到 Promise 完成。
2. 用法
async function fetchData() {
try {
const result = await Promise.resolve('異步數(shù)據(jù)'); // 等待 Promise 完成
console.log(result); // 異步數(shù)據(jù)
} catch (err) {
console.error(err);
}
}
fetchData();3. 適用場景
- 需要按順序執(zhí)行多個異步操作(如先請求用戶信息,再請求訂單詳情)。
- 替代復雜的 Promise 鏈(提升代碼可讀性)。
4. 與 Promise 對比
特性 | async/await | Promise |
|---|---|---|
代碼風格 | 類似同步代碼,更直觀 | 鏈式調(diào)用,需嵌套 then/catch |
錯誤處理 | 使用 try/catch | 使用 catch 方法 |
可讀性 | 高(邏輯線性) | 較低(嵌套層級深時) |
底層原理 | 基于 Promise | JavaScript 原生異步解決方案 |
六、Promise 相關(guān)面試題目
1. 經(jīng)典面試題:Promise 與事件循環(huán)
??題目??:分析以下代碼的輸出順序(結(jié)合宏任務(wù)與微任務(wù)):
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');解題思路??:
- 同步代碼優(yōu)先執(zhí)行??:輸出
1→4。 - ??微任務(wù)(Promise.then)??:在當前宏任務(wù)結(jié)束后立即執(zhí)行,輸出
3。 - ??宏任務(wù)(setTimeout)??:在下一個事件循環(huán)中執(zhí)行,輸出
2。
??最終輸出順序??:1 → 4 → 3 → 2。
2. 事件循環(huán)(宏任務(wù)與微任務(wù))
- ??宏任務(wù)??:script 整體代碼、setTimeout、setInterval、I/O 操作。
- ?微任務(wù)??:Promise.then/catch/finally、MutationObserver、queueMicrotask。
??執(zhí)行規(guī)則??:
- 執(zhí)行一個宏任務(wù)(如 script 代碼);
- 執(zhí)行該宏任務(wù)產(chǎn)生的所有微任務(wù);
- 渲染頁面(如有必要);
- 執(zhí)行下一個宏任務(wù)。
3. 解題思路總結(jié)
- Promise 狀態(tài)機??:明確 pending → fulfilled/rejected 的不可逆性。
- ??then 的鏈式調(diào)用??:每次 then 返回新 Promise,回調(diào)返回值決定新狀態(tài)。
- ??事件循環(huán)優(yōu)先級??:微任務(wù) > 宏任務(wù)(理解這一規(guī)則可解決 80% 的異步面試題)。
通過本文的全方位解析,你已掌握 Promise 的核心原理、實戰(zhàn)用法及面試要點。結(jié)合實際項目中的異步場景(如 API 請求、文件讀?。`活運用 Promise 和 async/await,可顯著提升代碼質(zhì)量和開發(fā)效率! ??
到此這篇關(guān)于js進階教程之promise全方位解析和異步編程的文章就介紹到這了,更多相關(guān)js promise解析和異步編程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript 獲取網(wǎng)頁參數(shù)系統(tǒng)
用處比較多,適合在當前網(wǎng)頁打開別的網(wǎng)站的內(nèi)容2008-07-07
javascript數(shù)據(jù)結(jié)構(gòu)之串的概念與用法分析
這篇文章主要介紹了javascript數(shù)據(jù)結(jié)構(gòu)之串的概念與用法,簡單講述了串的概念、功能并結(jié)合實例形式分析了基于javascript實現(xiàn)串的遍歷、比較、查找等相關(guān)操作技巧,需要的朋友可以參考下2017-04-04
js判斷數(shù)據(jù)類型如判斷是否為數(shù)組是否為字符串等等
js判斷數(shù)據(jù)類型如判斷是否為數(shù)組類型、判斷是否為字符串類型、判斷是否為數(shù)值類型等等,本文有幾個不錯的示例,大家可以學習下2014-01-01

