2015-03-25 199 views
2

我在sails.js中的異步事件中遇到了一些問題。在同步內進行異步調用

我從JSONapi獲取一些數據,並試圖將它們寫入到for循環中的數據庫中。一切都需要一個接一個地執行(以正確的順序)。爲了簡化這個例子只是可以說,我試圖做到以下幾點:

//let apiNames be a JSON that contains some names in that order: James, Betty, Jon 
//let Customer be a DB which contains that names and related age 

for(index in apiNames){ 
    console.log("Searching for "+apiNames[index].name+" in the Database...); 
    Customer.find({name:apiNames[index].name}).exec(function(err,customerData){ 
     console.log("Found "+apiNames[index].name+" in the Database!"); 
     console.log(customerData); 
    }); 
} 

的建議日誌應該是這樣的:

Searching for James in the Database.... 
Found James in Database! 
{name:James, age:23} 

Searching for Betty in the Database.... 
Found Betty in Database! 
{name:Betty, age:43} 

Searching for Jon in the Database.... 
Found Jon in Database! 
{name:Jon, age:36} 

由於JavaScript是異步運行,DB調用抽空長,輸出看起來像這樣:

Searching for James in the Database.... 
Searching for Betty in the Database.... 
Searching for Jon in the Database.... 
Found James in Database! 
{name:James, age:23} 
Found Betty in Database! 
{name:Betty, age:43} 
Found Jon in Database! 
{name:Jon, age:36} 

我已經嘗試了幾件事情來強制循環同步工作,但沒有任何工作。 AFAIK如果我在exec內部調用某個東西,它應該同步運行(通過與另一個exec鏈接),但是我的問題是,它在循環中同步工作已經失敗。有沒有人有這個解決方案,可以解釋一下?

編輯:apiNames不是一個數組,它是一個JSON,裏面有一些數據。這裏是apiNames怎麼看起來像一個例子:(由性別有在JSON的一些詳細信息,它不重要的解決方案)

[{ 
    "name": "James", 
    "gender": "male" 
}, 
{ 
    "name": "Betty", 
    "gender": "female" 
}, 
{ 
    "name": "Jon", 
    "gender": "male" 
}] 

+0

是'apiNames'數組 – 2015-03-25 00:40:10

+0

所以'apiNames'是一個字符串? – elclanrs 2015-03-25 00:44:24

+0

你可以分享'apiNames'的樣本,結構...還需要什麼瀏覽器兼容性 – 2015-03-25 00:46:46

回答

3

由於apiNames是一個對象,IE9 +的兼容性,我們可以使用Object.keys()來獲取該對象中的鍵名,並用它來遍歷apiNames

//process all names in the array one by one 
function process(apiNames, keys) { 
    //if there are no items in the array return from the function 
    if (!keys.length) { 
     return; 
    } 
    //get the first name in the array 
    var key = keys.shift(); 
    var name = apiNames[key]; 
    console.log("Searching for " + name + " in the Database..."); 
    Customer.find({ 
     name: name 
    }).exec(function (err, customerData) { 
     console.log("Found " + name + " in the Database!"); 
     console.log(customerData); 
     //once the current item is processed call the next process method so that the second item can be processed 
     process(apiNames, keys); 
    }); 
} 

//call the process method with an array 
var keys = Object.keys(apiNames); 
process(apiNames, keys); 

舊的瀏覽器使用填充工具以增加對Object.keys(支持)之類的one provided by MDN

演示:Fiddle

+0

謝謝你的例子。有沒有辦法讓循環代替它? – Depa 2015-03-25 01:29:16

+0

@Depa由於該方法是異步AFAIK沒有其他方法比使用基於回調的處理 – 2015-03-25 01:47:58

+0

感謝隊友,它似乎適用於這種特定情況! – Depa 2015-04-03 00:20:10

0

您可以使用遞歸來測試布爾值,您可以在準備就緒時進行切換。

var isFinding = false; 
var found = []; 

for (index in apiNames) { 
    checkIndex(index); 
} 

function checkIndex (index) { 
    if (index) { 
    found[index - 1] 
    ? findCustomer(index) 
    : setTimeout(checkIndex, 100, index); 
    } else { 
    findCustomer(index); 
    } 
} 

function findCustomer (index) { 
    if (isFinding) { 
    setTimeout(findCustomer, 100, index) 
    } else { 
    isFinding = true; 
    console.log("Searching for "+apiNames[index]+" in the Database..."); 
    Customer.find({name:apiNames[index]}).exec(function(err,customerData){ 
     console.log("Found "+apiNames[index]+" in the Database!"); 
     console.log(customerData); 
     found[index] = true; 
     isFinding = false; 
    }); 
    } 
} 

console.log("Searching for "+apiNames[index]+" in the Database..."); 

這是未經測試,我半睡半醒的......但我敢肯定這應該工作你想怎麼...或者至少讓你接近:-)

+0

我檢查了這一點,並讓你知道它是否工作。 – Depa 2015-03-25 10:21:14

0

因爲我相信我們談論這裏的NodeJS我會用async.js

和apiNames看起來像數組給我,如果它不是那麼讓它

var async = require('async'); 

var apiNames = JSON.parse('[{"name": "James","gender": "male"},{"name": "Betty","gender": "female"}]'); 

async.eachSeries(apiNames, function(apiName, callback) { 

    console.log("Searching for "+apiName.name+" in the Database...); 

    Customer.find({name:apiName.name}).exec(function(err,customerData){ 
    console.log("Found "+apiName.name+" in the Database!"); 
    console.log(customerData); 
    callback(); 
    }); 

});