javascript 페이지 약속에 의해 반환 된 첫 번째 사실을 기다리는 깨끗한 방법




팝업 타이틀 바꾸기 (5)

나는 현재 배열에서 세 가지 약속을 해고하는 일을하고 있습니다. 지금과 같은 모습입니다.

var a = await Promise.all([Promise1(), Promise2(), Promise3()]);

이제 그 약속들은 모두 진실하거나 거짓이 될 것입니다. 그러나 현재 나는 그들 모두가 끝날 때까지 기다리고 있으며, 그 중 하나가 진실로 돌아 오면 곧 갈 수 있습니다.

나는 그것을 성취 할 방법을 생각했지만, 모두보기 흉하게 보입니다. 이 과제를 어떻게 풀려고합니까?


주어진 약속이 다음과 같이 true 대로 해결되는 즉시 해결할 새로운 약속 을 만들 수 있습니다.

function promiseRaceTrue(promises) {
    return new Promise(function(resolve, reject) {
        promises.forEach(promise =>
            promise.then(val => val === true && resolve())
            // TODO handle resolve with value of "false"?
            // TODO handle rejection?
        );
        // TODO handle all resolved as "false"?
    });
}

var a = await promiseRaceTrue([Promise1(), Promise2(), Promise3()]);

Promise.race 와 비슷하게 작동하지만 주어진 약속 중 하나가 해결되거나 거부되는 즉시 해결되지 않고 주어진 약속 중 하나가 true 로 해석되면 해결됩니다.


기본적으로 some() 원합니다.

  • Promise.all() 은 모든 약속이 완료 될 때까지 기다릴 수 있기 때문에 작동하지 않습니다.
  • Promise.race() 는 1 Promise의 해결책 만 반환하기 때문에 혼자 작동하지 않습니다.

대신, 우리는 약속의 배열을 받아야하고, 그 중 하나가 true 로 돌아올 때까지 계속해서 경주해야합니다. 우리는 그만 두어야합니다. 그 중 아무 것도 사실이 아니라면, 우리는 여전히 멈출 필요가 있습니다. 그러나 우리는 그 중 아무 것도 사실이 아니라는 것을 알아야합니다.

테스트 하니스와 함께 다음 예제를 고려하십시오.

암호

/**
 * Promise aware setTimeout based on Angulars method
 * @param {Number} delay How long to wait before resolving
 * @returns {Promise} A resolved Promise to signal the timeout is complete
 */
function $timeout(delay) {
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve(), delay);
    });
}

/**
 * Return true (early) if any of the provided Promises are true
 * @param {Function(arg: *): Boolean} predicate The test the resolved Promise value must pass to be considered true
 * @param {Promise[]} arr The Promises to wait on
 * @returns {Promise<Boolean>} Whether one of the the provided Promises passed the predicate
 */
async function some(predicate, arr) {
    // Don't mutate arguemnts
    const arrCopy = arr.slice(0);

    // Wait until we run out of Promises
    while(arrCopy.length){
        // Give all our promises IDs so that we can remove them when they are done
        const arrWithIDs = arrCopy.map((p, idx) => p.then(data => ({idx, data})));
        // Wait for one of the Promises to resolve
        const soon = await Promise.race(arrWithIDs);
        // If it passes the test, we're done
        if(predicate(soon.data))return true;
        // Otherwise, remove that Promise and race again
        arrCopy.splice(soon.idx, 1);
    }
    // No Promises passed the test
    return false;
}

// Test harness
const tests = [
    function allTrue(){
        console.log(new Date());
        return some((v)=>v, [
            $timeout(1000).then(() => true),
            $timeout(2000).then(() => true),
            $timeout(3000).then(() => true)
        ]).then(d => {
            console.log(d);
            console.log(new Date());
        });
    },
    function twoSecondsTrue(){
        console.log(new Date());
        return some((v)=>v, [
            $timeout(1000).then(() => false),
            $timeout(2000).then(() => true),
            $timeout(3000).then(() => true)
        ]).then(d => {
            console.log(d);
            console.log(new Date());
        });
    },
    function threeSecondsTrue(){
        console.log(new Date());
        return some((v)=>v, [
            $timeout(1000).then(() => false),
            $timeout(2000).then(() => false),
            $timeout(3000).then(() => true)
        ]).then(d => {
            console.log(d);
            console.log(new Date());
        });
    },
    function allFalse(){
        console.log(new Date());
        return some((v)=>v, [
            $timeout(1000).then(() => false),
            $timeout(2000).then(() => false),
            $timeout(3000).then(() => false)
        ]).then(d => {
            console.log(d);
            console.log(new Date());
        });
    }
]

