如何将我的javascript回调流程转换为Promise?

时间:2017-03-22 21:58:03

标签: javascript asynchronous promise

function getMentionedUsers(str, next){
    var array = getUsernamesFromString(str); //['john','alex','jess'];
    if(array.length > 0){
        var users = [];
        var pending = array.length;
        array.forEach(function(username){
            getUserByUsername(username).then(function(model){
                users.push(model.key);
                --pending || next(users); //this is a callback model
            }); 
        });
    }
};

function getUserByUsername(username){
    return admin.database().ref('/users').orderByChild('username').equalTo(username).once('value').then(function(snapshot) {
        return snapshot.val(); //this is the firebase example of a promise
    });
};

现在,我正在这样做:

    getMentionedUsers(model.body, function(users){
        console.log("Mentions", users);
    });

但是,我想将getMentionedUsers变为承诺。我怎样才能做到这一点?我是Promises的新手

4 个答案:

答案 0 :(得分:5)

您可以使用Promise.allArray#map

function getMentionedUsers(str) {
  return Promise.all(getUsernamesFromString(str).map((username) => {
    return getUserByUsername(username).then((model) => model.key);
  }));
}

更易阅读的版本分为两个功能:

function getUserKeyByUsername(username) {
  return getUserByUsername(username).then((user) => user.key);
}

function getMentionedUsers(str) {
  const promises = getUsernamesFromString(str).map(getUserKeyByUsername);
  return Promise.all(promises);
}

答案 1 :(得分:1)

使用Promise.all

const getMentionedUsers = str =>
        Promise.all(
            getUsernamesFromString(str).map(
                username => getUserByUsername(username)
                    .then(model => model.key)
            )
        );

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

答案 2 :(得分:0)

你可以充分利用两者。如果您传递next函数,则会调用结果。如果没有,您的方法将返回一个承诺。

function getMentionedUsers(str, next){
    var array = getUsernamesFromString(str); //['john','alex','jess'];
    var promise = Promise.resolve([]); // default 
    var hasNext = typeof next === 'function';
    if(array.length > 0){
        promise = Promise.all(array.map(function(username){
            return getUserByUsername(username); 
        }));
    }
    promise = promise.then(models => {
        var users = models.map(model => model.key);
        if (hasNext) next(null, users);
        return users;
    });
    if (hasNext) promise.catch(next);
    else return promise;
};

更新:虽然不是原始问题的一部分,但这仍然是一个好点,值得指出。您现有的代码使用的是非标准回调技术。标准回调技术需要将错误作为第一个参数,并将结果作为第二个参数:

next(new Error(...)); //-> when something fails
next(null, results); //-> when something succeeds

因此,我更新了我的代码以显示与标准一起的“标准”回调行为。使用上面的混合方法允许现有代码保持原位,同时允许新代码使用新的Promise技术。这将被视为“不间断的变化”。

答案 3 :(得分:-1)

使用本机ES6承诺,以功能样式编写:

// Returns array of usernames
function getUsernamesFromString(str = '') {
  return str.split(',').map(s => s.trim())
}

// returns promise of user
function getUserByUserName(username) {
  // Lets say this is a slow async function and returns a promise
  return Promise.resolve({
    id: (Math.random() * 10 ** 10).toFixed(0),
    username
  });
}

function getMentionedUsers(str) {
  return Promise.all(
    getUsernamesFromString(str).map(getUserByUserName)
  );
}

getMentionedUsers('kai, ava, mia, nova').then(console.log.bind(console))

但是,还有像bluebird这样的库,只要遵循(err, result)的NODE约定作为回调参数,就可以自动地对象和函数进行委托。

您也可以返回new Promise((resolve, reject) => { /* all your code */ }),如果成功就调用resolve(dataToResolveWith),如果失败则调用reject(new Error()),但您很少这样做,事实上,它是反...图案。