web-dev-qa-db-ja.com

JavaScript、複数の約束を待つ方法

私が達成したいこと:

  • アーティストIDを収集します `。
    • データベースでそれらを見つけるか
    • またはそれらを作成する
  • データベースにイベントを作成し、event_idを取得する
  • 両方が完了するまで待って、アーティストとイベントIDが集まります
  • アーティスト、イベントの組み合わせをループします

私が得たもの:

私はNodeとmysqlで作業しています。関係を挿入するには、アーティストが挿入または作成するのを待つ必要があります。次のコードで実行しようとします:

let promises = [];

if (artists.length != 0) {
    for (key in artists) {
        promises.Push( find_artist_id_or_create_new_artist(artists[key]) )
    }
}

await Promise.all(promises);

IDを返す:

async function find_artist_id_or_create_new_artist(artist_name) {
    return await find_artist_return_id(artist_name, create_artist_return_id)
} 

アーティストを見つける:

async function find_artist_return_id(artist_name, callback) {
    var sql = "SELECT * FROM `artists` WHERE `name` LIKE "+con.escape(artist_name)+" LIMIT 1;"

    con.query(sql, (err,row) => {
      if(err) throw err;

      if (row.length == 0) {
        return callback(artist_name)
      } else {
        return row[0].id
      }
    });
}

アーティストを作成する

async function create_artist_return_id(artist_name) {
    var sql = "INSERT INTO `artists` (`id`, `name`, `meta_1`, `meta_2`) VALUES (NULL, "+con.escape(artist_name)+", NULL, NULL)";

    con.query(sql, (err, result) => {
      if(err) throw err;

      return result.insertId
    });
}

私はcon.query関数で返すことができないことを理解していますが、これを行うためにコードを適切に設定する方法はわかりません。回答へのリンク、または回答の検索方法のヘルプは、高く評価されています。

10
bart great

基本的な_SQL functions_をpromisesにするには、awaitedに変換する必要があります。

詳細については _Async Function_Promise および Array.prototype.map() を参照してください。

_// Artist Ids.
const artistIds = await Promise.all(artists.map(async (artist) => await findArtist(artist) || await createArtist(artist)))

// Find Artist.
const findArtist = artist => new Promise((resolve, reject) => con.query(`SELECT * FROM \`artists\` WHERE \`name\` LIKE ${con.escape(artist)} LIMIT 1;`, async (error, row) => {
  if(error) return reject(error)
  if (!row.length) return resolve(await createArtist(artist)) 
  return resolve(row[0].id)
}))

// Create Artist.
const createArtist = artist => new Promise((resolve, reject) => con.query(`INSERT INTO \`artists\` (\`id\`, \`name\`, \`meta_1\`, \`meta_2\`) VALUES (NULL, ${con.escape(artist)}, NULL, NULL)`, (error, result) => {
  if (error) return reject(error)
  return resolve(result.insertId)
}))
_
7
Arman Charan

Mysqlコールバックをpromiseにラップするだけです。

 function find_artist_return_id(artist_name) {
  return new Promise((resolve, reject) => {
     var sql = "SELECT * FROM `artists` WHERE `name` LIKE "+con.escape(artist_name)+" LIMIT 1;"

      con.query(sql, (err,row) => {
         if(err) return reject(err);

         if (row.length == 0) {
           return resolve(artist_name);

           return resolve(row[0].id);      
      });
   });
}

ちなみに、これは非常に醜いです:

 if (artists.length != 0) {
   for (key in artists) {

ただやる:

  for(const artist of artists)
    promises.Push(someApiCall(artist));

または:

  const promises = artists.map(someApiCall);
1
Jonas Wilms

簡単な方法は、既存の[〜#〜] orm [〜#〜] -sequalizejsなどのように使用することです。ネイティブMySQLドライバーの個別のRawクエリ。検索や何かの作成などのAPIを使用するだけです。

私はあなたの例で非同期がどのように機能するかを説明します、私はあなたの例からコードの一部を取った。

    async function createArtist(artist_name) {
    var sql = "INSERT INTO `artists` (`id`, `name`, `meta_1`, `meta_2`) VALUES (NULL, "+con.escape(artist_name)+", NULL, NULL)";

    con.query(sql, (err, result) => {
        if(err) throw err;

        return result.insertId
    });
}

const artistId = (async () => {
    await createArtist('maxi');
})();

createArtist関数を調べてくださいこれはまさにあなたが持っているものです。ここで注意しなければならない3つの点は、

  1. 非同期関数を宣言して、デフォルトでpromiseを返すようにします。
  2. 同期関数の場合は、通常の関数のようなものを単に返すことができます。非同期の使用は避けてください。
  3. あなたが言ったように、あなたはコールバックから何も返すことができません。非同期なので、promiseを返す必要があります。

コードを次のように変更できます

    async function createArtist(artist_name) {
    return new Promise((resolve,reject)=>{
        var sql = "INSERT INTO `artists` (`id`, `name`, `meta_1`, `meta_2`) VALUES (NULL, "+con.escape(artist_name)+", NULL, NULL)";

        con.query(sql, (err, result) => {
            if(err) reject(err);
            resolve(result.insertId)
        });
    });
}

const artistId = (async () => {
    await createArtist('maxi');
})();

状況がここで変更され、非同期になる前にネイティブのpromiseラッパーが追加されて返されます。成功するために解決と呼ばれます。そして、それを失敗させることを拒否します。

エラーを処理するために、try ... catchブログを追加することを忘れないでください。

0
Vignesh