web-dev-qa-db-ja.com

nodejs同期でこの呼び出しをリクエストにするにはどうすればよいですか?

Nodejsアプリケーションにget_source_atという関数があります。引数としてuriを取り、その目的はそのuriからソースコードを返すことです。私の問題は、コールバック関数を与えるのではなく、関数が同期的にリクエストを呼び出す方法を知らないことです。 I want uriのロードにかかる数秒間停止する制御フロー。どうすればこれを達成できますか?

function get_source_at(uri){
    var source;
    request({ uri:uri}, function (error, response, body) {
        console.log(body);
    });
    return source;
}

また、「イベント」とノードの「イベント」についても読みましたが、コードを書く際にはそれを尊重する必要があります。私はそれを喜んで行いますが、アプリケーションの制御フローを続行する前に、uriからのソースコードを持っていることを確認する方法が必要です。 ?

19
Trindaz

同期リクエストは避けてください。同期制御フローのようなものが必要な場合は、 async を使用できます。

async.waterfall([
    function(callback){
        data = get_source_at(uri);
        callback(null, data);
    },
    function(data,callback){
        process(data, callback);
    },
], function (err,result) {
    console.log(result)
});

processは、実行されると約束されていますafterget_source_at 戻り値。

15
Lai Yu-Hsuan

deasync でできます:

function get_source_at(uri){
    var source;
    request({ uri:uri}, function (error, response, body) {
        source = body;
        console.log(body);
    });
    while(source === undefined) {
      require('deasync').runLoopOnce();
    }
    return source;
}
17
abbr

これは、deasyncを使用するより良い方法です。

var request = require("request")
var deasync = require("deasync")

var getHtml = deasync(function (url, cb) {
   var userAgent = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36"}
   request({
      url: url, 
      headers: userAgent
   },
   function (err, resp, body) {
      if (err) { cb(err, null) }
      cb(null, body)
   })
})

var title = /<title>(.*?)<\/title>/

var myTitle = getHtml("http://www.yahoo.com").match(title)[1]
console.log(myTitle)

deasyncのドキュメント を参照してください。使用できることがわかります。
desync(function (n params, cb) {})
function を作成するには、cb(err, data)で返します。したがって、fs.readFile()のような関数は、deasync関数で簡単にラップできます。ただし、cb(err, data)で戻らないrequestなどの関数の場合。上記のコードで行ったように、カスタムcb(err, data)コールバック形式を使用して、独自の関数(名前付きまたは匿名)を作成できます。このように、コールバックcb(err, data)が別のjavascriptレイヤーに戻ってくるのを待つことで、ほぼすべての非同期関数を強制的にsyncのように実行できます(ドキュメントに記載されています)。また、cb(err, data)コールバックを使用してdeasyncでラップしている関数から抜け出す方法をすべて網羅していることを確認してください。そうしないと、プログラムがブロックされます。

願っています。

更新:
この方法で同期リクエストを実行しないでください。 Async/Awaitを使用して、Promisesベースの同期的なコードを作成します。 request-promise-native npmモジュールを使用すると、要求モジュールを自分でプロミスでラップすることを回避できます。

10
Vikas Gautam

シンプルなブロック機能を持つことは、インタラクティブな開発にとって大きな恩恵です! sync関数(以下で定義)は、任意のプロミスを同期でき、APIを使用して学習するために必要な構文の量を劇的に削減できます。たとえば、ヘッドレスChromeの puppeteer ライブラリで使用する方法は次のとおりです。

var browser = sync(puppeteer.connect({ browserWSEndpoint: "ws://some-endpoint"}));
var pages = sync(browser.pages())
pages.length
1
var page = pages[0]
sync(page.goto('https://duckduckgo.com', {waitUntil: 'networkidle2'}))
sync(page.pdf({path: 'webpage.pdf', format: 'A4'}))

最良の部分は、テストするたびに前の行をすべて再実行したり再入力したりすることなく、これらの各行を目的の処理が行われるまで調整できることです。これは、トップレベルからbrowserおよびpages変数に直接アクセスできるためです。

仕組みは次のとおりです。

const deasync = require("deasync");
const sync = deasync((promise, callback) => promise.then(result) => callback(null, result)));

他の回答で言及されている deasync パッケージを使用します。 deasyncは、匿名関数に部分的なアプリケーションを作成し、callbackを最後の引数として追加し、callbackが呼び出されるまでブロックします。 callbackは、最初の引数(ある場合)としてエラー条件を受け取り、2番目の引数(ある場合)として結果を受け取ります。

3
jpaugh

アプリケーションの制御フローを続行する前に、uriからのソースコードがあることを確認する方法が必要です。したがって、関数を同期化しない場合、どのように実行できますか。

アプリケーションへのこのエントリポイントがある場合:

function app(body) {
    // Doing lots of rad stuff
}

ボディを取得することでキックオフします:

request({ uri: uri }, function (error, response, body) {
    if(err) return console.error(err);

    // Start application
    app(body);
}

これは、node.js(および一般的なjavascript)のプログラミング時に慣れなければならないものです。非同期のような制御フローモジュール(私もお勧めします)がありますが、継続渡しスタイルに慣れる必要があります。

まず、そのコードを非同期に保つために、リクエスト関数のコールバック内に関連するコードを配置するだけで、リクエストの終了後に実行されますが、アプリケーションの他のタスクの処理をプロセッサが停止することはありません。複数回必要な場合は、 Node.jsの同期リクエスト をチェックアウトすることをお勧めします。これは、これをより合理化するためのさまざまな方法を概説し、さまざまな制御フローライブラリについて説明しています。

0
David Mulder