2017-03-27 33 views
1

すべての約束が解決されたら、成功関数を実行しようとしています。しかし、約束が解決される前に成功関数が実行されます。私のコードで何が間違っているか教えてください。Promises配列が正しく実行されていません

var loadImg = function(imageUrls, success, failure) { 
    var promises = []; 
    for (var i = 0; i < imageUrls.length; i++) { 
     (function(url, promise) { 
      var img = new Image(); 
      img.onload = function() { 
       promise.resolve(); 
      }; 
      img.onerror = function() { 
       promise.reject(); 
      }; 
      img.src = url; 
     }(imageUrls[i], promises[i] = $.Deferred())); 
    } 
    $.when.apply($, promises).done(success, failure); 

} 
+4

は 'failure'引数を持たない' done'コールバック以外の、私のためにうまく動作しているようですが、2番目のコールバックは、単になど第二の画像の成功と呼ばれるものあなたはおそらく '.apply($、p rom).done(成功).fail(失敗); ' – adeneo

+0

https:// jsfiddle。net/adeneo/gn7pj5ow/ – adeneo

答えて

1

あなたには、いくつかのアクションを実行する前に完了することを約束の収集を待つしたい場合は、私はPromise.all


をお勧めしますがよ、我々はまず

は、簡単なこと loadImageユーティリティ関数を作成してURLを取得し、 PromiseHTMLImageElement

そこから、新しいloadImageユーティリティを使用してURL文字列の配列をマップするだけで、これは約束の配列になります。これはまさにPromise.allが期待しているものです。

// loadImage :: String -> Promise<HTMLImageElement> 
const loadImage = url => { 
    return new Promise((resolve, reject) => { 
    var img = new Image() 
    img.src = url 
    img.onload =() => resolve(img) 
    img.onerror = (err) => reject(err) 
    }) 
} 

const imageUrls = ['a.jpg', 'b.jpg', 'c.jpg', 'd.jpg'] 

Promise.all(imageUrls.map(loadImage)).then(
    images => console.log(images), // [<img src='a.jpg'>, <img src='b.jpg'>, ...] 
    err => console.error(err) 
) 

loadImageそれが私たちのプログラムの任意の時点で約束を使用して画像をロードする一般的な方法を提供しますので、偉大な最初のステップです。イメージが必要になるたびに、ローディングに対処する約束を手作業で構築する必要はありません。ちょうどloadImage(someUrl)に電話して、約束された画像で作業することができます。

現在、明示的なループは必要ありません。 mapforEachのような他の組み込みのループ機構を使用することができ、すべてが期待どおりに機能します。このような小さなユーティリティ関数を書くことで、最終的に少ないコードを書いています。

警告:それらのいずれかが正しくロードに失敗した場合何の画像が表示されません。


実用

この

// loadImagesForElement :: (HTMLElement, [String]) -> Promise<[HTMLImageElement]> 
const loadImagesForElement = (target, imageUrls) => { 
    return Promise.all(imageUrls.map(loadImage)).then(
    images => images.forEach(i => target.appendChild(i)), 
    err => console.error(err) 
) 
} 

loadImagesForElement(document.body, ['a.jpg', 'b.jpg', 'c.jpg']) 
// => Promise { ... } 

ような何か多分、おそらく、あなたは何とか自分のドキュメントに画像を追加したいと思いますので、代わりにconsole.logのjQuery Deferredを使用して

これは、jQueryのことは、あなたが探しているものだ場合、かなり簡単に延期に変換 - あなたはスプレッド構文に頼ることができない場合は、物事は少し醜い取得大胆

// loadImage :: String -> Promise<HTMLImageElement> 
const loadImage = url => { 
    let d = $.Deferred() 
    var img = new Image() 
    img.src = url 
    img.onload =() =>d.resolve(img) 
    img.onerror = (err) =>d.reject(err) 
    return d.promise() 
} 

// loadImagesForElement :: (HTMLElement, [String]) -> Promise<[HTMLImageElement]> 
const loadImagesForElement = (target, imageUrls) => { 
    return $.when(...imageUrls.map(loadImage)).then(
    (...images) => images.forEach(i => target.appendChild(i)), 
    err => console.error(err) 
) 
}

の変化 - 太字の変化を

// loadImagesForElement :: (HTMLElement, [String]) -> Promise<[HTMLImageElement]> 
const loadImagesForElement = (target, imageUrls) => { 
    return $.when.apply($, imageUrls.map(loadImage)).then(
    function(/* images */) { 
     Array.prototype.forEach.call(arguments, i => target.appendChild(i)) 
    }, 
    err => console.error(err) 
) 
}
+0

私はこれを試しましたが、成功関数は発生していません。 https://jsbin.com/rilixaxova/edit?js,console,output – Vinny

+1

@Vinny {img.src = url;}を忘れてしまったので約束は決して決まらなかった – Bergi

+0

@Bergiはそれをキャッチしてくれてありがとう – naomik

関連する問題