지도 내에서 비동기 함수를 호출하는 가장 좋은 방법은?
배열을 매핑하고 있는데 새 개체의 반환 값 중 하나에 대해 비동기 호출을 해야 합니다.
var firebaseData = teachers.map(function(teacher) {
return {
name: teacher.title,
description: teacher.body_html,
image: urlToBase64(teacher.summary_html.match(/src="(.*?)"/)[1]),
city: metafieldTeacherData[teacher.id].city,
country: metafieldTeacherData[teacher.id].country,
state: metafieldTeacherData[teacher.id].state,
studioName: metafieldTeacherData[teacher.id].studioName,
studioURL: metafieldTeacherData[teacher.id].studioURL
}
});
그 기능의 구현은 다음과 같습니다.
function urlToBase64(url) {
request.get(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
return "data:" + response.headers["content-type"] + ";base64," + new Buffer(body).toString('base64');
}
});
}
어떻게 하는 게 최선의 방법인지 잘 모르겠어요약속?중첩 콜백?ES6나 ES7에서 뭔가를 사용한 다음 바벨과 바꿔치기?
현재 이를 구현하는 가장 좋은 방법은 무엇입니까?
2018년 업데이트:Promise.all
맵 콜백 내의 비동기 기능은 구현하기가 더 쉽습니다.
let firebaseData = await Promise.all(teachers.map(async teacher => {
return {
name: teacher.title,
description: teacher.body_html,
image: await urlToBase64(teacher.summary_html.match(/src="(.*?)"/)[1]),
city: metafieldTeacherData[teacher.id].city,
country: metafieldTeacherData[teacher.id].country,
state: metafieldTeacherData[teacher.id].state,
studioName: metafieldTeacherData[teacher.id].studioName,
studioURL: metafieldTeacherData[teacher.id].studioURL
}
}));
async function urlToBase64(url) {
return request.get(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
return "data:" + response.headers["content-type"] + ";base64," + new Buffer(body).toString('base64');
}
});
}
Edit@2018/04/29
: 저는 모든 사람들을 위한 일반적인 예를 들었습니다.
Edit@2019/06/19
: 일부 요청이 실패한 경우 프로세스가 계속 작동하도록 하려면 비동기/await가 오류를 처리하기 위한 시도/catch가 있어야 합니다.
let data = await Promise.all(data.map(async (item) => {
try {
item.fetchItem = await fetchFunc(item.fetchParams);
return item;
} catch(error) {
return {...item, error } ;
}
}));
/* we can filter errors in data and retry later
* eg:
* const errorItems = data.filter(item => !!item.error)
*/
이 답변은 Node 4.0+에서 작동합니다.이전 버전에는 약속 폴리필 또는 라이브러리가 필요합니다.저는 ES6 화살표 기능도 사용해 보았는데, 이 기능은 일반적인 것으로 대체가 가능합니다.function
노드 < 4의 경우 s.
이 기술은 수동으로 랩핑합니다.request.get
약속과 함께요청 약속 같은 도서관을 이용할 수도 있습니다.
function urlToBase64(url) {
return new Promise((resolve, reject) => {
request.get(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
resolve("data:" + response.headers["content-type"] + ";base64," + new Buffer(body).toString('base64'));
} else {
reject(response);
}
});
})
}
// Map input data to an Array of Promises
let promises = input.map(element => {
return urlToBase64(element.image)
.then(base64 => {
element.base64Data = base64;
return element;
})
});
// Wait for all Promises to complete
Promise.all(promises)
.then(results => {
// Handle results
})
.catch(e => {
console.error(e);
})
2020년에는 ECMAScript2021의 구문을 사용하여 다음과 같이 작업을 대폭 간소화할 수 있습니다.
이제 간단히 다음과 같은 작업을 수행할 수 있습니다.
//return an array of promises from our iteration:
let promises = teachers.map(async m => {
return await request.get(....);
});
//simply iterate those
//val will be the result of the promise not the promise itself
for await (let val of promises){
....
}
sync.map을 사용할 수 있습니다.
var async = require('async');
async.map(teachers, mapTeacher, function(err, results){
// results is now an array of stats for each file
});
function mapTeacher(teacher, done) {
// computing stuff here...
done(null, teacher);
}
모든 교사는 병렬로 처리됩니다. 다음 기능도 사용할 수 있습니다.
mapSeries(arr, iterator, [callback])
일일이 지도를 그리다
mapLimit(arr, limit, iterator, [callback])
지도들limit
동시에
저도 비슷한 문제가 있었고 이것이 더 쉽다는 것을 알았습니다(Kai의 일반 템플릿을 사용하고 있습니다).아래에서는 하나만 사용하면 됩니다.await
하고 있었습니다 저는 또한 저의 비동기 함수로서 ajax 함수를 사용하고 있었습니다.
function asyncFunction(item) {
return $.ajax({
type: "GET",
url: url,
success: response => {
console.log("response received:", response);
return response;
}, error: err => {
console.log("error in ajax", err);
}
});
}
let data = await Promise.all(data.map(item => asyncFunction(item)));
아래의 비동기 맵 함수인 맵()을 사용해 보십시오.
async function amap(arr,fun) {
return await Promise.all(arr.map(async v => await fun(v)))
}
또는 보다 간결한 방식으로 작성됩니다.
let amap = async (arr,fun) => await Promise.all(arr.map(async v => await fun(v)))
용도:
let arr = await amap([1,2,3], async x => x*2)
console.log(arr) // [2, 4, 6]
어레이 상에서 비동기 기능을 사용하고 있습니다.array.map을 사용하지 않고 a를 함수에 사용합니다.이것은 이런 것입니다.
const resultingProcessedArray = async function getSomeArray() {
try {
let { data } = await axios({url: '/myUrl', method:'GET'}); //initial array
let resultingProcessedArray = [];
for (let i = 0, len = data.items.length; i < len; i++) {
let results = await axios({url: `/users?filter=id eq ${data.items[i].someId}`, method:'GET'});
let domainName = results.data.items[0].domainName;
resultingProcessedArray.push(Object.assign(data.items[i], {domainName}));
}
return resultingProcessedArray;
} catch (err) {
console.error("Unable to fetch the data", err);
return [];
}
};
저는 편의상 이 글을 써야 했습니다.그렇지 않으면 https://github.com/mcollina/make-promises-safe 이 필요할 수도 있습니다.
export async function mapAsync<T, U>(
arr: T[],
callbackfn: (value: T, index: number, array: T[]) => Promise<U>,
thisArg?: any
) {
return await Promise.all(arr.map(async (value, index, array) => {
try {
return await callbackfn(value, index, array);
} catch(e) {
throw e;
}
}, thisArg));
}
lodasync와 같은 lib을 사용하고자 하는 생산 목적으로 휠을 재창조해서는 안 됩니다.
import { mapAsync } from 'lodasync'
const result = await mapAsync(async(element) => {
return 3 + await doSomething(element)
}, array)
그것은 약속을 사용하고, 의존성이 없으며, 최대한 빠릅니다.
약속을 이용해서.비동기 기능(즉, 약속)을 가진 각 작업에 대해 지도를 만들 수 있는 모든 것.
필터를 만들려면 먼저 비동기 맵(Promise.all을 사용)을 사용한 다음 true/false 값을 살펴보고 필터링/평가를 동기적으로 수행할 수 있습니다.
비동기 기능으로 오른쪽 기능을 줄이고 줄이려면 원래 기능을 누산기가 해결될 때까지 기다리는 새 기능으로 랩핑할 수 있습니다.
이 지식을 사용하면 원래 배열 방법을 정상/동기 기능으로 "평범한 대로" 계속 작동하지만 비동기 기능으로도 작동할 수 있도록 수정할 수 있습니다.
// a 'mini library' (save it somewhere and import it once/project)
(() => {
let AsyncFunction = Object.getPrototypeOf(async e => e).constructor;
['map', 'forEach'].forEach(method => {
let orgMethod = Array.prototype[method];
Array.prototype[method] = function (func) {
let a = orgMethod.call(this, func);
return func instanceof AsyncFunction ? Promise.all(a) : a;
};
});
['filter', 'some', 'every'].forEach(method => {
let orgMethod = Array.prototype[method];
Array.prototype[method] = function (func) {
if (func instanceof AsyncFunction) {
return (async () => {
let trueOrFalse = await this.map(func);
return orgMethod.call(this, (_x, i) => trueOrFalse[i]);
})();
}
else {
return orgMethod.call(this, func);
}
};
});
['reduce', 'reduceRight'].forEach(method => {
let orgMethod = Array.prototype[method];
Array.prototype[method] = function (...args) {
if (args[0] instanceof AsyncFunction) {
let orgFunc = args[0];
args[0] = async (...args) => {
args[0] = await args[0];
return orgFunc.apply(this, args);
};
}
return orgMethod.apply(this, args);
};
});
})();
// AND NOW:
// this will work
let a = [1, 2, 3].map(x => x * 3); // => [3, 6, 9]
let b = [1, 2, 3, 4, 5, 6, 7].filter(x => x > 3); // [4, 5, 6, 7]
let c = [1, 2, 3, 4, 5].reduce((acc, val) => acc + val); // => 15
// this will also work
let x = await [1, 2, 3].map(async x => x * 3);
let y = await [1, 2, 3, 4, 5, 6, 7].filter(async x => x > 3);
let z = await [1, 2, 3, 4, 5].reduce(async (acc, val) => acc + val);
모든 요소를 동시에 매핑하려면:
function asyncMap(arr, fn) {
return Promise.all(arr.map(fn));
}
모든 요소를 동시에 매핑하지 않으려면(예: 매핑 기능에 부작용이 있거나 모든 배열 요소를 한 번에 매핑하는 경우 리소스 비용이 너무 많이 듭니다):
옵션 A: 약속
function asyncMapStrict(arr, fn) {
return new Promise((resolve) => {
const result = [];
arr.reduce(
(promise, cur, idx) => promise
.then(() => fn(cur, idx, arr)
.then((res) => {
result.push(res);
})),
Promise.resolve(),
).then(() => resolve(result));
});
}
옵션 B: 비동기/대기
async function asyncMapStrict(arr, fn) {
const result = [];
for (let idx = 0; idx < arr.length; idx += 1) {
const cur = arr[idx];
result.push(await fn(cur, idx, arr));
}
return result;
}
내에서 비동기 함수를 호출하는 가장 좋은 방법map
a를 사용하는 것입니다.map
비동기 기능을 위해 특별히 생성되었습니다.
함수가 비동기화되려면 약속을 반환해야 합니다.
function urlToBase64(url) {
return new Promise((resolve, reject) => {
request.get(url, function (error, response, body) {
if (error) {
reject(error)
} else if (response && response.statusCode == 200) {
resolve(
"data:" + response.headers["content-type"] + ";base64," + new Buffer(body).toString('base64');
)
} else {
reject(new Error('invalid response'))
}
});
})
}
이제 매핑할 수 있습니다.
const { pipe, map, get } = require('rubico')
const metafieldTeacherData = {} // { [teacher_id]: {...}, ... }
const parseTeacher = teacher => ({
name: teacher.title,
description: teacher.body_html,
image: urlToBase64(teacher.summary_html.match(/src="(.*?)"/)[1]),
city: metafieldTeacherData[teacher.id].city,
country: metafieldTeacherData[teacher.id].country,
state: metafieldTeacherData[teacher.id].state,
studioName: metafieldTeacherData[teacher.id].studioName,
studioURL: metafieldTeacherData[teacher.id].studioURL
})
const main = async () => {
const teachers = [] // array full of teachers
const firebaseData = await map(pipe([
parseTeacher,
get('studioURL'),
urlToBase64,
]))(teachers)
console.log(firebaseData) // > ['data:application/json;base64,...', ...]
}
main()
루비코의 지도는 걱정을 합니다.Promise.all
그러니 그럴 필요는 없습니다.
IIFE와 Promise를 사용합니다.모두 간단한 사용 사례를 만들 수 있습니다.
await Promise.all(arr.map(el=>(async _=>{
// some async code
})()))
이 IIFE는 지도 함수의 반환 값으로 사용되는 약속을 반환할 수 있습니다.
(async _=>{
// some async code
})()
그래서 arr.map은 Promise에게 약속 목록을 반환합니다.모두 처리할 수 있습니다.
예
const sleep = (ms) => {
return new Promise((resolve, reject) => {
setTimeout(_ => {
resolve()
}, ms)
});
}
await Promise.all([1000,2000,3000].map(el=>(async _=>{
await sleep(el)
console.log(el)
return el
})()))
여기에 선택할 수 있는 간단한 기능이 있습니다.await
각 매핑 작업(serial
) 또는 모든 매핑을 실행합니다.parallel
.
맵퍼 기능이 a를 반환할 필요는 없습니다.promise
어느 하나.
async function asyncMap(items, mapper, options = {
parallel: true
}) {
const promises = items.map(async item => options.parallel ? mapper(item) : await mapper(item))
return Promise.all(promises)
}
타이프스크립트 버전
async function asyncMap<I, O>(items: I[], mapper: (item: I) => O, options = {
parallel: true
}): Promise<O[]> {
const promises = items.map(async item => options.parallel ? mapper(item) : await mapper(item))
return Promise.all(promises)
}
과학을 위한 작업 토막글
async function asyncMap(items, mapper, options = {
parallel: true
}) {
const promises = items.map(async item => options.parallel ? mapper(item) : await mapper(item))
return Promise.all(promises)
}
// A test to multiply number by 2 after 50 milliseconds
function delay(num) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(num * 2)
}, 50)
})
}
;
(async() => {
const data = [1, 2, 3, 4]
const resParallel = await asyncMap(data, it => delay(it))
const resSerial = await asyncMap(data, it => delay(it), {
parallel: false
})
console.log(data)
console.log(resParallel)
console.log(resSerial)
})();
언급URL : https://stackoverflow.com/questions/33438158/best-way-to-call-an-asynchronous-function-within-map
'it-source' 카테고리의 다른 글
오류: 오류 1064:SQL 구문에 오류가 있습니다. MariaDB 서버에 해당하는 설명서를 확인하십시오. (0) | 2023.10.18 |
---|---|
git diff -- patientity는 무엇을 위한 것일까요? (0) | 2023.10.18 |
C 전처리기 매크로에 전처리기 지시사항이 포함되는 것이 가능합니까? (0) | 2023.10.18 |
장고 모델:부울 필드의 기본값이 Maria에서 설정되지 않았습니다.DB (0) | 2023.10.18 |
다중 컬럼 ASC 및 DESC별 MySQL 주문 (0) | 2023.10.18 |