2017-06-15 4 views
0

次のコードは、いくつかのフォームフィールドをループします。フィールドをアップロードする必要があるファイルの場合は、api.uploadPhoto関数を実行します(写真がアップロードされたらペイロードを設定します)。ペイロードが直接設定されているときにフィールドが通常の入力である場合:コードをハングさせずに次の約束を取り除くには?

formFields.forEach(field => { 
    if (hasUploadFiles(field)) { 
    uploadPhotoPromise = new Promise((resolve, reject) => { 
     uploads.queued.push(file) 
     api.uploadPhoto(file, field).then(uploadedPhoto => { 
     uploads.finished.push(field) 
     if (uploads.queued.length === uploads.finished.length) { 
      payload[field.name] = uploadedPhoto 
      resolve() 
     } else { 
      reject() 
     } 
     }).catch(error => { 
     console.log('error:', error) 
     reject() 
     }) 
    }).catch(error => { 
     console.log('error:', error) 
    }) 
    } else { 
    payload[field.name] = field.value 
    } 
}) 

Promise.all([uploadPhotoPromise]).then(values => { 
    // update action 
} 

コードは機能します。しかし、それらのすべてcatchはちょっと乱雑に見えます。

私はそれらを削除しようとしましたが、いずれかを削除するとコードがハングします(Promise.allのコードは実行されません)。どうしてこれなの?どのようにして、このコードを、ハングさせずにすべてのcatchステートメントを使わずにリファクタリングするのですか?

オリジナルコード(プラスBergiの提案の変更):

const buildingFormPromise = utils.mapDeep(this.buildingForm.schema, field => { 
    if (!field.name) return // fields not in the database 
    else if (utils.hasUploadFiles(field)) { 
    utils.eachCall(field.value, (file, index) => { 
     field.userId = this.user.id 
     this.uploads.queued.push(file) 
     this.$set(this.uploads.queued, index, { progress: 30 }) 
     return api.uploadPhoto(file, field).then(uploadedPhoto => { 
     this.$set(this.uploads.queued, index, { progress: 100 }) 
     return loadImage(uploadedPhoto,() => { 
      this.uploads.finished.push(field) 
      if (this.uploads.queued.length === this.uploads.finished.length) { 
      console.log('This runs after the code inside Promise.all') 
      buildingPayload[field.name] = uploadedPhoto 
      } 
     }) 
     }) 
    }) 
    } else { 
    return Promise.resolve(buildingPayload[field.name] = field.value) 
    } 
}) 

Promise.all([buildingFormPromise]).then(values => { 
    console.log('This runs before the files are uploaded') 
}) 
+0

「ハングさせない」とはどういう意味ですか? – Bergi

+0

2つのこと:1)Promiseの配列を作成しない。各反復ごとに1つの 'uploadPhotoPromise'が繰り返しています。 2)最初の 'catch()'では 'resolve()'を呼び出すことはできません。なぜなら、あなたはこの関数にアクセスすることができず、あなたは約束外にいるからです。このコードは、おそらく 'catch 'の内部に入っていないため動作します。そうでなければ、Promisesをどのように使うのかは分かりません。 – vassiliskrikonis

+0

このコードは、不要な 'catch'esよりも間違っています。 'uploadPhotoPromise'で' Promise.all'が動作するとは思っていません。キューイングのロジックは非常に怪しいです(キューではありませんが、並列でも動作しません)。そして、 'Promise'コンストラクタアンチパターン](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it)。コードが実際に 'formFields'で何をしたいのですか? – Bergi

答えて

1

あなたはPromise.allにすべての約束の配列を渡す必要がある、とあなたがPromise constructor antipatternを避ける必要があります。個々のアップロードエラーを処理したくない場合は、.catchを最後まで移動できます。

var fieldValuePromises = formFields.map(field => { 
    if (hasUploadFiles(field)) { 
    return api.uploadPhoto(file, field).then(uploadedPhoto => { 
     return payload[field.name] = uploadedPhoto; 
    }); 
    } else { 
    return Promise.resolve(payload[field.name] = field.value); 
    } 
}); 

Promise.all(fieldValuePromises).then(values => { 
    // update action 
}).catch(error => { 
    // at least one upload failed 
    console.log('error:', error) 
}); 
+0

ありがとう私はそれを試してみてください! 1つの質問:else文だけに 'Promise.resolve'が必要ですか?すべてのフィールドがアップロードフィールドの場合はどうなりますか? – alex

+0

はい、ifの場合、 '()'を 'uploadPhoto()'に連鎖した結果、すでに約束を返しています。厳密には、 'Promise.all'もプレーンな値を解決するので、elseの場合の約束事は必要ありませんが、' fieldValuePromises'には約束だけが含まれている方が良いでしょう。 – Bergi

+0

奇妙なことに、 'Promise.all'はファイルがアップロードされる前に実行されます。 (私は私の質問に元のコードを含めた)。 – alex

関連する問題