2017-01-07 4 views
0

Я использую библиотеку TWIT для nodejs, которые имеют асинхронные вызовы, и я сделал такие функции, как это:Лучшего способ возврата значений из функций в асинхронных JavaScript

function getUserFromSearch(phrase) { 
    T.get('search/tweets', { q: phrase+' lang:pt', count: 1 }, function(err, data, response) { 
    data['statuses'].forEach(function(element) { 
     var result = "maybe"; 
     say('getting user profile from search for '+phrase, result); 
     console.log(element); 
     return element['user']['screen_name']; 
    }, this); 
    }) 
} 

С T.get() выполняется asynchonously всякий раз, когда я

var username = getUserFromSearch('banana'); 

я получаю username=undefined, потому что это занимает много времени, чтобы вернуть вещи. Очевидным решением было бы реализовать функцию обратного вызова, как это:

function getUserFromSearch(phrase, callback) { 
    T.get('search/tweets', { q: phrase+' lang:pt', count: 1 }, function(err, data, response) { 
    data['statuses'].forEach(function(element) { 
     var result = "maybe"; 
     say('getting user profile from search for '+phrase, result); 
     console.log(element); 
     callback(element['user']['screen_name']); 
    }, this); 
    }) 
} 

Но я не думаю, что это лучшее решение, потому что мне нужно создать функцию обратного вызова только для этого. Не существует способа передать имя пользователя «pointer» следующим образом: getUserFromSearch('banana', username); таким образом, что функция изменяет значение имени пользователя? Есть ли еще лучший способ?

ответ

1

не Есть ли способ, чтобы передать имя пользователя «указатель»

Нет, нет. JavaScript не имеет ссылок на переменные.

Вы могли бы передать в объекте с usernameсобственности и он установить это свойство, но плотно пару getUserFromSearch к конкретному объекту и не компонуемо.

Обещания - отличный способ справиться с этой ситуацией. Они компонуемы и предлагают четкую семантику вокруг успеха и неудач:

function getUserFromSearch(phrase) { 
    return new Promise(function(resolve, reject) { 
     T.get('search/tweets', { q: phrase + ' lang:pt', count: 1 }, function(err, data, response) { 
      if (err) { 
       reject(err); 
      } else { 
       data['statuses'].forEach(function(element) { 
        var result = "maybe"; 
        say('getting user profile from search for ' + phrase, result); 
        resolve(element['user']['screen_name']); 
       }, this); 
      } 
     }) 
    }); 
} 

Usage:

getUserFromSearch(phrase).then(function(result) { 
    username = result; 
}); 

Да, есть еще обратный вызов, но это обратный вызов, который легко состоит с другими.


С ES2015 синтаксисом:

function getUserFromSearch(phrase) { 
    return new Promise((resolve, reject) => { 
     T.get('search/tweets', { q: phrase + ' lang:pt', count: 1 }, function(err, data, response) { 
      if (err) { 
       reject(err); 
      } else { 
       data['statuses'].forEach(element => { 
        const result = "maybe"; 
        say('getting user profile from search for ' + phrase, result); 
        resolve(element['user']['screen_name']); 
       }); 
      } 
     }) 
    }); 
} 

Использование:

getUserFromSearch(phrase).then(result => { 
    username = result; 
}); 
+0

Могу ли я использовать синтаксис ES2015 в nodejs? – Gatonito

+0

@ Гатонито: Да. Узел v6.x имеет полную поддержку, отличную от модулей (и оптимизацию хвостового вызова, если вы не используете флаг). v5.x и v4.x имели частичную поддержку. –

+1

Затем вы можете использовать его следующим образом: 'var username = await getUserFromSearch (фраза);' однажды узел поддерживает ['async' /' await'] (https://developers.google.com/web/fundamentals/getting-started/праймеры/асинхронное-функция). – jib

0

Это способ работы javascript.
Поскольку это асинхронная функция, вам нужно сделать это, как вы сказали.

getUserFromSearch('banana', function(username){ 
    //do something with username here 
}); 

Что вы можете сделать, это использовать что-то вроде async.js уменьшить вложенную обратный вызов ад ...

+0

Что вы думаете об этой идее: HTTP: // StackOverflow.com/questions/5292159/is-it-possible-to-change-the-value-of-the-function-parameter – Gatonito

+0

Вместо передачи обратного вызова я мог передать объект, который содержит свойство «имя пользователя», и изменить функцию Это. – Gatonito

+0

понравилось бы, если бы люди прокомментировали, а не просто fly-by downvoted – Alex

1

Поскольку JavaScript не имеет понятия указателей, вы можете создать объект перед вызовом функции и передать объект как второй параметр функции. Назначьте результат функции объекту.

Ваш код будет выглядеть следующим образом:

function getUserFromSearch(phrase,obj) { 
T.get('search/tweets', { q: phrase+' lang:pt', count: 1 }, function(err, data, response) { 
data['statuses'].forEach(function(element) { 
    var result = "maybe"; 
    say('getting user profile from search for '+phrase, result); 
    console.log(element); 
    obj.username = element['user']['screen_name']; 
}, this); 
}) 
} 

var obj = {username:null} 
getUserFromSearch('banana',obj);