简体   繁体   English

承诺完成后导出

[英]exporting after promise finishes

I would like to export a class which initial state depends on a value returned from a Promise in another module i cannot modify.我想导出一个类,该类的初始状态取决于我无法修改的另一个模块中的Promise返回的值。

Here's the code:这是代码:

let e = true;

APromiseFromAnotherModule()
  .then(value => return value;);

export default class E {
  constructor() {
    if (e) {
      //...
    } else {
      //...
    }
  }
}

I also tried with async/await encapsulating the Promise into an async function like this:我还尝试使用async/awaitPromise封装成这样的异步函数:

let e = true;

getInitialValue = async () => {
  return await APromiseFromAnotherModule()
    .then(value => e = value;);
};

e = getInitialValue();

export default class E {
  constructor() {
    if (e) {
      //...
    } else {
      //...
    }
  }
}

But it doesn't make sense because that one is an async function so obviously it doesn't work.但这没有意义,因为那个是async函数,所以显然它不起作用。

What am I missing?我错过了什么?

module exports are done synchronously. 模块导出是同步完成的。 So, they cannot depend upon the results of an asynchronous operation. 因此,它们不能依赖异步操作的结果。

And, await only works inside a function. 并且, await仅在函数内部起作用。 It doesn't actually block the containing function (the containing function returns a promise) so that won't help you make an async operation into a synchronous one either. 它实际上并没有阻塞包含函数(包含函数返回一个Promise),因此也不会帮助您将异步操作转换为同步操作。

The usual ways to deal with a module that uses some async code in its setup is to either export a promise and have the calling code use .then() on the promise or to initialize the module with a constructor function that returns a promise. 处理在其设置中使用一些异步代码的模块的常用方法是导出承诺,并使调用代码对承诺使用.then() ,或者使用返回承诺的构造函数初始化模块。

The code is only pseudo code so it's hard to tell exactly what your real problem is to show you specific code for your situation. 该代码仅是伪代码,因此很难确切说明您的真正问题是向您显示具体情况的代码。

As an example. 举个例子。 If you want to export a class definition, but don't want the class definition used until some async code has completed, you can do something like this: 如果要导出class定义,但不希望在某些异步代码完成之前使用该类定义,则可以执行以下操作:

// do async initialization and keep promise
let e;
const p = APromiseFromAnotherModule().then(val => e = val);

class E {
    constructor() {
        if (e) {
            //...
        } else {
            //...
        }
    }
};

// export constructor function
export default function() {
   return p.then(e => {
       // after async initialization is done, resolve with class E
       return E;
   });
}

The caller could then use it like this: 然后,调用方可以像这样使用它:

import init from 'myModule';
init().then(E => {
   // put code here that uses E
}).catch(err => {
   console.log(err);
   // handle error here
});

This solves several issues: 这解决了几个问题:

  1. Asynchronous initialization is started immediately upon module loading. 加载模块后立即开始异步初始化。
  2. class E is not made available to the caller until the async initialization is done so it can't be used until its ready 在异步初始化完成之前,调用者无法使用E类,因此在其就绪之前不能使用它
  3. The same class E is used for all users of the module 该模块的所有用户都使用相同的class E
  4. The async initialization is cached so it's only done once 异步初始化已被缓存,因此只需完成一次

I understand that @jfriend00's answer works fine, but in my case, there is not just one block of code that depends on the foreign async function's completion.我知道@jfriend00 的答案工作正常,但在我的情况下,不只有一个代码块依赖于外部异步函数的完成。

In my app, configuration loading is asynchronous, so the server must wait for the configs to load before starting.在我的应用程序中,配置加载是异步的,因此服务器在启动之前必须等待配置加载。 Since there are other files (like routes) that compose the server that also need access to the configs, I would have to reluctantly call .then() in each other file.由于构成服务器的其他文件(如路由)需要访问配置,因此我不得不不情愿地在每个其他文件中调用.then()

Here is how I was able to do it with require statements instead of export .这是我如何使用require语句而不是export来做到这一点。

config.js配置文件

Module that can be required by other modules in order to gain access to the global configs.其他模块可能需要的模块,以便访问全局配置。

module.exports.loadAllConfigs = async () => {
  const appConfigs = await AsyncConfigLibrary.load();
  module.exports.CONFIG = appConfigs;
};

server.js服务器.js

Main file for Node application that makes use of other modules that require access to global configs. Node 应用程序的主文件,它使用需要访问全局配置的其他模块。

const { loadAllConfigs } = require('./modules/config');

loadAllConfigs()
  .then(() => {
    const { CONFIG } = require('./modules/config');

    /* import modules */
    const auth = require('./modules/auth');
};

auth.js认证.js

Module used by server.js that requires access to configs. server.js使用的需要访问配置的模块。

const { CONFIG } = require('./config');
const cookieSecret = CONFIG.secretItem;

Therefore, as long as the CONFIG property is set in config.js before any of the other modules attempt to access it, that is, before the modules are require 'd, then the single .then() in server.js is sufficient.因此,只要在config.js任何其他模块尝试访问它之前设置CONFIG属性,即在模块被require 'd 之前,那么server.js的单个.then()就足够了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM