承诺不像我期望的那样表现

时间:2016-10-26 00:25:28

标签: javascript ecmascript-6 sequelize.js es6-promise

我使用Express进行路由,使用Sequelize进行数据库管理。

app.get('/api/users/:username', (req, res) => {
  let username = req.params.username;
  findChattersPerRole()
    .then(chattersPerRole => {
      console.log('instakbot should\'ve been added by now...');
    });
});

函数findChattersPerRole返回一个对象,每个用户的用户名和角色作为另一个对象。

const findChattersPerRole = () => {
  return fetch('https://tmi.twitch.tv/group/user/instak/chatters')
    .then(parseJSON)
    .then(r => {
      let chatters = r.chatters;
      let chattersPerRole = Object.keys(chatters).map(role => {
        return chatters[role].map(username => {
          console.log('findOrCreateViewer will be executed after this');
          findOrCreateViewer(username, role);
          return {
            username: username,
            role: role
          };
        });
      });
      return Promise.resolve(flattenDeep(chattersPerRole));
    }).catch(err => {
      console.log(`Error in fetch: ${err}`);
    });
};

问题是,在我的路线中,我希望在我的观众插入数据库之后执行console.log('instakbot should\'ve been added by now...');,因为在我的函数findChattersPerRole中我已经使用函数findOrCreateViewer插入它们。我希望这会发生,因为在我的路线中,当findChattersPerRole()被解析时,我编写了console.log ...

const findOrCreateViewer = (username, role) => {

  return Viewer.findOrCreate({
    where: {
      username
    },
    defaults: {
      instakluiten: 5,
      role
    }
  }).spread((unit, created) => {
    console.log('unit is: ', unit.dataValues.username);
    if(created){
      return `created is ${created}`;
    }else{
      return unit;
    }
  });

};

然而,在我的终端中你可以看到这不是它发生的方式......为什么我的承诺没有在预期的时间执行? Screenshot of my terminal

2 个答案:

答案 0 :(得分:2)

调用函数后立即return {username: ...}发生findOrCreateViewer(username, role);,插入任何数据之前发生。这也意味着return Promise.resolve(flattenDeep(chattersPerRole));在插入任何数据之前发生等等。

你说findOrCreateViewer会返回一个承诺,所以你需要等到该承诺得到解决(即等到数据插入之后),然后再继续其他内容。

您希望chattersPerRole成为(数组)承诺的数组,并且只有在所有承诺得到解决后才能继续

Promise.all很容易做到:

const findChattersPerRole = () => {
  return fetch('https://tmi.twitch.tv/group/user/instak/chatters')
    .then(parseJSON)
    .then(r => {
      let chatters = r.chatters;
      let chattersPerRole = Object.keys(chatters).map(
        role => chatters[role].map(username => {
          console.log('findOrCreateViewer will be executed after this');
          return findOrCreateViewer(username, role).then(
            () => ({username, role})
          );
        });
      );
      return Promise.all(flattenDeep(chattersPerRole));
    }).catch(err => {
      console.log(`Error in fetch: ${err}`);
    });
};

现在findChattersPerRole返回的承诺将在解决findOrCreateViewer返回的所有承诺后解析

答案 1 :(得分:2)

承诺没有魔力。返回一个承诺并不意味着调用该函数将阻止,而是您可以轻松链接回调以对结果执行某些操作。您需要使用

function findChattersPerRole() {
  return fetch('https://tmi.twitch.tv/group/user/instak/chatters')
    .then(parseJSON)
    .then(r => {
      let chatters = r.chatters;
      let chattersPerRole = Object.keys(chatters).map(role => {
        return chatters[role].map(username => {
          console.log('findOrCreateViewer will be executed after this');
          return findOrCreateViewer(username, role).then(() => {
//        ^^^^^^                                   ^^^^^
            return {
              username: username,
              role: role
            };
          });
        });
      });
      return Promise.all(flattenDeep(chattersPerRole));
//                   ^^^ get a promise for an array of results from an array of promises
    }).catch(err => {
      console.log(`Error in fetch: ${err}`);
    });
}