阻塞NodeJS上的函数

时间:2016-10-05 01:16:11

标签: node.js function blocking

我正在使用NodeJS为API构建SDK,可以找到here。我的问题是,当用户声明模块时,它会提供我需要验证的用户名和密码,以及必须用于将来调用的令牌。因此,此令牌存储在irecarga.token中,并且对于将来的每次调用,我都必须使用它来识别用户。我的问题是,如果用户在声明后直接调用另一个函数,声明可能无法及时完成(因为它执行HTTP POST),属性标记将为null。

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

所以,我看到了很多用Node创建阻塞函数的解决方案,我可以使用回调或其他模块来发送我想要执行的函数作为其他函数的参数。

这些解决方案最有可能奏效,但代码将变得丑陋和混乱。此外,我不认为我在创新,实际上这就是我看到微软和谷歌这样的大公司宣布他们的API密钥的方式。

我在这里遗漏了什么吗?我可以在验证函数中添加任何可以使iRecarga的任何方法等到验证完成之后的任何内容吗?

2 个答案:

答案 0 :(得分:1)

在node.js中,你不能将异步事物变成阻塞事物。相反,您将它们用作异步并在它们之上创建一个异步接口。

因此,您需要为初始化提供异步接口,以便调用者知道何时完成初始化以及何时安全或可以调用其他方法。有很多不同的方法可以做到这一点:

  1. require()()返回一个承诺,其中已解析的值是您的模块对象。然后,调用者执行.then(),并且在该回调中可以使用正确初始化的模块。

  2. 将回调传递给模块初始化,并要求所有模块都使用该回调(与上面的承诺相同,只使用常规回调)。

  3. 不要将凭据传递给构造函数。相反,创建一个异步.login()方法,该方法返回一个promise并指示调用者不要使用该接口,除非在已解析的登录promise中。

  4. 例如,它可能如下所示:

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

答案 1 :(得分:0)

使用await,您可以为每个API方法添加一行代码,等待初始化(身份验证)完成,等待承诺解析。这是你可以做到的一种方式。我使用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);