2016-10-05 77 views
2

我使用NodeJS爲API構建了一個SDK,可以找到它here。我的問題是,當用戶聲明模塊時,它會提供我需要驗證的用戶名和密碼以及必須用於將來調用的令牌。所以,這個令牌存儲在irecarga.token中,並且對於每個將來的呼叫,我都必須使用它來識別用戶。我的問題是,如果用戶在聲明後直接調用另一個函數,聲明可能無法及時完成(因爲它執行HTTP POST),並且屬性標記將爲空。NodeJS上的阻塞函數

// module declaration which requires a HTTP call and updates irecarga.token 
var irecarga = require('../')({ 
    username: process.env.IRECARGA_USERNAME, 
    password: process.env.IRECARGA_PASSWORD 
}) 

// function called straight after declaration which uses irecarga.token 
irecarga.getServiceProviders(48, function(err, data){ 
    // this code won't even run because the token = null will break the code 
    console.log('err: ', err) 
    console.log('data', data) 
}) 

於是,我看到了很多的解決方案與節點創建阻塞功能,我可以利用回調或將需要發送我想執行的參數等功能功能等模塊。

這些解決方案很可能會工作,但代碼會變得醜陋和混亂。此外,我不認爲我在創新,事實上,這是我看到像微軟和谷歌這樣的大公司宣佈他們的API密鑰的方式。

我在這裏錯過了什麼嗎?有什麼我可以添加驗證功能,使任何方法的iRecarga等待,直到驗證完成?

+0

你爲什麼不使用承諾。 如果你不希望它是異步的,那就使用像wait.for這樣的庫,這會讓你的代碼執行順序。但是我更願意在任何一天使用promise。 – maddygoround

+0

看看這個:http://stackoverflow.com/questions/20315434/node-js-asynchronous-module-loading 答案描述了幾個偉大的模式。最終,你將不得不使用其中的一個,沒有辦法避免回調(或承諾如上述評論建議)。但是,它並不一定要讓你的代碼混亂,我不認爲。 –

+0

爲什麼您需要在設置變量時發出發佈請求? – Orlando

回答

0

使用await你可以一個班輪添加到您的每一個API方法,將等待initializatoin(認證)完成等待承諾解決。這是你可以做到的一種方法。我使用babel的最新語法。

// myapi.js 

import login from './auth'; 
import {query, insert} from './db'; 

let authenticated = null, user = null; 

async function getProviders({regionId}) { 
    await authenticated; 
    return await query({region:regionId}); 
} 

async function order({provider, service}) { 
    await authenticated; 
    return await insert({entity:'orders'}, {service, user}); 
} 

export default function ({username, password}) { 
    authenticated = new Promise(async (resolve, reject) => { 
    const valid = await login({username, password}); 
    if (valid) { 
     user = username; 
     resolve(); 
    } else { 
     reject(); 
    } 
    }); 
    return {getProviders, order}; 
} 

// test/myapi.js 

import myapi from '../myapi'; 

async function test() { 
    let api = myapi({username:'tom', password:'1234'}); 
    let providers = await api.getProviders({regionId:48}); 
    console.log(providers); 
    let providers2 = await api.getProviders({regionId:5}); 
    console.log(providers2); 
} 

test().catch(console.error); 
+0

答案總是更好,如果他們也包括一些關於OP的問題的解釋,而不僅僅是代碼。 – jfriend00

+0

我選擇這個作爲正確的答案,因爲await似乎是我的問題的最佳解決方案,所以唯一的要求是用戶使用等待功能。但是,我必須注意,我沒有在SDK上這樣做,我決定每個函數都會在運行之前檢查令牌,如果它爲空,驗證過程將在運行該函數之前被調用。 – Ernanirst

+0

@ErnanideSãoThiago對於使用SDK來說這是一個非常糟糕的要求。除非你打算在你擁有的環境中使用它,否則我認爲這不是一個好主意(例如,你將無法在普通的JavaScript環境中使用它)。 'async/await'是一個ES2016 API,不支持沒有babel或其他轉換器。 你最好延遲驗證用戶名/密碼,直到第一個請求,或者只是使用Promises – Orlando

1

在node.js中,您不會使異步事物阻塞事物。相反,您將它們用作異步並在它們之上創建一個異步界面。

所以,你需要爲你的初始化提供一個異步接口,以便調用者知道初始化完成的時間以及何時調用其他方法是安全的或可能的。有很多不同的方法來做到這一點:

  1. 返回從require()()承諾與解析值是你的模塊對象。然後,調用者執行.then(),並且在該回調中可以使用您正確初始化的模塊。

  2. 將一個回調傳遞給模塊初始化,並要求所有使用該模塊的回調(與上面的承諾相同,只是使用常規回調)。

  3. 不要將憑據傳遞給構造函數。相反,請創建一個異步.login()方法,該方法返回一個承諾,並指示調用方不要在解析的登錄承諾內使用該接口。

例如,它可能看起來像這樣:

require('../')({ 
    username: process.env.IRECARGA_USERNAME, 
    password: process.env.IRECARGA_PASSWORD 
}).then(function(irecarga) { 
    // function called straight after declaration which uses irecarga.token 
    // this method should probably be changed to use promises 
    irecarga.getServiceProviders(48, function(err, data){ 
     console.log('err: ', err) 
     console.log('data', data) 
    }); 
}).catch(function(err) { 
    // handle intiialization error here 
}); 
+0

爲什麼downvote?在沒有提供理由的情況下下決心不會幫助人們做出更好的答案。 – jfriend00