2012-03-27 97 views
17

我在我的nodejs應用程序中有一個名爲get_source_at的函數。它以uri作爲參數,其目的是從該uri返回源代碼。我的問題是,我不知道如何使該功能同步調用請求,而不是給它那個回調函數。我想要控制流程停止加載uri所需的幾秒鐘。我怎樣才能做到這一點?如何使這個調用請求在nodejs同步?

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

另外,我已經閱讀了關於「事件」以及節點是如何「放棄」的,我應該在編寫我的代碼時尊重它。我很樂意這樣做,但是我必須有一種方法來確保我有一個來自uri的源代碼,然後才能繼續控制應用程序的流程 - 所以如果這不是通過使該功能同步,那該如何做?

+0

雖然賴的答案在技術上是正確的(所以我將其標記爲答案),但我最終的解決方案需要更多的工作。如果您有不確定數量的呼叫請求,則可以使用https://gist.github.com/2234466 – Trindaz 2012-03-29 08:53:01

回答

16

您應該避免同步請求。如果你想要類似於同步控制流程的東西,你可以使用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是答應後get_source_at返回運行

+16

中找到的示例代碼中的模式「您應該避免同步請求」不是準確的總括聲明。您應該避免在應用程序的主線程上執行同步請求,否則會導致您的UI被阻塞。但在說的情況下,一個無頭Web服務,其唯一目的是委託給其他Web服務並報告結果?有一個同步請求是非常好的,事實上,對於異步請求來說,它更好/更清晰。瞭解您的使用情況並選擇最適合的解決方案非常重要。這不是一個永遠只有一個,永遠不會是另一個的情況。 – aroth 2017-04-20 05:49:25

+1

同意@aroth - 我使用nodejs腳本進行自定義複雜部署任務,我需要按嚴格順序執行每個命令。我可以使用承諾,但是如果你有超過10個任務按照嚴格的順序運行,那麼即使'then()'鏈接也會變得有些難看。 – JustAMartin 2017-11-17 16:42:59

+0

這不是這個問題的答案。 – 2017-12-03 20:11:50

0

好吧,首先,保持代碼異步,你可以簡單地請求函數這意味着它將運行請求結束後的回調中的相關代碼,但不能從您的應用程序處理其他任務停止處理器。如果您多次需要它,我會建議您查看Synchronous request in Node.js,其中概述了各種方法,以便更加簡化並討論各種控制流程庫。

1

我必須有一種方法來確保我有一個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)。有喜歡異步控制流模塊(我也一樣,建議),但你必須要習慣延續傳遞風格,因爲它被稱爲。

14

您可以用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; 
} 
8

這是使用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) 

請參考documentation of deasync,你會發現,你可以使用
desync(function (n params, cb) {})
使功能其中cb應該回來與(err, data)。所以fs.readFile()類似的功能可以很容易地用deasync函數包裝。但是,對於像request功能不回來與cb(err, data)。您可以使用自定義的cb(err, data)回調格式爲您創建自己的函數(有名或無名),就像我在上面的代碼中所做的一樣。通過這種方式,您可以通過等待回調cb(err, data)回到不同的JavaScript層(如文檔所述)來強制幾乎任何異步函數執行同步。還要確保你已經覆蓋了所有的方法從你正在用cb(err, data)回調進行deasync包裝的功能中脫身,否則你的程序將被阻止。

希望,它可以幫助那裏的人!

更新:
不要使用這種做同步請求的方式。使用Async/Await寫入基於同步代碼的promise。您可以使用request-promise-native npm模塊來避免自己承諾包裝請求模塊。

+1

請讓我們開啓您隱藏的知識。在評論中表達你對downvote的理由。謝謝! – 2016-11-20 21:58:53

+1

這是很好的解決方案。 deasync是更好,更優雅的同步呼叫方式。 – Shad 2016-12-10 07:57:00

1

擁有一個簡單的阻塞函數對交互式開發來說是一個很大的福音! sync功能(定義如下)可以同步任何承諾,大幅減少API所需的語法數量並學習它。例如,下面是如何與puppeteer庫無頭Chrome中使用它:

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'})) 

最好的部分是,這些線的每一個都可以進行調整,直到你想要做什麼,而不必重新運行或每次你想測試它時,重新輸入所有以前的行。這是有效的,因爲您可以直接訪問頂層的browserpages變量。

下面是它如何工作的:

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

它使用在其他的答案中提到的deasync包。 deasync爲匿名函數創建了一個部分應用程序,它將callback作爲最後一個參數,並且直到callback被調用。 callback接收錯誤條件作爲其第一個參數(如果有),並將結果作爲第二個參數(如果有的話)。

+0

這對於不支持異步/等待的較早節點版本有幫助。 – 2018-01-26 02:18:52