您可以不使用Deferred来编写此代码吗? [英] Can you write this without using a Deferred?

查看:69
本文介绍了您可以不使用Deferred来编写此代码吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在下面编写了一些使用Promise的代码,而我找到的最简单的方法是使用 Deferred 对象而不是通常的Promise executor函数,因为我需要解决执行者外部的承诺。我想知道是否存在基于Promise执行程序功能的可接受的设计模式,而不使用类似延迟的解决方案?不需要从承诺执行者外部解决承诺就可以做到吗?



以下是详细信息。



我有一个项目,该项目使用一组工作线程以及希望不时使用工作线程的代码的各个部分。为了解决这个问题,我创建了一个简单的 WorkerList 类,该类保留了可用的工作线程列表。当某人想要使用它时,他们在其上调用 get()并返回一个承诺,该承诺将解析为工作线程。如果辅助线程立即可用,则诺言将立即解决。如果所有工作线程都在使用中(因此可用工作线程列表为空),则承诺将无法解析,直到稍后通过 add(worker)将其放回到可用列表中方法。



该WorkerList类只有两个方法, add(worker) get()。您 get()工人,完成后,您 add(worker)回来。返回 add(worker)时,该类将检查是否有任何任务在等待可用的Worker。如果存在,它将与可用的Worker达成其承诺。



以下是 WorkerList 的代码:



p>

  class WorkerList {
Constructor(){
this.workers = [];
this.deferredQueue = [];
}
add(worker){
this.workers.push(worker);

//如果有人在等工人,
//从列表中拉出最老的工人,然后将
//交给等待$ b的最老的延期工人$ b while(this.deferredQueue.length&& this.workers.length){
let d = this.deferredQueue.shift();
d.resolve(this.workers.shift());
}
}
//如果有工人,立即得到一个
//如果没有工人,则返回下一个由工人
//解决的承诺可用
get(){
if(this.workers.length){
return Promise.resolve(this.workers.shift());
} else {
let d = new Deferred();
this.deferredQueue.push(d);
回报d。承诺;
}
}
}

这是Deferred实现:

  function Deferred(){
if(!(此Deferred实例)){
返回新的Deferred();
}
const p = this.promise = new Promise((resolve,拒绝)=> {{
this.resolve =解决;
this.reject =拒绝;
});
this.then = p.then.bind(p);
this.catch = p.catch.bind(p);
if(p.finally){
this.finally = p.finally.bind(p);
}
}


解决方案

也许下面只是一个穷人的递延方法,并没有真正解决问题的症结,但是除了递延队列之外,您还可以保留一个解析程序函数队列。



这比您的方法节省了少量代码,并且避免了显式使用Deferreds。



我不知道是否存在用于这样,但它本身似乎是用于维护异步对象池的可重用模式,因此您可以将其命名为 AsyncPool,而不是将其命名为 WorkerList ,然后将其组合为您的 WorkerList 中的可重用部分:



  class AsyncPool {Constructor(){this.entries = []; this.resolverQueue = []; } add(entry){console.log(ʻadd $ {entry}`);; this.entries.push(entry); //如果有人在等待条目,//将最旧的条目从列表中拉出// //将其提供给正在等待的最旧的解析器(this.resolverQueue.length&& this.entries .length){令r = this.resolverQueue.shift(); r(this.entries.shift()); }} //如果有一个条目,//立即获得一个//如果没有条目,则返回一个承诺,该承诺将以一个条目解决// //当下一个可用时,get(){return new Promise((r)=> this.entries。长度?r(this.entries.shift():this.resolverQueue.push(r)); }}让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); //稍后添加更多条目setTimeout(()=> pool.add('Sneezy') ,1000); setTimeout(()=> pool.add('Sleepy'),2000);  


I wrote some code below that uses promises and the easiest way I could find to write it was using a Deferred object instead of the usual Promise executor function because I need to resolve the promise from outside the executor. I'm wondering if there's an accepted design pattern based on the Promise executor function for a problem like this that doesn't use a deferred-like solution? Can it be done without having to resolve the promise from outside the promise executor?

Here are the details.

I have a project that uses a set of Worker Threads and various parts of the code that want to use a Worker Thread from time to time. To manage that, I've created a simple WorkerList class that keeps a list of the available Worker Threads. When someone wants to use one, they call get() on it and that returns a promise that resolves to a Worker Thread. If a worker thread is available immediately, the promise resolves immediately. If all worker threads are in use (and thus the list of available workers is empty), then the promise doesn't resolve until one is later put back into the available list via the add(worker) method.

This WorkerList class has only two methods, add(worker) and get(). You get() a worker and when you're done with it, you add(worker) it back. When you add(worker) it back, the class checks to see if there are any tasks waiting for an available Worker. If there, are, it resolves their promise with an available Worker. That resolving of someone else's promise is where the Deferred was used.

Here's the code for the 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;
        }
    }
}

And, here's the Deferred implementation:

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);
    }
}

解决方案

Maybe the below is just a poor man's approach to deferreds, and doesn't really get to the crux of the matter, but instead of a queue of deferreds, you could just keep a queue of resolver functions.

This saves a small amount of code over your approach and avoids explicitly using Deferreds.

I don't know if there is an established pattern for this, but this in itself seems like a reusable pattern for maintaining an asynchronous pool of objects, so rather than calling it WorkerList, you could name it AsyncPool, and then compose that as a reusable piece within your WorkerList:

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);

这篇关于您可以不使用Deferred来编写此代码吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