Возвращает значение из функции обратного вызова в узле.js [дубликат]
этот вопрос уже есть ответ здесь:
Как вернуть ответ из асинхронного вызова?
33 ответы
я столкнулся с небольшой проблемой при возврате значения из функции обратного вызова в узле.js, я постараюсь объяснить свою ситуацию как можно проще. Рассмотрим, что у меня есть фрагмент, который принимает URL и попадает в этот url и дает вывод:
urllib.request(urlToCall, { wd: 'nodejs' }, function (err, data, response) {
var statusCode = response.statusCode;
finalData = getResponseJson(statusCode, data.toString());
});
Я попытался обернуть его внутри функции и вернуть значение следующим образом:
function doCall(urlToCall) {
urllib.request(urlToCall, { wd: 'nodejs' }, function (err, data, response) {
var statusCode = response.statusCode;
finalData = getResponseJson(statusCode, data.toString());
return finalData;
});
}
потому что в моем узле.JS код, у меня много if-else оператор, где значение urlToCall будет решено, вот так:
if(//somecondition) {
urlToCall = //Url1;
} else if(//someother condition) {
urlToCall = //Url2;
} else {
urlToCall = //Url3;
}
дело во всех утверждениях внутри a urllib.request останется таким же, кроме значения urlToCall. Так что определенно мне нужно поместить этот общий код внутри функции. Я пробовал то же самое, но в doCall всегда верни меня undefined. Я попробовал вот так:
response = doCall(urlToCall);
console.log(response) //Prints undefined
но если я напечатать значение внутри doCall() он отлично печатает, но он всегда будет возвращаться undefined. Согласно моим исследованиям, я узнал, что мы не можем возвращать значения из функций обратного вызова! (это правда)? Если да, может ли кто-нибудь посоветовать мне, как справиться с этой ситуацией, так как я хочу предотвратить дублирование кода в каждом if-else блоки.
4 ответов:
его
undefined, потому чтоconsole.log(response)работает доdoCall(urlToCall);закончена. Вы должны передать в функцию обратного вызова, а также, что работает, когда ваш запрос сделано.во-первых, ваша функция. Передайте ему обратный вызов:
function doCall(urlToCall, callback) { urllib.request(urlToCall, { wd: 'nodejs' }, function (err, data, response) { var statusCode = response.statusCode; finalData = getResponseJson(statusCode, data.toString()); return callback(finalData); }); }теперь:
var urlToCall = "http://myUrlToCall"; doCall(urlToCall, function(response){ // Here you have access to your variable console.log(response); })@Rodrigo, posted a хороший ресурс в комментариях. Читайте о обратные вызовы в узле и как они работают. Помните, что это асинхронный код.
я столкнулся с небольшой проблемой при возврате значения из функции обратного вызова в узле.js
Это не "небольшая проблема", на самом деле невозможно" вернуть " значение в традиционном смысле из асинхронной функции.
поскольку вы не можете "вернуть значение", вы должны вызвать функцию, которая будет нуждаться в значении, как только вы его получите. @display_name уже ответил на ваш вопрос, но я просто хотел отметить, что возврат в doCall не возвращает значение традиционным способом. Вы можете написать doCall следующим образом:
function doCall(urlToCall, callback) { urllib.request(urlToCall, { wd: 'nodejs' }, function (err, data, response) { var statusCode = response.statusCode; finalData = getResponseJson(statusCode, data.toString()); // call the function that needs the value callback(finalData); // we are done return; }); }строка
callback(finalData);это то, что вызывает функцию, которая нуждается в значение, которое вы получили от асинхронной функции. Но имейте в виду, что оператор return используется для указания того, что функция заканчивается здесь, но это не означает, что значение возвращается вызывающему (абонент уже ушел.)
Если вы хотите, чтобы ваш код работал без изменения слишком много. Вы можете попробовать это решение, которое избавляется от обратных вызовов и сохраняет тот же рабочий процесс кода:
учитывая, что вы используете узел.JS, вы можете использовать co и co-request для достижения той же цели без опасения обратного вызова.
в принципе, вы можете сделать что-то вроде этого:
function doCall(urlToCall) { return co(function *(){ var response = yield urllib.request(urlToCall, { wd: 'nodejs' }); // This is co-request. var statusCode = response.statusCode; finalData = getResponseJson(statusCode, data.toString()); return finalData; }); }затем,
var response = yield doCall(urlToCall); // "yield" garuantees the callback finished. console.log(response) // The response will not be undefined anymore.By делая это, мы ждем, пока функция обратного вызова не завершится, а затем получить значение из него. Так или иначе, это решает вашу проблему.
пример кода для узла.js-асинхронная функция для синхронизации функции:
var deasync = require('deasync'); function syncFunc() { var ret = null; asyncFunc(function(err, result){ ret = {err : err, result : result} }); while((ret == null)) { deasync.runLoopOnce(); } return (ret.err || ret.result); }
Comments