2016-12-10 28 views
6

powiedzmy Używam następujący kod do uruchomienia kilka obietnic w serii:Opóźnienia między obietnicami w łańcuchu obietnicy

let paramerterArr = ['a','b','c','d','e','f'] 
parameterArr.reduce(function(promise, item) { 
    return promise.then(function(result) { 
    return mySpecialFunction(item); 
    }) 
}, Promise.resolve()) 

Kod prostu wywołuje mySpecialFunction (zwraca obietnicę), czeka na obietnicy być rozwiązane, a następnie ponownie wywołuje funkcję mySpecialFunction itd. Tak więc funkcja jest wywoływana raz dla każdego elementu w tablicy, we właściwej kolejności.

Jak mogę się upewnić, że między każdą rozmową mySpecialFunction(item) występuje opóźnienie co najmniej 50 milisekund?

Ważne jest, aby obietnice były wykonywane we właściwej kolejności, a czas realizacji mySpecialFunction zmienia się za każdym razem.

Domyślam się, że synchroniczny sen będzie działał, ale nie planuję uruchomić tego kodu w osobnym wątku, więc spowoduje to irytujące ui w przeglądarce.

Nie jestem pewien, czy setTimer mógłby w jakiś sposób zostać do tego użyty. Chodzi mi o to, że nie mogę opóźnić powrotu obietnicy.

+1

To może pomóc http://bluebirdjs.com/docs/api/promise.delay.html –

+0

Już to widziałem, ale nie używam bluebirda. Używam rodzimych obietnic. (ECMA6) – Forivin

Odpowiedz

8
Odpowiedzi są dobre, ale czekają zbyt długo, ponieważ wszystkie odpowiedzi oczekują na niezależnie od tego, czy, czy faktyczna operacja zajęła już ponad 50 ms. Można używać do tego celu
const delay = ms => new Promise(resolve => setTimeout(resolve, ms)); 
let paramerterArr = ['a','b','c','d','e','f'] 
parameterArr.reduce(function(promise, item) { 
    return promise.then(function(result) { 
    return Promise.all([delay(50), mySpecialFunction(item)]); 
    }) 
}, Promise.resolve()) 
+1

Pokonaj mnie przez 37s :-) – Bergi

1

Poniżej przedstawiono przykład, jak można osiągnąć obietnicę, że nie blokuje, ale czeka na wyznaczonym okresie czasu:

function timedPromise(ms, payload) { 
    return new Promise(function(resolve) { 
     setTimeout(function() { 
      resolve(payload); 
     }, ms); 
    }) 
} 


var time = Date.now(); 

timedPromise(1000) 
    .then(function() { 
     console.log(time - Date.now()); 
     return timedPromise(2000); 
    }).then(function() { 
     console.log(time - Date.now()); 
     return timedPromise(3000); 
    }); 

więc, w zależności od tego, co dokładnie chcesz, powinny móc zrobić coś takiego:

let paramerterArr = ['a','b','c','d','e','f'] 
parameterArr.reduce(function(promise, item) { 
    return promise.then(function(result) { 
    return mySpecialFunction(item); 
    }).then(function(specialResult) { 
    return timedPromise(50, specialResult); 
    }); 
}, Promise.resolve()) 
3

naprawdę przydatna funkcja użyteczności mieć wokół jest coś, co nazywamy delay():

function delay(t, val) { 
    return new Promise(function(resolve) { 
     if (t <= 0) { 
      resolve(val); 
     } else { 
      setTimeout(resolve.bind(null, val), t); 
     } 
    }); 
} 

Następnie można go używać w łańcuchu obietnicy takich jak to:

let paramerterArr = ['a','b','c','d','e','f'] 
parameterArr.reduce(function(promise, item, index) { 
    return promise.then(function(result) { 
    // no delay on first iteration 
    var delayT = index ? 50 : 0; 
    return delay(delayT, item).then(mySpecialFunction); 
    }) 
}, Promise.resolve()); 

Można również zrobić trochę funkcję użytkową dla wykonując kolejne iteracje z opcjonalnym opóźnieniem:

// delayT is optional (defaults to 0) 
function iterateSerialAsync(array, delayT, fn) { 
    if (!fn) { 
     fn = delayT; 
     delayT = 0; 
    } 
    array.reduce(function(p, item, index) { 
     return p.then(function() { 
      // no delay on first iteration 
      if (index === 0) delayT = 0; 
      return delay(delayT, item).then(fn) 
     }); 
    }, Promise.resolve()); 
} 

A następnie użyj go tak:

iterateSerialAsync(paramerterArr, 50, mySpecialFunction).then(function(finalVal) { 
    // all done here 
}); 
1

Ją e idziesz: https://jsbin.com/suvasox/edit?html,js,console

let paramerterArr = ['a','b','c','d','e','f'] 
paramerterArr.reduce((p, val) => { 
    return p.then(() => { 
    return new Promise((res) => { 
     setTimeout(() => { res(mySpecialFunction(val)); }, 1000); 
    }); 
    }); 
}, Promise.resolve()); 

p musi być wynikiem p.then(). Tylko w ten sposób łańcuch obietnic.

Zauważ, zmieniłem go na opóźnienie 1000 ms tylko dla podkreślenia.

2

Aby uzyskać opóźnienie przynajmniej 50ms, użyj Promise.all:

function delay(t) { 
    return new Promise(function(resolve) { 
    setTimeout(resolve, t); 
    }); 
} 
parameterArr.reduce(function(promise, item) { 
    return promise.then(function() { 
    return Promise.all([ 
     mySpecialFunction(item), 
     delay(50) 
    ]); 
    }); 
}, Promise.resolve()); 
0

ponieważ wydaje się być wymóg mySpecialFunction bym go wdrożyć tam. Tak że opóźnienia funkcyjne go, jeśli to się nazywa mniej niż 50ms po ostatnim zaproszeniu

const delayBetweenCalls = (delay, fn) => { 
    let lastCall = NaN; 
    return function(/*...arguments*/){ 
     //this and arguments are both forwarded to fn 

     return new Promise(resolve => { 
      let poll =() => { 
       let delta = Date.now() - lastCall; 
       if(delta < delay){ 
        setTimeout(poll, delta - delay); 
       }else{ 
        lastCall = Date.now(); 
        resolve(fn.apply(this, arguments)); 
       } 
      } 
      poll(); 
     }) 
    } 
} 

następnie:

const mySpecialFunction = delayBetweenCalls(50, function(some, ...args){ 
    return someValueOrPromise; 
}); 

//and your loop stays the same: 
parameterArr.reduce(function(promise, item) { 
    return promise.then(function(result) { 
     return mySpecialFunction(item); 
    }) 
}, Promise.resolve()) 

więc to nie ma znaczenia gdzie/jak mySpecialFunction nazywa, zawsze będą opóźnienie wynoszące co najmniej 50 ms przed uruchomieniem kodu wewnątrz przekazanego wywołania zwrotnego.