2016-08-29 2 views
5

필자는 동기화 작업이 필요한 약속 개체를 보유하고 있습니다. 예를 들어 첫 번째 약속이 완료되기 전에 두 번째 약속이 작동해서는 안됩니다. 첫 번째가 거절하면 먼저 다시 실행해야합니다.약속 개체를 동기화하는 방법?

몇 가지 예를 구현했습니다.이 중 하나가 효과적입니다. 반환, GETVAL 전화 2000ms 대기 , 나는 ++, 다시

getVal() { 
     return new Promise(function(resolve, reject) { 
     setTimeout(function(){ resolve(19) }, 2000); 
     }); 

    } 

async promiseController(){ 

    for(var i =0;i<5;i++) 
     { 
     var _val = await this.getVal() 
     console.log(_val+'prom'); 
     } 
    } 

..... GETVAL를 호출하지만 약속 객체의 배열을 제어 할 필요가있다. 내가 원하는 것은 데이터가 있고 그것을 5 조각으로 나누었습니다. 첫 번째 부분이 처리 된 후 (예 : 서버로 전송) 잘 두 번째 부분을 처리하려면 그렇지 않으면 첫 번째 부분을 다시 처리해야합니다.

는이 코드가 순차적으로 작동에

getVal() { 
    return new Promise(function(resolve, reject) { 
    setTimeout(function(){ resolve(19) }, 2000); 
    }); 

} 

async promiseController(){ 
    var proms=[] 
    for(var i =0;i<5;i++) 
    { 
     proms.push(this.getVal()) 
    } 

for(var i =0;i<5;i++) 
    { 
    var _val = await proms[i] 
    console.log(_val+'prom'); 
    } 
} 

약속 개체를 만든 프로토 타입 구현입니다. 첫 번째 예제처럼 동기식으로 작동하도록 아래 코드를 어떻게 수정합니까?

+1

당신이 ['Promise.all()'] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)을 수행하려고하는지 알 수 없습니다./모두) 또는 당신이 당신의 약속이 Waterfall 타입의 것을 더 원한다면. – zero298

+0

promise.all()이 작동하지 않습니다. 약속을 지키면 라인을 거부합니다. 내 상황에서 나는 그들 모두가 그렇지 않으면 쓸모가 없어야한다. –

+0

첫 번째 약속을 되 돌리는 재귀 호출이 해결되지 않는다면 예상되는 결과는 무엇입니까? – guest271314

답변

3
async promiseController(){ 
    for(const value of array) { 
    console.log((await this.getVal(value))+'prom'); 
    } 
} 

일을 복잡하게 할 필요가 있습니다. 루프 안에 await으로 전화하면 원하는 것을 기다리게됩니다.

다른 답변이 정당하게 말한대로 - 약속은 을 나타내며 조작이 아닙니다. 작업의 경우 일반 함수가 사용됩니다.

오류를 무시하려는 경우 .catch(() => {})을 약속 할 수 있습니다. 당신이 실패 할 때까지 다시 시도하십시오 - 당신은 함수에 다시 시도하고 사용 리팩토링 수 :

const retry = fn => (...args) => fn(...args).catch(retry(fn)); 
+0

감사하지만 내가 질문에 언급했듯이 나는 약속의 배열을 가지고있다. getVal이 나를 위해 작동하지 않는다 –

+0

그것은 0에서 4까지 반복하는 대신 값을 반복한다. 나는이 예제를 업데이트하여 0 대신에 –

+0

을 의미한다 (this.getVal (value)를 기다린다) 또는 (await value) –

1

첫 번째 약속이 해결 될 때까지 "후속 약속을 실행하지 않는 것이 목표라면, 약속이 비동기 활동 인 이 이미에 있음을 명심해야합니다. 일단 약속이 이루어지면, 너무 늦었습니다.

첫 번째 약속이 완료 될 때까지 후속 약속 팩토리 메서드를 호출하지 않아도됩니다. 첫 번째 예제에서는 이전 약속이 완료 될 때까지 getVal()을 호출하지 않음으로써이 작업을 수행합니다.

그래서 당신은 같은 것을 끝낼 없습니다 :

delay(time) { 
    return new Promise(resolve => setTimeout(resolve, time)); 
} 

async promiseController() { 
    const factories = []; 
    for (let i = 0; i < 5; ++i) { 
     factories.push(() => this.getVal()); 
    } 

    for (const f of factories) { 
     // keep running this factory until it succeeds 
     let success = false; 
     while (!success) { 
      try { 
       const promise = f(); 
       const result = await f; 
       success = true; 
       console.log(`result = ${result}`); 
      } 
      catch (err) { 
       console.log("promise failed. retrying"); 
       await delay(100); 
      } 
     } 
    } 
} 
+0

감사합니다. '첫 번째 예제는 이전 약속이 완료 될 때까지 getVal()을 호출하지 않음으로써이를 수행합니다.' 두 번째 예제가 잘못되었습니다. this.getVal()을 기다리는 것과 proms [i]를 기다리는 것의 차이점은 무엇입니까? 둘 다 약속 안해도 되나요? –

1

당신은 재귀라는 기능을 사용할 수 있습니다, .then()

var arr = [Promise.resolve("a") 
 
      , Promise.resolve("b") 
 
      , Promise.resolve("c")]; 
 
var i = 0; 
 
