2016-09-03 2 views
1

У меня есть следующая функция, которая работает, как ожидалась:асинхронные ждет в Foreach

createObjectFrom(record) { 
    let obj = {}; 

    this.opts.transformers.forEach((transformer, index) => { 
     const headerIndex = findIndex(this.headers, (header) => { 
     return header === transformer.column; 
     }); 

     const value = transformer.formatter(record[headerIndex]); 

     obj[transformer.field] = value; 
    }); 

    return obj; 
    } 

Я хочу, чтобы реорганизовать его использовать асинхра ОЖИДАНИЕ и вызвать функцию асинхронной в теле ForEach, как это:

createObjectFrom(record) { 
    let obj = {}; 

    this.opts.transformers.forEach(async (transformer, index) => { 
     const headerIndex = findIndex(this.headers, (header) => { 
     return header === transformer.column; 
     }); 

     const result = await this.knex('managers').select('name') 

     console.log(result); 

     const value = transformer.formatter(record[headerIndex]); 

     obj[transformer.field] = value; 
    }); 

    return obj; 
    } 

Это, очевидно, нарушит функцию, поскольку forEach теперь выполняет асинхронно, и функция просто выполнит и уйдет.

Есть ли способ, которым я могу использовать async, ждут, чтобы forEach выполнялся синхронно. Могу ли я реорганизовать генераторы?

+0

«Это, очевидно, нарушит функцию, поскольку forEach теперь выполняет асинхронно» - это ничего не изменит. 'Array.prototype.forEach' не ожидает принятия' async' -функций, поэтому он будет вызывать его как «нормальную» функцию. Таким образом, все функции будут вызываться немедленно. – zerkms

+0

«Есть ли способ, которым я могу использовать async, ждут, чтобы forEach выполнялся синхронно» - просто используйте цикл 'for' или' for-of' для итерации по массиву. Вам также придется изменить 'createObjectFrom' как' async'. – zerkms

+0

Вы можете использовать этот материал плавно, используя [этот] (https://github.com/toniov/p-iteration), попробуйте, если вы не против использования модуля. –

ответ

1

Вы не можете заставить обычную JS-функцию ждать асинхронного поведения. Выхода нет!

Так что вам нужно будет реорганизовать ваш createObjectFrom, чтобы быть асинхронным. А затем, вероятно, пойдите для map/reduce вместо forEach. Чтобы быть производительным вы не хотите, чтобы это сделать:

for(transformer of this.opts.transformers) { 
    await this.knex('managers').select('name'); 
} 

Вместо этого вы должны использовать await Promise.all(...).

Однако в вашем случае вызов knex кажется, не зависит от трансформатора, так что вы можете сделать это:

async createObjectFrom(record) { 
    let obj = {}; 

    const result = await this.knex('managers').select('name') 

    this.opts.transformers.forEach(async (transformer, index) => { 
    const headerIndex = findIndex(this.headers, (header) => { 
     return header === transformer.column; 
    }); 

    console.log(result); 

    const value = transformer.formatter(record[headerIndex]); 

    obj[transformer.field] = value; 
    }); 

    return obj; 
} 

Однако, если вы хотите сделать что-то вроде выборки для каждого пункта что-то асинхронного сделать это как это:

async foo(data) { 
    const subDataArr = await Promise.all(data.map(record => loadSubData(record))); 

    return subDataArr; 
} 
+0

Мне понадобится s knex call для каждой итерации foreach. им любопытно, как это обрабатывается в узле, как кажется довольно распространенным случаем использования – dagda1

+0

@ dagda1 thats в основном мой последний пример кода. Предположим, что 'loadSubData' - это вызов Knex. – Lux

Смежные вопросы