减少承诺清单

时间:2020-06-06 07:06:30

标签: javascript typescript promise

我有一个应该顺序执行的作业列表。 由于作业需要几秒钟才能完成,因此应该在后台运行。 我以为工作可以描述为

interface Job {
    name: string
    execute(): Promise<boolean>
}

我希望有一个函数可以接收此作业列表并按顺序执行 直到列表完成或一项作业失败或被拒绝为止,基本上就是这样:

function executeUntilFailed(jobs: Job[]): Promise<boolean> 
{
    // execute first job
    // if this job
    //   - returns with true: continue with the next job
    //   - returns with false: resolve the promise with false
    //   - got rejected: reject the promise with the reason prefixed with the jobs name
    //
    // if there are no more jobs to do, resolve the promise with true
    //
    // basically it's a reduce operation with starting value of true and 
    // early stops if one job yields false or got rejected
}

我对Javascript / Typescript还是很陌生,很难实现。

谢谢, 迪特尔

3 个答案:

答案 0 :(得分:2)

感谢Aluan Happed和ehab。

我收集了他们的解决方案,现在有以下代码, 正是我所需要的:

    interface Job {
        name: string
        execute(): Promise<boolean>
    }


    async function executeUntilFailed(jobs: Job[]) {
        for (const job of jobs) {
            try {
                if(!await job.execute()) {
                    return false
                }
            }
            catch (err) {
                throw new Error(`${job.name}: ${err.message}`)
            }
        }
        return true
    }

这是一些例子

    class JobImpl implements Job {
        constructor(public name: string, private value: boolean, private throwMsg: string|null = null) {}
        execute(): Promise<boolean> {
            console.log(`executing job '${this.name}'`)
            return new Promise((resolve,reject) => {
                setTimeout(()=> {
                    if(this.throwMsg!=null) { reject(this.throwMsg) }
                    else { console.log(`finished job '${this.name}' with result: ${this.value}`); resolve(this.value) }
                }, 1000)
            })
        }
    }

    const successJobs = [
        new JobImpl("a", true),
        new JobImpl("b", true),
        new JobImpl("c", true),
    ]

    const failedJobs = [
        new JobImpl("d", true),
        new JobImpl("e", false),
        new JobImpl("f", true),
    ]

    const throwingJobs = [
        new JobImpl("g", true),
        new JobImpl("g", true, "undefined problem"),
        new JobImpl("i", true),
    ]


    executeUntilFailed(successJobs)
        .then((res) => console.log("resolved", res))
        .catch((err) => console.log("rejected", err))

    executeUntilFailed(failedJobs)
        .then((res) => console.log("resolved", res))
        .catch((err) => console.log("rejected", err))

    executeUntilFailed(throwingJobs)
        .then((res) => console.log("resolved", res))
        .catch((err) => console.log("rejected", err))

<!-- end snippet -->

答案 1 :(得分:2)

作为替代,您可以创建一个生成器,然后使用for await ... of语法:

function * chainJobs(jobs) {
    for (const job of jobs) {
        yield job.execute().catch(err => new Error(`${job.name}: ${err.message}`));
    }
}

async function executeUntilFailed(jobs) {
    for await (const result of chainJobs(jobs)) {
        if (!result) return false;
        if (result instanceof Error) throw result;
    }
    return true;
}

答案 2 :(得分:0)

您可以通过reduce函数或for循环实现此目的,我将在for

中显示一个实现
async function executeUntilFailed(jobs) {
  for (const job of jobs) {
    try {
     // notice that if a job resolved with false then it is considered a successful job
     // This is normal and a promise resolved with false should not be considered an error
      await job.execute()

      // if u want based on your description to resolve the whole promise with false if one of promises resolved with false you could do
     // const jobResult = await job.execute()
        // if (jobResult === false) {
           //  return Prmise.resolve(false)
       //  }
    } catch (err) {
      return Promise.reject(new Error(`${job.name}_${err.toString()}`))
    }
  }
  return Promise.resolve(true)
}

让我们看到实际的功能


const successJobs = [{
    name: "a",
    execute: () => Promise.resolve(1)
  },
  {
    name: "b",
    execute: () => Promise.resolve(2),
  },
  {
    name: "c",
    execute: () => Promise.resolve(3)
  },
]

const failedJobs = [{
    name: "a",
    execute: () => Promise.resolve(1)
  },
  {
    name: "b",
    execute: () => Promise.reject(new Error("undefined problem")),
  },
  {
    name: "c",
    execute: () => Promise.resolve(3)
  },
]

async function executeUntilFailed(jobs) {
  for (const job of jobs) {
    try {
      await job.execute()
    } catch (err) {
      return Promise.reject(new Error(`${job.name}_${err.toString()}`))
    }
  }
  return Promise.resolve(true)
}


console.log(
  executeUntilFailed(successJobs)
  .then((res) => console.log("resolved", res))
  .catch((err) => console.log("rejected", err))
)


console.log(
  executeUntilFailed(failedJobs)
  .then((res) => console.log("resolved", res))
  .catch((err) => console.log("rejected", err))
)