Async .mjs 在直接调用时有效,在从另一个 .mjs 调用时失败

Async .mjs works when calling directly, fails when called from another .mjs

我目前正在使用 Ring-Client-API,并且 运行 在我开发的最后遇到了一个小问题。我成功地创建、测试并 运行 我的 RingListener 作为一个单独的文件,即通过执行 RingListener.mjs。我的目标是现在从另一个文件位置启动侦听器,我 运行 遇到了一些尝试这样做的问题。我对 CommonJS 更熟悉,所以请随时为我指出我缺少的 ES6 东西的正确方向。我是运行节点14.15.4

代码RingListener.mjs:

import {RingApi} from 'ring-client-api'
import * as dotenv from "dotenv";
dotenv.config({path: '../.env'});
import {readFile, writeFile} from 'fs'
import {promisify} from 'util'
import App from "../objects/GoogleHomeNotification.js";

export async function start() {
    const {env} = process;
    console.log("Test 1")
    const ringApi = new RingApi({my credentials});
    console.log("Test 2")
    const allCameras = await ringApi.getCameras();
    console.log("Test 3")
    console.log("Found " + allCameras.length + " camera(s)")
    ringApi.onRefreshTokenUpdated.subscribe(
        async ({newRefreshToken, oldRefreshToken}) => {
            console.log('Refresh Token Updated: ', newRefreshToken)
        }
    )
    if (allCameras.length) {
        console.log('Listening for motion and doorbell presses on your cameras.')
    }
}
start();

RingListener.mjs

的输出
Test 1
Test 2
Test 3
Found 1 camera(s).
Refresh Token Updated: {my token}
Now writing it to proper .env file
Listening for motion and doorbell presses on your cameras.

当我尝试从我的其他文件启动它时,我只到达测试 2。 Start.mjs

import {start} from './objects/RingListener.mjs'

start();
//await start(); //Returns the same results as just start()

Start.mjs

的输出
Test 1
Test 2

当从另一个位置 运行 它似乎卡在第一个 await 语句时,我不确定为什么。任何帮助将不胜感激。我很困惑,因为我能够实际执行该函数并获得控制台日志语句,但由于某种原因,当通过另一个文件执行时,它总是在与 await 调用完全相同的位置失败。从另一个文件调用异步函数时是否遗漏了什么?

谢谢!

编辑:感谢@JoshA 为我指明了 dotenv 文件路径的正确方向。

当我尝试导入另一个 js 模块时,以下代码现在挂在“测试 1 测试 2”上。

import {start} from './objects/RingListener.mjs'
import {default as Webserver} from './app.js' 

await start();

输出

Test 1 
Test 2

但是当我删除对另一个 class 的导入时,它运行完美,IE“测试 1、2、3 等”。

 import {start} from './objects/RingListener.mjs'
//import {default as Webserver} from './app.js'

await start();

输出

Test 1 
Test 2
Test 3
Found 1 camera(s).
Refresh Token Updated:  
Now writing it to proper .env file
Listening for motion and doorbell presses on your cameras.

我什至还没有使用它,它仍然导致它挂起。最终我将使用 Webserver.listen();但是 ./app.js 只是导出 express 应用程序。

编辑:app.js 包含一堆变量初始化和快速应用程序配置。映射到服务器上的不同路由。目标是删除 app.js 中的 app.listen() 并将其移动到 Start.mjs 并通过 Webserver.listen() 从导入中调用它。

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var logger = require('morgan');
require('dotenv').config()

/* Variable def here */

var app = express();
// app config here

/*  Exports  */
module.exports = app;

app.listen(1337, () => {
    console.log("Starting server on 1337");
})

我假设您正在使用 dotenv.env 文件加载您的凭据,然后将其传递给 new RingApi({my credentials}) 构造函数。

如果是这样,它失败的最可能原因是 dotenv 使用 fs.readFileSync 读取 .env 文件,该文件查找与节点 js 所在路径相关的文件执行而不是相对于模块的路径。这就是为什么如果您从位于不同路径的 Start.mjs 执行应用程序,它会停止工作。

如果你真的想在你的 RingListener.mjs 文件中保留 dotenv 配置调用,你可以将它重写为这样的东西,它解析 .env 文件的绝对路径。

import { resolve } from 'path';
dotenv.config({path: resolve(__dirname, '../.env')});

如果出现错误 __dirname is not defined 这是因为它在 ECMAScript 模块中不可用 here

作为解决方法,您可以执行类似的操作。

import { fileURLToPath } from 'url';
import { dirname, resolve } from 'path';

// Initialize __dirname
const __dirname = dirname(fileURLToPath(import.meta.url));

// Then use it to resolve path for .env
dotenv.config({path: resolve(__dirname, '../.env')});