一般而言,事件与侦听器的关系是一对多,但在异步编程中,也会出现事件与侦听器的关系是多对 一的情况,也就是说一个业务逻辑可能依赖两个通过回调或事件传递
AOP 模式
lodash 就有 after,在多少次后执行,私有化预制了 timers 变量。
function after (timers, callback) {
return function (params) {
if (--timers === 0) {
callback()
}
}
}
let newFn = after(2, function () {
console.log('after')
})
newFn()
newFn()
以文件读取为例:
function after (timers, fn) {
let arr = [];
return function (data) { // 每次都会触发这个函数
arr.push(data)
if (--times === 0) { // 达到目的就触发
fn(arr)
}
}
}
let out = after(2, function (data) {
// 执行完成的回调
console.log(data)
})
// 异步都有一个回调
fs.readFile('./a.txt', 'utf8', function (err, data) {
console.log(data)
out(data)
})
fs.readFile('./b.txt', 'utf8', function (err, data) {
console.log(data)
out(data)
})
发布订阅模式
function Events () {
this.arr = []
}
Events.prototype.on = function (fn) {
// 订阅
this.arr.push(fn)
}
Events.prototype.emit = function (params) {
this.arr.forEach(function (fn) {
fn(params)
})
}
// 多个异步并发靠的都是计数器
let e = new Events();
let arr = []
e.on(function (r) {
if (arr.length === 2) {
// 执行完成的回调
console.log('ok')
}
})
// 异步都有一个回调
fs.readFile('./a.txt', 'utf8', function (err, data) {
console.log(data)
e.emit(data)
})
fs.readFile('./b.txt', 'utf8', function (err, data) {
console.log(data)
e.emit(data)
})
Promise/Deferred 模式
let fs = require('fs');
// 实现promise延迟对象,defer
Promise.defer = function () {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
})
return dfd
}
// function read () {
// return new Promise((resolve, reject) => {
// fs.readFile('./a.txt', 'utf8', (err, data) => {
// if (!err) resolve(data)
// })
// })
// }
// 减少代码嵌套,
function read () {
let defer = Promise.defer()
fs.readFile('./a.txt', 'utf8', (err, data) => {
if (!err) defer.resolve(data)
})
return defer.promise
}
read().then((data) => {
console.log(data)
})
promise 化,将一个方法 promise 化,node 有个库, bluebird。
const fs = require('fs')
let bluebird = require('bluebird')
let read = bluebird.promisify(fs.readFile)
Promise.all([read('./a.txt'), read('./b.txt')]).then(data => {
console.log(data)
})
function promisify (fn) {
return function (...args) {
return new Promise((resolve, reject) => {
fn(...args, function (err, data) {
if (!err) resolve(data)
})
})
}
}