2016-06-21 15 views
1

私は雄弁なjavascriptを通過しており、promise.allを実装する必要があります。ここに私の解決策があります。javascriptの実装はpromise.allが機能していませんか?

function all(promises) { 
    return new Promise(function(success, fail) { 
    var results = []; 
    var failed = false; 
    promises.forEach(function(promise) { 
     promise.then(function(result) { 
     results.push(result); 
     }, function (error) { 
     failed = true; 
     fail(error); 
     }); 
    }); 
    if (!failed) 
     success(results); 
    }); 
} 

これは私が実行しているテストです。私たちは、[]

必要があります:[3、2、1] []

これは次のようになります。私のコードは、これは[]でなければなりません

を出力していますbecuase、明らかに間違っている

// Test code. 
all([]).then(function(array) { 
    console.log("This should be []:", array); 
}); 
function soon(val) { 
    return new Promise(function(success) { 
    setTimeout(function() { success(val); }, 
       Math.random() * 500); 
    }); 
} 
all([soon(1), soon(2), soon(3)]).then(function(array) { 
    console.log("This should be [1, 2, 3]:", array); 
}); 
function fail() { 
    return new Promise(function(success, fail) { 
    fail(new Error("boom")); 
    }); 
} 
all([soon(1), fail(), soon(3)]).then(function(array) { 
    console.log("We should not get here"); 
}, function(error) { 
    if (error.message != "boom") 
    console.log("Unexpected failure:", error); 
}); 

ここに来ないでください

最初のものが唯一正しいものです。 基本的に私の欠陥があるビューから、私が書いたものを作品と同じであり、ここで見つけることができ、実際のソリューション: http://eloquentjavascript.net/code/#17.2

私のコードは動作しないのはなぜ?どうしたの?

+3

@AliTorabiはジャークてはいけません。プログラミングや言語の理解を深めるために、ホイールを再発明することが重要な場合もあります。 –

+0

@AliTorabi学習の練習として、よく理解するために共通の機能を再実装することは良いことです。私の理解は、これがOPの目標だということです。 – Timo

+0

私はもはやじゃない。コードと質問の操作 –

答えて

0

あなたはとても速く

if (!failed)     
    success(results); 

に達しました。すべての約束が完了し、それが最後のものであれば、すべてが解決されます。

function all(promises) { 
    return new Promise(function(success, fail) { 
     var results = []; 
     var failed = false; 
     promises.forEach(function(promise) { 
      promise.then(function(result) { 

       results.push(result); 

       if (results.length == promises.length) { 
        if (!failed) 
         success(results); 
       } 
      }, function (error) { 

       failed = true; 
       fail(error); 
      }); 
     }); 


    }); 
} 

あなたの機能をテスト:

all([soon(1), fail(), soon(3)]).then(function(array) { 
    console.log("We should not get here"); 
}, function(error) { 
    console.log("Fail"); 
    if (error.message != "boom") 
     console.log("Unexpected failure:", error); 
}); 

しかし、それはまだ結果の順序付けの欠如を持っています。

+0

注文がないことは別として、空の入力に対しても機能しません。 – Bergi

1

forEachが同期すると、約束が解決される前にif (!failed)ステートメントが実行されます。あなたは、次の操作を行うことができます。

あなたはたとえば、秩序を保つことができるスパース配列を使用して
function all(promises) { 
    var results = [], 
     left = promises.length; 
    if (!left) { 
    return Promise.resolve(results) 
    } 
    return new Promise((res, rej) => { 
    promises.forEach((p, i) => { 
     Promise.resolve(p).then(x => { 
     results[i] = x 
     left -= 1 
     if (left === 0) { 
      res(results) 
     } 
     }, rej) 
    }) 
    }) 
} 

:他人として

function timeout(n) { 
    return new Promise((res) => { 
    setTimeout(() => { 
     res(n) 
    }, n) 
    }) 
} 

var pa = timeout(200) 
var pb = timeout(300) 
var pc = timeout(100) 

// success 
all([pa, pb, pc]).then(console.log).catch(console.log) //=> [200, 300, 100] 


// error 
var pd = Promise.reject('error') 

all([pa, pb, pc, pd]).then(console.log).catch(console.log) //=> error 
+0

これは、最後の約束が最後に成立したときにのみ機能するようです。空の入力に対しても機能しません。そして、私は '.then(...、rej)'をシンプルさのために 'catch 'なしでお勧めしたいと思います。 – Bergi

+0

ああ、あなたは@Bergiが間違っています。 – elclanrs

+0

私の編集を参照してください。うまくいけば、今回はすべてのケースをカバーします。 – elclanrs

0

は、あなたの約束は解決した前であっても、すぐに、あなたの.forEach完了を言及しています。 .forEachの各約束については、非同期計算が完了するまでに多少時間がかかります。このexerciseの場合、時刻はMath.random() * 5000です。

したがって、各繰り返しでは、最終的な結果は「約束」され、.forEachが続きます。だから空の配列を得る:[].forEachはあなたの約束が解決する前に完了しました。

あなたがしたいことは、すべての約束を追跡し、3つの約束があるとすぐにresultsアレイのsuccessハンドラに電話することができます。これは、各約束の.then()に渡されたハンドラの外にあるクロージャ変数を保持することによって行うことができます。それぞれの約束が完了すると、その変数を増分することができます。私の解決策では、私は、この変数countの名前:

function all(promises) { 
    return new Promise(function(success, fail) { 
    if (promises.length === 0) { 
     return success([]); 
    } 
    const results = []; 
    let count = 0; 

    for (let i = 0; i < promises.length; i++) { 
     promises[i].then(val => { 
     results[i] = val; 
     count++; 

     if (count === promises.length) { 
      return success(results); 
     } 
     }).catch(err => fail(err)); 
    } 
    }); 
} 
関連する問題