tests.reduce((acc, curr) => acc.then(()=>curr()), Promise.resolve());

산출

// 1 Second true
2018-07-03T18:41:33.264Z
true
2018-07-03T18:41:34.272Z

// 2 Seconds true
2018-07-03T18:41:34.273Z
true
2018-07-03T18:41:36.274Z

// 3 Seconds true
2018-07-03T18:41:36.274Z
true
2018-07-03T18:41:39.277Z

// 3 Seconds false
2018-07-03T18:41:39.277Z
false
2018-07-03T18:41:42.282Z

str의 대답을 앞두고 콜백을 제공하는 기능을 추가하고 싶습니다.이 기능은 true/false 약속 이상에서 작동합니다.

콜백을 추가하면 Promise의 결과를 테스트하고 콜백 필터 ( true/false 값을 반환해야 함)와 성공적으로 일치하는 약속을 반환 할 수 true/false .

Promise.until = function(callback, ...promises) {
  return new Promise(function(resolve, reject) {
    promises.forEach(promise =>
      promise.then(val => callback(val) === true && resolve(val))
    )
  })
}

// Create some functions that resolve true/false
function Promise1() {return new Promise(resolve => setTimeout(()=> resolve(false), 1000))}
function Promise2() {return new Promise(resolve => setTimeout(()=> resolve(true), 3000))}
function Promise3() {return new Promise(resolve => setTimeout(()=> resolve(false), 1000))}

// Create som functions that resolve objects
function Promise4() {return new Promise(resolve => setTimeout(()=> resolve({a:1}), 1000))}
function Promise5() {return new Promise(resolve => setTimeout(()=> resolve({a:2}), 3000))}
function Promise6() {return new Promise(resolve => setTimeout(()=> resolve({a:123}), 1000))}

// Create some functions that resolve strings
function Promise7() {return new Promise(resolve => setTimeout(()=> resolve('Brass'), 1000))}
function Promise8() {return new Promise(resolve => setTimeout(()=> resolve('Monkey'), 500))}
function Promise9() {return new Promise(resolve => setTimeout(()=> resolve(['Brass', 'Monkey']), 100))}

// Once one resolves `true` we will catch it
Promise.until(result => result === true, Promise1(), Promise2(), Promise3())
  .then(result => console.log(result));

// Once one resolves where `a` equals 123, we will catch it
Promise.until(result => result.a === 123, Promise4(), Promise5(), Promise6())
  .then(result => console.log(result));
  
// Once one resolves where `a` equals 123, we will catch it
Promise.until(result => result === 'Monkey', Promise7(), Promise8(), Promise9())
  .then(result => console.log(result));


Promise.racePromise.all 을 결합하여 구현할 수 있습니다.

function firstTrue(promises) {
    const newPromises = promises.map(p => new Promise(
        (resolve, reject) => p.then(v => v && resolve(true), reject)
    ));
    newPromises.push(Promise.all(promises).then(() => false));
    return Promise.race(newPromises);
}

위의 코드 테스트 :

function firstTrue(promises) {
  const newPromises = promises.map(p => new Promise(
    (resolve, reject) => p.then(v => v && resolve(true), reject)
  ));
  newPromises.push(Promise.all(promises).then(() => false));
  return Promise.race(newPromises);
}

var test = values => firstTrue(
  values.map((v) => new Promise((resolve) => {
    setTimeout(() => resolve(v), Math.round(Math.random() * 1000));
  }))
).then((ret) => console.log(values, ret));

test([true, true, true]);
test([false, false, false]);
test([true, false, false]);
test([false, true, false]);
test([false, false, true]);


Promise.race 하고 값이 true 일 때 초기 약속 만 해결할 수 있습니다.

const doSomething = (bool, val)=>{
  return new Promise((resolve, reject)=>{
     if (bool){
        resolve(val)
     }
  })
}

const promise1 = doSomething(false,'one')
const promise2 = doSomething(false,'two')
const promise3 = doSomething(true,'three')
const promise4 = doSomething(true,'four')
const promise5 = doSomething(true,'five')

Promise.race([promise1, promise2, promise3, promise4, promise5]).then(value => {
  console.log('First true one to resolve is: ', value);
  
});





promise