等待者模式(waiter)
通过对多个异步进程监听,来触发未来发生的动作。(类似于
Promise
Promise.all(...)
)
什么是等待者模式
等待者模式
或者说等待者对象
是用来解决那些不确定先后完成的异步逻辑的
比如:运动会的入场仪式,你不确定请哪只队伍先入场,但有一点你很确定,就是会议开始必须等到所有的队伍入场完毕。而这里的会议开始就相当于等待这模式的逻辑执行
Promise.all(...)
function fnA() {
let code = [0, 1][Math.floor(Math.random() * 2)];
return new Promise((resolve, reject) => {
setTimeout(function () {
if (code) resolve({
code, msg: 'success!', name: 'fnA' })
else reject({
code, msg: 'fail!', name: 'fnA' })
}, 1500);
});
}
function fnB() {
let code = 1;
return new Promise((resolve, reject) => {
setTimeout(function () {
if (code) resolve({
code, msg: 'success!', name: 'fnB' })
else reject({
code, msg: 'fail!', name: 'fnB' })
}, 1000);
});
}
Promise.all([fnA(), fnB()])
.then(res => {
/**
* [{ code: 1, msg: 'success!', name: 'fnA' },
* { code: 1, msg: 'success!', name: 'fnB' }]
*/
console.log(res);
})
.catch(err => {
// { code: 0, msg: 'fail!', name: 'fnA' }
console.log(err);
});
函数形参嵌套函数形参
/**
* 函数形参fn 嵌套 函数形参resolve、reject
* @param {Function} fn demo的函数行参
* @param {Function} resolve fn的函数形参1
* @param {Function} reject fn的函数形参2
*/
function demo(fn = (resolve, reject) => {
resolve(null); reject(null); }) {
fn(resolve, reject);
function resolve(...args) {
console.log('resolve', args); }
function reject(...args) {
console.log('reject', args); }
}
demo(); // resolve->[null] reject->[null]
demo((resolve, reject) => {
resolve(1, 2, 3);
reject(4, 5, 6);
}); // resolve->[1, 2, 3] reject->[4, 5, 6]
以上代码的变式1
等待者模式完成 40%
/**
* 函数形参fn 嵌套 函数形参resolve、reject
* @param {Function} fn Demo的函数行参
* @param {Function} resolve fn的函数形参1
* @param {Function} reject fn的函数形参2
*/
function Demo(fn = (resolve, reject) => {
resolve(null); reject(null); }) {
let value = [];
fn(resolve, reject);
function resolve(...args) {
value = [...value, ...args];
}
function reject(...args) {
value = [...value, ...args];
}
this.then = (callback) => {
callback(value);
}
}
new Demo((resolve, reject) => {
resolve(1, 2, 3);
reject(4, 5, 6);
}).then(res => console.log(res)); // (6) [1, 2, 3, 4, 5, 6]
new Demo().then(res => console.log(res)); // [null, null]
以上代码的变式2
等待者模式完成 80%
/**
* 函数形参fn 嵌套 函数形参resolve、reject
* @param {Function} fn Demo的函数行参
* @param {Function} resolve fn的函数形参1
* @param {Function} reject fn的函数形参2
*/
function Demo(fn) {
let state = null; // null->赋值操作 true->resolve、onFulfilled false->reject、onRejected
let value = [];
let deferred = {
};
fn(resolve, reject);
function resolve(...args) {
state = true;
value = args;
deferred.onFulfilled && deferred.onFulfilled(value);
}
function reject(...args) {
state = false;
value = args;
deferred.onRejected && deferred.onRejected(value);
}
this.then = (onFulfilled, onRejected) => {
if (state === null) {
deferred = {
onFulfilled, onRejected }
} else {
(state ? onFulfilled : onRejected)(value);
}
return this;
}
}
new Demo((resolve, reject) => {
setTimeout(function () {
resolve(1, 2, 3);
reject(4, 5, 6);
}, 2000);
}).then(res => {
console.log('res', res); // res->[1, 2, 3]
}, err => {
console.log('err', err); // err->[4, 5, 6]
});
自定义实现等待者模式(仿Promise.all
)
等待者模式完成 100%
/**
* 等待者模式
* @param {Function} fn (resolve, reject) => { resolve('ok'); reject('fail'); }
* @returns 实例化
*/
function Waiter(fn) {
// 兼容不使用new关键字
if (!(this instanceof Waiter)) return new Waiter(fn);
let state = null; // true 成功回调; false 失败回调; null 中立
let value = null; // 暂存`成功或失败回调的结果`,用于`后续调用.then`的`使用`
let deferred = {
}; // 存储.then(...)传入的参数 ---> { onFulfilled, onRejected }
fn(resolve, reject);
/**
* 接收成功失败回调
* @param {Function} onFulfilled 成功回调
* @param {Function} onRejected 失败回调
* @returns 当前实例
*/
this.then = function (onFulfilled, onRejected) {
if (state === null) {
deferred = {
onFulfilled, onRejected };
} else {
(state ? onFulfilled : onRejected)(value);
}
return this;
};
/**
* 成功回调
* @param {any} val 结果
*/
function resolve(val) {
if (state !== null) return;
state = true;
value = val;
deferred.onFulfilled && deferred.onFulfilled(value);
deferred = null;
}
/**
* 失败回调
* @param {any} val 结果
*/
function reject(val) {
if (state !== null) return;
state = false;
value = val;
deferred.onRejected && deferred.onRejected(value);
deferred = null;
}
}
/**
* 等待所传函数全部完成
* @param {...any} args 任意参数
* @returns Waiter实例
*/
Waiter.all = (...args) => {
// 如果参数只有一个并且是数组,那么使用这个数组;如果参数为多个,那么使用参数组合成的数组;
let arr = (args.length === 1 && Array.isArray(args[0])) ? args[0] : args;
return new Waiter(function (resolve, reject) {
// 如果未传参,则返回空数组
if (arr.length === 0) return resolve([]);
// 还需处理的对象数量计数器
let remaining = arr.length;
// 处理传参保存结果函数
function result(w, i) {
if (w instanceof Waiter) {
w.then(function (res) {
result(res, i); }, reject);
return;
}
// 完成一个替换一个
arr[i] = w;
if (--remaining === 0) {
resolve(arr);
}
}
arr.forEach((w, i) => result(w, i));
});
};
const w1 = new Waiter((resolve, reject) => {
setTimeout(() => {
Math.random() > 0.5 ? resolve(1) : reject(0);
}, 2000);
}).then(res => console.log('res', res), err => console.log('err', err));
// 返回对象,成功或失败回调
function fnA() {
return new Waiter((resolve, reject) => {
setTimeout(() => {
Math.random() > 0.5 ? resolve({
name: 'A', msg: 'success' }) : reject({
name: 'A', msg: 'fail' });
}, 100);
});
}
// 返回对象,成功回调
function fnB() {
return new Waiter((resolve, reject) => {
setTimeout(() => {
resolve({
name: 'B', msg: 'success' });
}, 3000);
});
}
// 返回数字,成功回调
function fnC() {
return new Waiter((resolve, reject) => {
setTimeout(() => {
resolve(123);
}, 1000);
});
}
const w2 = Waiter.all([fnB(), fnA(), fnC(), 'abc', 456])
.then(res => console.log(JSON.stringify(res)), err => console.log(err));
等待者模式(ES6写法)
class Waiter {
#state = null; // true 成功回调; false 失败回调; null 中立
#value = null; // 暂存`成功或失败回调的结果`,用于`后续调用.then`的`使用`
#deferred = {
}; // 存储.then(...)传入的参数 ---> { onFulfilled, onRejected }
constructor(fn) {
// 兼容不使用new关键字
if (!(this instanceof Waiter)) return new Waiter(fn);
fn(this.#resolve, this.#reject);
}
/**
* 接收成功失败回调
* @param {Function} onFulfilled 成功回调
* @param {Function} onRejected 失败回调
* @returns 当前实例
*/
then = function (onFulfilled, onRejected) {
if (this.#state === null) {
this.#deferred = {
onFulfilled, onRejected };
} else {
(this.#state ? onFulfilled : onRejected)(this.#value);
}
return this;
};
/**
* 成功回调
* @param {any} val 结果
*/
#resolve = (val) => {
if (this.#state !== null) return;
this.#state = true;
this.#value = val;
this.#deferred.onFulfilled && this.#deferred.onFulfilled(this.#value);
this.#deferred = null;
};
/**
* 失败回调
* @param {any} val 结果
*/
#reject = (val) => {
if (this.#state !== null) return;
this.#state = false;
this.#value = val;
this.#deferred.onRejected && this.#deferred.onRejected(this.#value);
this.#deferred = null;
};
/**
* 等待所传函数全部完成
* @param {...any} args 任意参数
* @returns Waiter实例
*/
static all = (...args) => {
// 如果参数只有一个并且是数组,那么使用这个数组;如果参数为多个,那么使用参数组合成的数组;
let arr = (args.length === 1 && Array.isArray(args[0])) ? args[0] : args;
return new Waiter(function (resolve, reject) {
// 如果未传参,则返回空数组
if (arr.length === 0) return resolve([]);
// 还需处理的对象数量计数器
let remaining = arr.length;
// 处理传参保存结果函数
function result(w, i) {
if (w instanceof Waiter) {
w.then(function (res) {
result(res, i); }, reject);
return;
}
// 完成一个替换一个
arr[i] = w;
if (--remaining === 0) {
resolve(arr);
}
}
arr.forEach((w, i) => result(w, i));
});
};
}
const w1 = new Waiter((resolve, reject) => {
setTimeout(() => {
Math.random() > 0.5 ? resolve({
msg: 'success' }) : reject({
msg: 'fail' });
}, 5000);
}).then(res => console.log('res', res), err => console.log('err', err));
// 返回对象,成功或失败回调
function fnA() {
return new Waiter((resolve, reject) => {
setTimeout(() => {
Math.random() > 0.5 ? resolve({
name: 'A', msg: 'success' }) : reject({
name: 'A', msg: 'fail' });
}, 100);
});
}
// 返回对象,成功回调
function fnB() {
return new Waiter((resolve, reject) => {
setTimeout(() => {
resolve({
name: 'B', msg: 'success' });
}, 3000);
});
}
// 返回数字,成功回调
function fnC() {
return new Waiter((resolve, reject) => {
setTimeout(() => {
resolve(123);
}, 1000);
});
}
const w2 = Waiter.all([fnB(), fnA(), fnC(), 'abc'])
.then(res => console.log(JSON.stringify(res)), err => console.log(err));