【问题标题】:JS: Call async function before exporting somethingJS:在导出某些东西之前调用异步函数
【发布时间】:2017-06-15 11:35:33
【问题描述】:

我需要调用异步函数来获取我的身份验证令牌。在导出中,我想包含此 fn 的返回值。

我的第一次尝试:

const token = await sessionHandler.getToken();

export const httpService = axios.create({
    ...
    headers: {
        "auth-token": token
        ...
    }
});

当然这不起作用,因为await 不在异步函数中。 所以我可以把它包装在一个异步函数中,对吧?不,因为我必须使用回调。再说一次,我不会在顶层进行导出,这也不起作用。

解决这个问题的最佳方法是什么?

【问题讨论】:

  • 为什么要求不使用回调?这是您自己设定的要求,还是因为您不知道如何通过回调解决它?
  • @t.niese 出口必须是顶级的
  • 似乎您正试图将异步转换为同步 - 这就是您要问的吗?
  • 我还是不明白。使用身份验证令牌的 http 请求,ist async,那么为什么不能在第一次需要时请求身份验证令牌?
  • 在axios实例中每次调用都会用到token,所以我想先拿到token再导出服务

标签: javascript asynchronous async-await es6-modules ecmascript-next


【解决方案1】:

这是不可能的。 导出必须以同步方式定义,并且在导出之前您不能等待。

我建议你导出一个异步函数。如果您不希望每次都请求令牌,您可以考虑保存它:

let token;

export const createHttpService = async () => {
  token = token == null ? await sessionHandler.getToken() : token;
  return axios.create({
    /* ... */
    headers: {
        "auth-token": token
        /* ... */
    }
  });
};

但是,如果这对您来说可以接受,我想我更愿意分离此令牌的请求,并让模块的使用者将其传递回 createHttpService(并因此负责保存它)。

export const getToken = () => sessionHandler.getToken();

export const createHttpService = (token) => {
  return axios.create({
    /* ... */
    headers: {
        "auth-token": token
        /* ... */
    }
  });
};

如果你真的想在模块加载时需要令牌,你也可以直接导出承诺。但是,我建议在加载模块时要注意副作用。

【讨论】:

  • 有意思,以后怎么称呼?
  • 我不希望它获得任何请求的新令牌?!
  • 我知道,在这种情况下,您可能想要保存该令牌。
  • 好的,我会试试的。消费者将是createHttpService().get(...)?
  • 不,createHttpService(第一个版本)将返回 Promise(与任何异步函数一样)。 Here is a nice article about promises.
【解决方案2】:

如果httpService 不能是异步的,那么我会使用interceptors 来满足这种要求,如果令牌在第一次请求时还没有准备好,那么拦截器将等待直到承诺完成。令牌只会被请求一次。

const axios = require('axios')
const token = sessionHandler.getToken();

export const httpService = axios.create({
  ...
  headers: {
    ...
  }
});

httpService.interceptors.request.use(function(config) {
  return token.then(token => {
    config.headers['auth-token'] = token;
    return config;
  })
}, function(error) {
  console.dir(error)
  // Do something with request error
  return Promise.reject(error);
});

编辑我个人更喜欢仅按需请求数据而不是包含数据,因此我会使用稍微不同的版本:

const axios = require('axios')
let token;

export const httpService = axios.create({
  ...
  headers: {
    ...
  }
});

httpService.interceptors.request.use(function(config) {
  token = token || sessionHandler.getToken(); //request it only if not already requested.

  return token.then(token => {
    config.headers['auth-token'] = token;
    return config;
  })
}, function(error) {
  console.dir(error)
  // Do something with request error
  return Promise.reject(error);
});

【讨论】:

  • @Sandrooco 为什么你认为它每次都请求令牌?
  • 因为拦截器拦截了所有请求,而不仅仅是一个?!
  • @Sandrooco 是的,但是令牌的请求只做一次,第一次执行文件。 顶级 token 变量存储 Promise。您可以根据需要随时在 Promise 上调用 .then,这不会启动新请求,它只会等到 Promise 解决。 getToken 执行请求并返回一个 Promise。 Promise 只存储一个状态(等待、已完成的值或拒绝错误)
  • 对不起 - 我没有想到这一点。完美运行!
  • @Sandrooco 没问题。你越用 Promises 越习惯它
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-13
  • 2020-12-02
相关资源
最近更新 更多