Javascript自动释放资源(如RAII)

时间:2012-07-27 18:52:00

标签: javascript raii

我的一般问题是我可以使用哪些技术来确保在Javascript中清理/发布资源?目前,我正在采用C(不使用goto)方法来查找函数中返回或异常的每个执行路径,并确保清理。

我的具体示例如下:在Node.js中我在对象成员函数中使用互斥(通过文件锁)(我需要互斥,因为我运行Node.js应用程序的多个实例并且在不同时具有竞争条件实例与文件系统交互。)

例如,在C ++中我会做类似以下的事情:

void MyClass::dangerous(void) {
     MyLock lock(&this->mutex);
     ...
     // at the end of this function, lock will be destructed and release this->mutex.
}

据我所知,JavaScript不提供任何RAII功能。在C中,我会使用goto来解除发生错误时的资源分配,这样我只有一个函数的返回路径。

在Javascript中实现类似效果的一些技巧是什么?

4 个答案:

答案 0 :(得分:3)

正如其他人可能已经指出的那样,您将需要使用try / finally。创建包装函数来模拟生存期范围可能会更舒适(来自c ++)。尝试在javascript控制台中运行以下代码以获取其用法示例:

class MockFileIO {
    constructor(path) {
        console.log("Opening file stream to path", path);
        this.path = path;
    }
    destructor() {
        console.log("Closing file stream to path", this.path);
    }
    write(str) {
        console.log("Writing to file: ", str);
    }
}

async function run_with(resource, func) {
    try {
        func(resource);
    } catch(e) {
        throw e;
    } finally {
        resource.destructor();
    }
}

async function main() {
    console.log("Starting program");
    const fpath = "somewhere.txt";
    await run_with(new MockFileIO(fpath), (f) => {
        f.write("hello");
        f.write("world");
    });
    console.log("returning from main");
}

main();

答案 1 :(得分:1)

使用在范围结束时调用的回调列表。在需要时打电话给他们。

使用此方法,例如,取消初始化附加到浏览器窗口的附加处理程序。包含去初始化代码的回调存储在一个列表中,该列表在窗口的卸载事件中处理。

不幸的是,由于异常安全要求,这种方法大多不适合范围管理。

答案 2 :(得分:0)

您可以使用闭包和try ... finally块来近似RAII,如下所述:http://jeanlauliac.com/raii-in-javascript/

例如,

function using(start, close, execute) {
    try {
        start.call(this);
        return execute.call(this);
    } finally {
        close.call(this);
    }
}

// specialize to some resource (inside a Context2D wrapper)
    usingScaledLineWidth(execute) {
        const tmp = this.context.lineWidth;
        const start = () => {
            this.context.lineWidth *= Math.abs(this.cf().a);
        };
        const close = () => {
            this.context.lineWidth = tmp;
        };
        return using.call(this, start, close, execute);
    }


// later RAII based usage
    stroke() {
        // have to manually do this because we're not scaling context
        if (this.context.strokeStyle !== "rgba(0, 0, 0, 0)") {
            this.usingScaledLineWidth(()=>{
                this.context.stroke();
            });
        }
    }

答案 3 :(得分:0)

不幸的是,没有语言说明(例如析构函数和确定性破坏)。您必须使用-D语句。

如果您想知道如何以类似于C ++的方式完成此操作,请尝试使用{ii} https://github.com/cardinalby/ts-raii-scope来使用raii容器和TypeScript装饰器。但是我不确定这是否适合生产代码,因为这种方法会使其他开发人员感到困惑。

如果我们在谈论TypeScript,我也认为它可以由TypeScript transforms

实现