var res = []; 
 

 
function foo() { 
 
    // conditional resolved or rejected promise 
 
    var n = String(new Date().getTime()).slice(-1); 
 
    // if `n` < 5 reject `n` , else resolve `n` 
 
    var curr = n < 5; 
 
    return curr ? arr[i] : Promise.reject(["rejected", n]) 
 
} 
 

 
var p = (function repeat() { 
 
    var promise = foo(); 
 
    return promise 
 
    .then(function(data) { 
 
     console.log(data); 
 
     res.push(data); 
 
     ++i; 
 
     if (i < arr.length) return repeat() 
 
     // return `res` array when all promises complete 
 
     else return res 
 
    }) 
 
    .catch(function(err) { 
 
     console.log(err); 
 
     if (err[0] === "rejected") return repeat() 
 
    }) 
 
}()); 
 

 
p.then(function(complete) { 
 
    console.log("complete:", complete) 
 
});

1

음 OK . 나는 적절한 함수 프로그래밍 목적을 위해서 asyncawait을 피해야한다고 생각한다. 나는 약속이 매우 충분하다고 믿는다. 그러나 C++ ish 명령형으로 계속 코딩하려면 asyncawait을 사용하십시오.

필자는 동기화 작업이 필요한 약속 개체가 있습니다. 예를 들어 첫 번째 약속이 완료되기 전에 두 번째 약속이 작동해서는 안됩니다. 처음 하나가 을 거절하면 다시 실행해야합니다.

아래 코드에 대해 간단히 설명하겠습니다. 우리는 데이터와 콜백을 취하는 async() 함수를 가지고 있습니다 (첫 번째 오류 유형). 데모 목적으로는 2000ms 이내에 데이터로 콜백을 호출하려고 시도하지만 1000ms에 타임 아웃이 있습니다. 따라서 50-50은 데이터 또는 오류가있는 콜백을 호출합니다.

promisify()의 도움으로 그것을 약속하고 async() 함수를 사용하고 나에게 asyncPro() 함수를 반환하므로 실제로 우리에게 약속을 되돌려 줄 필요가 있습니다. 실제로는 async()과 동일하지만 대신 약속을 반환합니다. 따라서 then 단계에서 콜백을 사용해야합니다.

그런 다음 데이터를 취하는 tryNTimes(data,asyncFun,n = 5) 함수, 약속 된 비동기 함수 및 거부하기 전에 시도 할 횟수를 지정하는 정수가 제공됩니다. 기본 시도 횟수는 5이지만 세 번째 인수를 전달하여 모든 값으로 설정할 수 있습니다.

마지막 부분은 Array.prototype.reduce()의 도움으로 완벽하게 우리의 약속을 이어주는 flowControl()입니다.

이제 우리는 우리의 모든 약속을 하나씩 이어지며 5 번 시도하기 전에 어떤 것도 실패 할 것입니다.

당신이 오류가 자주 async() 함수에서 시간 초과 값을 낮추십시오 "5 회 시도"보고 싶은 경우

function promisify(fun){ 
 
    return (data) => new Promise((resolve,reject) => fun(data, (err,res) => err ? reject(err) : resolve(res))); 
 
} 
 

 
function async(data, callback){ 
 
    var dur = Math.floor(Math.random()*2000); 
 
    setTimeout(_ => callback(false,data),dur);   // may resolve before timeout 
 
    setTimeout(_ => callback("error at " + data),1000); // timeout at 1 sec 
 
} 
 

 
function tryNTimes(data,asyncFun,n = 5){ 
 
    return new Promise((resolve,reject) => { n === 0 && reject("try out fail at 5 tries: " + data); 
 
              asyncFun(data).then(v => resolve("resolved at countdown " + n + ": " + v)) 
 
                 .catch(e => resolve(tryNTimes(data,asyncFun,--n))); 
 
             }); 
 
} 
 

 
function flowControl(d,f,tc){ 
 
    return d.reduce((prom,chunk) => prom.then(v => { console.log(v); 
 
                return tryNTimes(chunk,f,tc); 
 
               }),Promise.resolve("initial dummy promise")); 
 
} 
 

 
var data = ["chunk_1", "chunk_2", "chunk_3", "chunk_4", "chunk_5"], 
 
asyncPro = promisify(async);       // now our async function returns a promise 
 

 
flowControl(data,asyncPro).then(v => console.log(v)) 
 
          .catch(e => console.log(e));
.

+0

에 감사드립니다. 나는 한 걸음도 이해하지 못했다. Promise에는 executer 함수가 있으며이 함수는 즉시 실행됩니다 (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).이 함수를 비동기 적으로 만들었습니까? 이 함수를 비동기로 만들면 함수가 즉시 호출되지 않을 수 있습니다. –

+0

@Burak Karasoy '비동기'가 아닙니다. 네, promise 객체를 생성 할 때 executer 함수를 실행 시켰습니다.이 예제에서 executer는'promisfy' 함수에 있습니다 ..'(resolve, reject) => fun (data, (err, res) => err? reject (err) : resolve (res))'그것은 비동기 함수의 해석이나 거부를 기다리는 promise 객체를 동 기적으로 실행하고 리턴한다. 'asyncPro = promisify (async); 명령을 보면'async' 함수가'promisfy'의'fun' 인수가되고 executer의'resolve'와'reject' 콜백은'async' 함수 – Redu

+0

에 제공됩니다 promisify()는 약속을 반환하지 않습니다. 약속을 반환하는 함수를 반환합니다. 약속이 바로 트리거되지 않지만 메서드가 올바르게 호출 된 이유는 무엇입니까? 이 상황에서 메소드의 이름은 비동기가되어야합니까? 또는 setTimeout (..)이 있기 때문에 비동기라고 부르셨습니까? 비동기 대신 _asyncFunc로 지정할 수 없습니다. –