我在下面编写了一些使用DeferredPromise的代码,而我找到它的最简单方法是使用对象而不是通常的Promise执行程序函数,因为我需要从执行程序外部解析Promise。我想知道是否存在基于Promise执行程序功能的可接受的设计模式,而不使用类似延迟的解决方案?无需从承诺执行者外部解决承诺就可以做到吗?
Deferred
这是详细信息。
我有一个项目,该项目使用一组工作线程以及希望不时使用工作线程的代码的各个部分。为了解决这个问题,我创建了一个简单的WorkerList类,其中列出了可用的工作线程列表。当某人想要使用一个get()线程时,他们会调用它,并返回一个解析为工作线程的promise。如果辅助线程立即可用,则诺言立即解决。如果所有工作线程都在使用中(因此可用工作线程列表为空),则承诺将无法解析,直到以后通过该add(worker)方法将一个承诺线程放回到可用列表中。
WorkerList
get()
add(worker)
此WorkerList类只有两个方法,add(worker)和get()。您get()是一个工作人员,当您完成工作后,便将add(worker)其退回。当您add(worker)返回时,该类将检查是否有任何任务在等待可用的Worker。如果存在,它将与可用的Worker达成其承诺。解决其他人的诺言的地方就是使用“延期”的地方。
这是的代码WorkerList:
class WorkerList { constructor() { this.workers = []; this.deferredQueue = []; } add(worker) { this.workers.push(worker); // if someone is waiting for a worker, // pull the oldest worker out of the list and // give it to the oldest deferred that is waiting while (this.deferredQueue.length && this.workers.length) { let d = this.deferredQueue.shift(); d.resolve(this.workers.shift()); } } // if there's a worker, get one immediately // if not, return a promise that resolves with a worker // when next one is available get() { if (this.workers.length) { return Promise.resolve(this.workers.shift()); } else { let d = new Deferred(); this.deferredQueue.push(d); return d.promise; } } }
并且,这是Deferred实现:
function Deferred() { if (!(this instanceof Deferred)) { return new Deferred(); } const p = this.promise = new Promise((resolve, reject) => { this.resolve = resolve; this.reject = reject; }); this.then = p.then.bind(p); this.catch = p.catch.bind(p); if (p.finally) { this.finally = p.finally.bind(p); } }
也许下面的内容只是穷人的递延方法,并没有真正解决问题的症结,但是除了递延队列之外,您还可以保留解析器功能队列。
这样可以在您的方法上节省少量代码,并避免显式使用Deferreds。
我不知道是否存在已建立的模式,但是它本身似乎是用于维护异步对象池的可重用模式,因此WorkerList可以调用它而不是调用它,而是将其命名AsyncPool为可重用的部分在您的WorkerList:
AsyncPool
class AsyncPool { constructor() { this.entries = []; this.resolverQueue = []; } add(entry) { console.log(`adding ${entry}`); this.entries.push(entry); // if someone is waiting for an entry, // pull the oldest one out of the list and // give it to the oldest resolver that is waiting while (this.resolverQueue.length && this.entries .length) { let r = this.resolverQueue.shift(); r(this.entries.shift()); } } // if there's an entry, get one immediately // if not, return a promise that resolves with an entry // when next one is available get() { return new Promise((r) => this.entries.length ? r(this.entries.shift()) : this.resolverQueue.push(r) ); } } let pool = new AsyncPool(); pool.add('Doc'); pool.add('Grumpy'); pool.get().then(console.log); pool.get().then(console.log); pool.get().then(console.log); pool.get().then(console.log); // add more entries later setTimeout(() => pool.add('Sneezy'), 1000); setTimeout(() => pool.add('Sleepy'), 2000);