다음 promise 호출 과 연결된 logger.log (res) 가 반복을 통해 동 기적으로 실행 되도록 루프를 올바르게 구성하는 방법은 무엇입니까? (블루 버드)
db.getUser(email).then(function(res) { logger.log(res); }); // this is a promise
나는 다음과 같은 방법을 시도했다 ( http://blog.victorquinn.com/javascript-promise-while-loop의 방법 )
var Promise = require('bluebird');
var promiseWhile = function(condition, action) {
var resolver = Promise.defer();
var loop = function() {
if (!condition()) return resolver.resolve();
return Promise.cast(action())
.then(loop)
.catch(resolver.reject);
};
process.nextTick(loop);
return resolver.promise;
});
var count = 0;
promiseWhile(function() {
return count < 10;
}, function() {
return new Promise(function(resolve, reject) {
db.getUser(email)
.then(function(res) {
logger.log(res);
count++;
resolve();
});
});
}).then(function() {
console.log('all done');
});
작동하는 것처럼 보이지만 logger.log (res); 호출 순서를 보장하지 않는다고 생각합니다 .
어떤 제안?
답변
logger.log (res); 호출 순서를 보장하지 않는다고 생각합니다.
사실 그렇습니다. 해당 명령문은 resolve
호출 전에 실행 됩니다.
어떤 제안?
많이. 가장 중요한 것은의 사용입니다 생성 – 약속 – 수동 안티 패턴 만 할 전용 –
promiseWhile(…, function() {
return db.getUser(email)
.then(function(res) {
logger.log(res);
count++;
});
})…
둘째, 그 while
기능은 많이 단순화 될 수 있습니다.
var promiseWhile = Promise.method(function(condition, action) {
if (!condition()) return;
return action().then(promiseWhile.bind(null, condition, action));
});
셋째, while
루프 (클로저 변수 포함)를 사용하지 않고 루프를 사용합니다 for
.
var promiseFor = Promise.method(function(condition, action, value) {
if (!condition(value)) return value;
return action(value).then(promiseFor.bind(null, condition, action));
});
promiseFor(function(count) {
return count < 10;
}, function(count) {
return db.getUser(email)
.then(function(res) {
logger.log(res);
return ++count;
});
}, 0).then(console.log.bind(console, 'all done'));
답변
promiseWhen()
이 목적과 다른 목적을위한 일반적인 기능을 정말로 원한다면 Bergi의 단순화를 사용하여 꼭 그렇게하세요. 그러나 promise가 작동하는 방식으로 인해 이러한 방식으로 콜백을 전달하는 것은 일반적으로 불필요하며 복잡한 작은 후프를 뛰어 넘도록합니다.
내가 당신이 노력하고 있다고 말할 수있는 한 :
- 이메일 주소 모음에 대한 일련의 사용자 세부 정보를 비동기식으로 가져옵니다 (적어도 그게 합당한 유일한 시나리오입니다).
.then()
재귀를 통해 체인을 구축하면 됩니다.- 반환 된 결과를 처리 할 때 원래 순서를 유지합니다.
따라서 정의 된 문제는 실제로 Promise Anti-patterns의 “The Collection Kerfuffle”에서 논의 된 문제이며 , 두 가지 간단한 솔루션을 제공합니다.
- 사용하는 병렬 비동기 호출
Array.prototype.map()
- 사용 시리얼 비동기 호출
Array.prototype.reduce()
.
병렬 접근 방식은 (직접적으로) 피하려는 문제를 제공합니다. 즉, 응답의 순서가 불확실합니다. 직렬 접근 방식은 .then()
재귀없이 필요한 체인 을 구축합니다 .
function fetchUserDetails(arr) {
return arr.reduce(function(promise, email) {
return promise.then(function() {
return db.getUser(email).done(function(res) {
logger.log(res);
});
});
}, Promise.resolve());
}
다음과 같이 전화하십시오.
//Compose here, by whatever means, an array of email addresses.
var arrayOfEmailAddys = [...];
fetchUserDetails(arrayOfEmailAddys).then(function() {
console.log('all done');
});
보시다시피 추악한 외부 var count
또는 관련 condition
함수 가 필요하지 않습니다 . 제한 (문제에서 10 개)은 전적으로 배열의 길이에 의해 결정됩니다 arrayOfEmailAddys
.
답변
표준 Promise 객체로 수행하는 방법은 다음과 같습니다.
// Given async function sayHi
function sayHi() {
return new Promise((resolve) => {
setTimeout(() => {
console.log('Hi');
resolve();
}, 3000);
});
}
// And an array of async functions to loop through
const asyncArray = [sayHi, sayHi, sayHi];
// We create the start of a promise chain
let chain = Promise.resolve();
// And append each function in the array to the promise chain
for (const func of asyncArray) {
chain = chain.then(func);
}
// Output:
// Hi
// Hi (After 3 seconds)
// Hi (After 3 more seconds)
답변
주어진
- asyncFn 함수
- 항목 배열
필수
- Promise Chaining .then () ‘s in series (순서대로)
- 네이티브 es6
해결책
let asyncFn = (item) => {
return new Promise((resolve, reject) => {
setTimeout( () => {console.log(item); resolve(true)}, 1000 )
})
}
// asyncFn('a')
// .then(()=>{return async('b')})
// .then(()=>{return async('c')})
// .then(()=>{return async('d')})
let a = ['a','b','c','d']
a.reduce((previous, current, index, array) => {
return previous // initiates the promise chain
.then(()=>{return asyncFn(array[index])}) //adds .then() promise for each item
}, Promise.resolve())
답변
이를 해결하는 새로운 방법이 있으며 async / await를 사용하는 것입니다.
async function myFunction() {
while(/* my condition */) {
const res = await db.getUser(email);
logger.log(res);
}
}
myFunction().then(() => {
/* do other stuff */
})
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
https://ponyfoo.com/articles/understanding-javascript-async-await
답변
Bergi가 제안한 기능은 정말 좋습니다.
var promiseWhile = Promise.method(function(condition, action) {
if (!condition()) return;
return action().then(promiseWhile.bind(null, condition, action));
});
그래도 약속을 사용할 때 의미가있는 작은 추가 작업을하고 싶습니다.
var promiseWhile = Promise.method(function(condition, action, lastValue) {
if (!condition()) return lastValue;
return action().then(promiseWhile.bind(null, condition, action));
});
이렇게하면 while 루프를 promise 체인에 포함하고 lastValue로 해결할 수 있습니다 (또한 action ()이 실행되지 않는 경우). 예를보십시오 :
var count = 10;
util.promiseWhile(
function condition() {
return count > 0;
},
function action() {
return new Promise(function(resolve, reject) {
count = count - 1;
resolve(count)
})
},
count)
답변
나는 다음과 같이 만들 것이다.
var request = []
while(count<10){
request.push(db.getUser(email).then(function(res) { return res; }));
count++
};
Promise.all(request).then((dataAll)=>{
for (var i = 0; i < dataAll.length; i++) {
logger.log(dataAll[i]);
}
});
이런 식으로 dataAll은 기록 할 모든 요소의 정렬 된 배열입니다. 그리고 모든 약속이 완료되면 로그 작업이 수행됩니다.
