提示💡
all(): 遍历、计数器、race(): 遍历、成功一个就返回。
手写代码
Promise . all
原生的 Promise. all 有什么特点?
- 特点1:接收一个可迭代对象
- 特点2:传入的数据中可以是普通数据,也可以是Promise对象
- 特点3:可迭代对象的promise是并行执行的
- 特点4:保持输入数组的顺序和输出数组的顺序一致
- 特点5:传入数组中只要有一个reject,立即返回reject
- 特点6:所有数据resolve之后返回结果
function myPromiseAll(iterable) {
return new Promise((resolve,reject) => {
const promises = Array.from(iterable);
// 定义Promise对象resolve的数组
const result = [];
// 定义一个计数器用来判断是否所有的promise执行完毕
let count = 0;
// 并发执行每一个promise
for (let i = 0; i < promises.length; i++) {
Promise.resolve(promises[i]).then(res => {
result[i] = res;
count++;
if (count === promises.length) {
resolve(result);
}
}).catch(err => reject(err))
}
})
}
Promise.race
function myPromiseRace(promises) {
return new Promise(function (resolve, reject) {
for (let i = 0; i < promises.length; i++) {
Promise.resolve(promises[i]).then(function (value) {
return resolve(value)
}, function (reason) {
return reject(reason)
})
}
})
}
测试代码:
const p1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('p1'), 1000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => resolve('p2'), 5000)
})
Promise.race([p1, p2]).then(ret => {
console.log(ret) // 'p1'
})
手写 promise
核心代码
// 记录 Promise 的三种状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
/**
* 运行一个微队列任务
* 把传递的函数放到微队列中(模拟 vue 实现)
* @param {Function} callback
*/
function runMicroTask(callback) {
// 判断 node 环境
// 为了避免「变量未定义」的错误,这里最好加上前缀 globalThis
// globalThis 是一个关键字,指代全局对象,浏览器环境为 window,node 环境为 global
if (globalThis.process && globalThis.process.nextTick) {
// node
process.nextTick(callback);
} else if (globalThis.MutationObserver) {
// 高版本浏览器
const p = document.createElement('p');
const observer = new MutationObserver(callback); // 可以做成单例,提高效率,这里简单实现
observer.observe(p, {
childList: true, // 观察该元素内部的变化
});
p.innerHTML = '1';
} else {
// 低版本浏览器
setTimeout(callback, 0);
}
}
/**
* 判断一个数据是否是 Promise 对象
* @param {any} obj
* @returns
*/
function isPromise(obj) {
// 必须是一个对象 && 必须有 then 函数
return !!(obj && typeof obj === 'object' && typeof obj.then === 'function');
}
class MyPromise {
/**
* 创建一个 Promise
* @param {Function} executor 任务执行器,立即执行
*/
constructor(executor) {
this._state = PENDING; // 状态
this._value = undefined; // 数据
this._handlers = []; // 处理函数形成的队列
try {
executor(this._resolve.bind(this), this._reject.bind(this));
} catch (error) {
// 处理错误
this._reject(error);
console.error(error);
}
}
/**
* 向处理队列中添加一个函数
* @param {Function} executor 添加的函数
* @param {String} state 该函数什么状态下执行
* @param {Function} resolve 让 then 函数返回的 Promise 成功
* @param {Function} reject 让 then 函数返回的 Promise 失败
*/
_pushHandler(executor, state, resolve, reject) {
this._handlers.push({ executor, state, resolve, reject });
}
/**
* 根据实际情况,执行队列
*/
_runHandlers() {
if (this._state === PENDING) {
// 目前任务仍在挂起
return;
}
while (this._handlers[0]) {
const handler = this._handlers[0];
this._runOneHandler(handler);
this._handlers.shift();
}
}
/**
* 处理一个 handler()
* @param {Object} handler
*/
_runOneHandler({ executor, state, resolve, reject }) {
// 处理与当前状态 _state 相同的微任务
runMicroTask(() => {
if (this._state !== state) {
// 状态不一致,不处理
return;
}
if (typeof executor !== 'function') {
// 传递后续处理并非一个函数,与之前的状态保持一致
this._state === FULFILLED ? resolve(this._value) : reject(this._value);
return;
}
try {
const result = executor(this._value); // 返回结果有可能是 promise
if (isPromise(result)) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (error) {
reject(error);
console.error(error);
}
});
}
/**
* Promise A+ 规范的 then
* @param {Function} onFulfilled
* @param {Function} onRejected
*/
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
this._pushHandler(onFulfilled, FULFILLED, resolve, reject);
this._pushHandler(onRejected, REJECTED, resolve, reject);
this._runHandlers(); // 执行队列(用户可能直接在 new Promise 中执行 resolve 或 reject,此时状态变化,需要立即执行队列)
});
}
/**
* 更改任务状态
* @param {String} newState 新状态
* @param {any} value 相关数据
*/
_changeState(newState, value) {
if (this._state !== PENDING) {
// 目前状态已经更改
return;
}
this._state = newState;
this._value = value;
this._runHandlers(); // 状态变化,执行队列
}
/**
* 标记当前任务完成
* @param {any} data 任务完成的相关数据
*/
_resolve(data) {
this._changeState(FULFILLED, data);
}
/**
* 标记当前任务失败
* @param {any} reason 任务失败的相关数据
*/
_reject(reason) {
this._changeState(REJECTED, reason);
}
}
测试代码
// ------ 测试 1 ------
let pro1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
reject('失败');
}, 1000);
});
let pro2 = pro1.then(function A1() { }, undefined);
setTimeout(() => {
console.log(pro1);
console.log(pro2);
}, 1500);
// 值穿透
// MyPromise { _state: 'rejected', _value: '失败', _handlers: [] }
// MyPromise { _state: 'rejected', _value: '失败', _handlers: [] }
// ------ 测试 2 ------
let pro3 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('成功');
}, 1000);
});
let pro4 = pro3.then(function A1(data) {
console.log(data);
return new MyPromise((resolve, reject) => {
resolve(1);
});
});
setTimeout(() => {
console.log(pro4);
}, 1500);
// 成功
// MyPromise { _state: 'fulfilled', _value: 1, _handlers: [] }
// ------ 测试 3(与官方 promise 互操作) ------
function delay(duraton) {
return new MyPromise((resolve) => {
setTimeout(resolve, duraton);
});
}
(async function () {
console.log('start');
await delay(2000);
console.log('end');
})();
// ------ 测试 4(与官方 promise 互操作) ------
const pro5 = new MyPromise((resolve) => {
resolve(1);
});
pro5.then((data) => {
console.log(data);
return new Promise((resolve) => {
resolve(2);
})
}).then(data => {
console.log(data);
});
完整代码
// 记录 Promise 的三种状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
/**
* 运行一个微队列任务
* 把传递的函数放到微队列中(模拟 vue 实现)
* @param {Function} callback
*/
function runMicroTask(callback) {
// 判断 node 环境
// 为了避免「变量未定义」的错误,这里最好加上前缀 globalThis
// globalThis 是一个关键字,指代全局对象,浏览器环境为 window,node 环境为 global
if (globalThis.process && globalThis.process.nextTick) {
// node
process.nextTick(callback);
} else if (globalThis.MutationObserver) {
// 高版本浏览器
const p = document.createElement('p');
const observer = new MutationObserver(callback); // 可以做成单例,提高效率,这里简单实现
observer.observe(p, {
childList: true, // 观察该元素内部的变化
});
p.innerHTML = '1';
} else {
// 低版本浏览器
setTimeout(callback, 0);
}
}
/**
* 判断一个数据是否是 Promise 对象
* @param {any} obj
* @returns
*/
function isPromise(obj) {
return !!(obj && typeof obj === 'object' && typeof obj.then === 'function');
}
class MyPromise {
/**
* 创建一个 Promise
* @param {Function} executor 任务执行器,立即执行
*/
constructor(executor) {
this._state = PENDING; // 状态
this._value = undefined; // 数据
this._handlers = []; // 处理函数形成的队列
try {
executor(this._resolve.bind(this), this._reject.bind(this));
} catch (error) {
// 处理错误
this._reject(error);
console.error(error);
}
}
/**
* 向处理队列中添加一个函数
* @param {Function} executor 添加的函数
* @param {String} state 该函数什么状态下执行
* @param {Function} resolve 让 then 函数返回的 Promise 成功
* @param {Function} reject 让 then 函数返回的 Promise 失败
*/
_pushHandler(executor, state, resolve, reject) {
this._handlers.push({ executor, state, resolve, reject });
}
/**
* 根据实际情况,执行队列
*/
_runHandlers() {
if (this._state === PENDING) {
// 目前任务仍在挂起
return;
}
while (this._handlers[0]) {
const handler = this._handlers[0];
this._runOneHandler(handler);
this._handlers.shift();
}
}
/**
* 处理一个 handler()
* @param {Object} handler
*/
_runOneHandler({ executor, state, resolve, reject }) {
// 处理与当前状态 _state 相同的微任务
runMicroTask(() => {
if (this._state !== state) {
// 状态不一致,不处理
return;
}
if (typeof executor !== 'function') {
// 传递后续处理并非一个函数,与之前的状态保持一致
this._state === FULFILLED ? resolve(this._value) : reject(this._value);
return;
}
try {
const result = executor(this._value); // 返回结果有可能是 promise
if (isPromise(result)) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (error) {
reject(error);
console.error(error);
}
});
}
/**
* Promise A+ 规范的 then
* @param {Function} onFulfilled
* @param {Function} onRejected
*/
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
this._pushHandler(onFulfilled, FULFILLED, resolve, reject);
this._pushHandler(onRejected, REJECTED, resolve, reject);
this._runHandlers(); // 执行队列(用户可能直接在 new Promise 中执行 resolve 或 reject,此时状态变化,需要立即执行队列)
});
}
/**
* 仅处理失败的场景
* @param {Function} onRejected
*/
catch(onRejected) {
return this.then(null, onRejected);
}
/**
* 无论成功还是失败都会执行回调
* @param {Function} onSettled
*/
finally(onSettled) {
return this.then(
(data) => {
onSettled();
return data;
},
(reason) => {
onSettled();
throw reason;
}
);
}
/**
* 更改任务状态
* @param {String} newState 新状态
* @param {any} value 相关数据
*/
_changeState(newState, value) {
if (this._state !== PENDING) {
// 目前状态已经更改
return;
}
// 下面这个判断是为了处理value为Promise的情况
// 这一段代码课程中没有涉及,特此注释说明
if (isPromise(value)) {
value.then(this._resolve.bind(this), this._reject.bind(this));
return;
}
this._state = newState;
this._value = value;
this._runHandlers(); // 状态变化,执行队列
}
/**
* 标记当前任务完成
* @param {any} data 任务完成的相关数据
*/
_resolve(data) {
this._changeState(FULFILLED, data);
}
/**
* 标记当前任务失败
* @param {any} reason 任务失败的相关数据
*/
_reject(reason) {
this._changeState(REJECTED, reason);
}
/**
* 返回一个已完成的 Promise
* 特殊情况:
* 1. 传递的 data 本身就是 ES6 的 Promise 对象
* 2. 传递的 data 是 PromiseLike(Promise A+),返回新的 Promise,状态和其保持一致即可
* @param {any} data
*/
static resolve(data) {
if (data instanceof MyPromise) {
return data;
}
return new MyPromise((resolve, reject) => {
if (isPromise(data)) {
data.then(resolve, reject);
} else {
resolve(data);
}
});
}
/**
* 得到一个被拒绝的 Promise
* @param {any}} reason
*/
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason);
});
}
/**
* 得到一个新的 Promise
* 该 Promise 的状态取决于 proms 的执行
* proms 是一个迭代器,包含多个 Promise
* 全部 Promise 成功,则返回的 Promise 成功,数据为所有 Promise 成功的数据,并且顺序是按照传入的顺序排列
* 只要有一个 Promise 失败,则返回的 Promise 失败,原因是第一个失败的 Promise 的原因
* @param {iterator} proms
*/
static all(proms) {
return new MyPromise((resolve, reject) => {
try {
const results = [];
let count = 0; // Promise 的总数,利用索引向 results 中放入结果,这样 results 里面的结果是有顺序的
let fulfilledCount = 0; // 已完成的数量
for (const p of proms) {
let i = count;
count++;
MyPromise.resolve(p).then( // MyPromise.resolve(p) 包裹一下,p有可能不是 promise
(data) => {
fulfilledCount++;
results[i] = data;
if (fulfilledCount === count) {
// 当前是最后一个 Promise 完成了
resolve(results);
}
},
reject
);
}
if (count === 0) {
resolve(results);
}
} catch (error) {
reject(error);
console.error(error);
}
});
}
/**
* 等待所有的 Promise 有结果之后
* 该方法返回的 Promise 完成
* 并且按照顺序将所有结果汇总
* @param {iterator} proms
*/
static allSettled(proms) {
const ps = [];
for (const p of proms) {
ps.push(
// p.then: p 有可能不是 promise,所以用 MyPromise.resolve(p) 包裹一下
MyPromise.resolve(p).then(
(value) => ({
status: FULFILLED,
value,
}),
(reason) => ({
status: REJECTED,
reason,
})
)
);
}
return MyPromise.all(ps);
}
/**
* 返回的Promise与第一个有结果的一致
* @param {iterator} proms
*/
static race(proms) {
return new MyPromise((resolve, reject) => {
for (const p of proms) {
MyPromise.resolve(p).then(resolve, reject);
}
});
}
}
源码
//Promise 完整的实现
class Promise {
callbacks = [];
state = 'pending';//增加状态
value = null;//保存结果
constructor(fn) {
fn(this._resolve.bind(this), this._reject.bind(this));
}
then(onFulfilled, onRejected) {
return new Promise((resolve, reject) => {
this._handle({
onFulfilled: onFulfilled || null,
onRejected: onRejected || null,
resolve: resolve,
reject: reject
});
});
}
catch(onError) {
return this.then(null, onError);
}
finally(onDone) {
if (typeof onDone !== 'function') return this.then();
let Promise = this.constructor;
return this.then(
value => Promise.resolve(onDone()).then(() => value),
reason => Promise.resolve(onDone()).then(() => { throw reason })
);
}
static resolve(value) {
if (value && value instanceof Promise) {
return value;
} else if (value && typeof value === 'object' && typeof value.then === 'function') {
let then = value.then;
return new Promise(resolve => {
then(resolve);
});
} else if (value) {
return new Promise(resolve => resolve(value));
} else {
return new Promise(resolve => resolve());
}
}
static reject(value) {
if (value && typeof value === 'object' && typeof value.then === 'function') {
let then = value.then;
return new Promise((resolve, reject) => {
then(reject);
});
} else {
return new Promise((resolve, reject) => reject(value));
}
}
static all(promises) {
return new Promise((resolve, reject) => {
let fulfilledCount = 0
const itemNum = promises.length
const rets = Array.from({ length: itemNum })
promises.forEach((promise, index) => {
Promise.resolve(promise).then(result => {
fulfilledCount++;
rets[index] = result;
if (fulfilledCount === itemNum) {
resolve(rets);
}
}, reason => reject(reason));
})
})
}
static race(promises) {
return new Promise(function (resolve, reject) {
for (let i = 0; i < promises.length; i++) {
Promise.resolve(promises[i]).then(function (value) {
return resolve(value)
}, function (reason) {
return reject(reason)
})
}
})
}
_handle(callback) {
if (this.state === 'pending') {
this.callbacks.push(callback);
return;
}
let cb = this.state === 'fulfilled' ? callback.onFulfilled : callback.onRejected;
if (!cb) {//如果then中没有传递任何东西
cb = this.state === 'fulfilled' ? callback.resolve : callback.reject;
cb(this.value);
return;
}
let ret;
try {
ret = cb(this.value);
cb = this.state === 'fulfilled' ? callback.resolve : callback.reject;
} catch (error) {
ret = error;
cb = callback.reject
} finally {
cb(ret);
}
}
_resolve(value) {
if(this.state !== 'pending') return
if (value && (typeof value === 'object' || typeof value === 'function')) {
var then = value.then;
if (typeof then === 'function') {
then.call(value, this._resolve.bind(this), this._reject.bind(this));
return;
}
}
this.state = 'fulfilled';//改变状态
this.value = value;//保存结果
this.callbacks.forEach(callback => this._handle(callback));
}
_reject(error) {
if(this.state !== 'pending') return
this.state = 'rejected';
this.value = error;
this.callbacks.forEach(callback => this._handle(callback));
}
}