Javascript,如何等待多个承诺

时间:2018-04-03 09:48:57

标签: javascript node.js asynchronous async-await

我想要完成的事情:

  • 收集艺术家ID
    • 在db
    • 中找到它们
    • 或创建它们
  • 在db中创建一个事件,获取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函数中返回,但我不知道如何正确设置代码来完成这项工作。感谢您提供链接或帮助如何搜索答案。

3 个答案:

答案 0 :(得分:3)

您的基本SQL functions需要转换为promises才能成为awaited

有关详细信息,请参阅Async FunctionPromiseArray.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)
}))

答案 1 :(得分:0)

你只需要将mysql回调包装成promises:

 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);

答案 2 :(得分:0)

简单的方法是使用现有的 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 功能,这正是您所拥有的。你必须在这里注意三件事,

  1. 你声明它是一个异步函数,所以它默认返回promise。
  2. 它可以简单地返回任何类似普通函数的东西,如果是同步函数则避免使用异步。
  3. 正如你所说,你不能从回调中返回任何东西。因为它是异步的,你必须返回承诺。
  4. 所以代码可以改为

        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');
    })();
    

    在这里发生了变化,在异步之前添加了原生承诺包装并返回它。叫做决心取得成功。拒绝让它失败。

    不要忘记添加try ... catch博客来等待处理错误。