2016-10-05 64 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