async/wait loop with readline (inquirer) questions

时间:2017-06-15 10:00:34

标签: typescript promise async-await

I am using Inquirer & Typescript 2.3 for a console application, here's whats goind down

  • I want to have the user pick a name from the lists using await. No problem
  • Afterwards, i want the user to pick 1 or more options that he would like to adjust. No problem
  • I want to loop trough all the chosen option, using the same async/await as before.
  • I want to fill up the answers object like {fieldName: chosenOption, fieldname2: chosenOption2}

But that's where i get into trouble. I have tried various options, but whatever kind of loop i use, I end up with getting all * qeuestions to answer and have them the same value.

I see this is a subject widely explained, but i am simply overlooking something obvious. In order not to take up space the this.ask class property is included as gist.

async startInteractive() {
    let names = Object.keys(this.config('connect'));
    let name  = await this.ask.list('name', names);
    console.log('need to edit ', name);
    let availableFields       = [ 'user', 'host', 'port', 'method', 'localPath', 'hostPath' ]
    let chosenFields: Answers = await this.ask.checkbox('Choose fields to edit', availableFields)
    let current               = this.config('connect.' + name);

    let answers = {}

    // THIS PART
    // is the issue i'm not able to tackle
    await chosenFields.map(async (field) => {
        answers[ field ] = await this.ask.ask(field)
    })
}

Edit: this is the visual representation of the problem:

  • enter image asdfasdfenter code here here
  • enter image description here
  • enter image description here
  • enter image description here

1 个答案:

答案 0 :(得分:1)

chosenFields.map will return an array of callback results, i.e. promises in the case of the async callback. To be able to await an array of promises, you need to use Promise.all to convert it into a promise for an array before:

await Promise.all(chosenFields.map(async (field) => {
    answers[ field ] = await this.ask.ask(field)
}))

I can't tell why you'd get the same result for all fields, though. It seems there's a race condition in inquirer.prompt when it is called concurrently. To invoke it sequentially, use

for (let field of chosenFields) {
    answers[ field ] = await this.ask.ask(field)
}