NodeJS 上的阻塞函数

Blocking Function on NodeJS

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

// 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 创建阻塞函数的解决方案,我可以使用回调或其他需要将我想要执行的函数作为参数发送给其他函数的模块。

这些解决方案很可能会奏效,但代码会很丑陋和混乱。此外,我不认为我在创新,实际上这是我看到像 Microsoft 和 Google 这样的大公司声明他们的 API 密钥的方式。

我是不是漏掉了什么?有什么我可以在验证函数中添加的东西,可以让 iRecarga 的任何方法等待验证完成吗?

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

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

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

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

  3. 不要将凭据传递给构造函数。相反,创建一个 returns 承诺的异步 .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
});

使用 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);