【问题标题】:Await skipping and how to fix?等待跳过以及如何解决?
【发布时间】:2019-07-06 15:41:50
【问题描述】:

我正在使用https://github.com/jimmywarting/StreamSaver.js 将一些几何数据流式传输到文件中,但是我无法使用我有限的 Promise 知识使其工作

        const fileStream = streamSaver.createWriteStream('export.obj')
        const writer = fileStream.getWriter()
        const encoder = new TextEncoder

        object.streamExportGeometry(async data => {    //Callback from streamExportGeometry with data to write. Called many times
            console.log("writerQueued");
            await new Promise((resolve, reject) => {
                writer.write(encoder.encode(data)).then(() => { setTimeout(resolve) })
            });
            console.log("writerDone");
        }, onProgress);
        writer.close()

我尝试了许多 await 变体,但它从不等待 writer.write 完成。 控制台输出如下所示

24x writerQueued 24x writerQueued exported finished 24x writerDone 24x writerDone writerDone

这个工具提供了examples,但我不知道如何为我的代码放置承诺

编辑:添加 streamExportGeometry

 streamExportOBJ(writer, onProgressCallback) {
    var i, j, k, l, x, y, z;

    var vertices = this._vertices ? this._vertices.array : null;

    //Buffer object, to optimize amount of lines per write
    var writeBuffer = {
        _outputBuffer: "",
        _currBuffer: 0,
        _bufferLineLimit: 10000,
        _progress: 0,
        _expectedProgress: 1 + (vertices ? vertices.length / 3 : 0) + (uvs ? uvs.length / 2 : 0) + (normals ? normals.length / 3 : 0) + (indices ? indices.length / 3 : vertices.length / 3),
        writeLine: function (data) {
            this._outputBuffer += data;
            this._currBuffer++;
            if (this._currBuffer >= this._bufferLineLimit)
                this.flush();
        },
        flush: function () {
            if (this._outputBuffer) {
                writer(this._outputBuffer);
                this._outputBuffer = "";
                this._progress += this._currBuffer;
                this._currBuffer = 0;
                onProgressCallback(this._progress / this._expectedProgress * 100);
            }
        }
    }

    writeBuffer.writeLine('o export\n');

    //vertices
    if (vertices !== undefined && vertices && vertices.length >= 3) {
        for (i = 0; i < vertices.length; i += 3) {
            x = vertices[i];
            y = vertices[i + 1];
            z = vertices[i + 2];

            writeBuffer.writeLine('v ' + x + ' ' + y + ' ' + z + '\n');
        }
    }

    //Some more data..

   writeBuffer.flush();
 }

【问题讨论】:

  • setTimeout(resolve()) 调用resolve() 并将结果传递给setTimeoutsetTimeout 尝试在下一个事件循环中将该结果作为函数调用。您可能正在寻找 setTimeout(resolve),或者只是 resolve(),因为使用 setTimeout 不太可能为您做很多事情。
  • 我尝试了很多可能的方法,但没有按照你的建议解决,总是一样的 @HereticMonkey 。显然不是重复的
  • 你可能只是想做await writer.write(encoder.encode(data)); 我看不出有任何理由创建一个承诺来包装另一个承诺。
  • 在您编辑代码之前,它显示的症状与建议的副本相同。考虑到您在问题中没有提到您之前尝试过其他方法,“显然”是一个很大的延伸。
  • @HereticMonkey 我最初尝试过,但没有用。认为 writer.write 可能不会像 stackoverflow.com/questions/48617486/… 中所建议的那样返回 Promise 值,所以我将 Promise 包裹起来。还尝试了示例中建议的超时组合。我尝试更改示例,但它没有超时就无法工作,所以这就是我(尝试)使用它的原因。

标签: javascript promise async-await


【解决方案1】:

这是我的建议。您有 streamExportOBJ() 正在尝试同步运行,但它正在调用实际上是异步的编写器方法,因此 streamExportOBJ() 无法真正知道它调用的任何异步内容何时完成。所以,我让你传递给streamExportOBJ()的回调有一个异步接口,然后streamExportOBJ()可以await它。

我不完全确定您想在这里对错误处理做什么。如果writer.write() 中出现任何错误,则整个过程将中止,错误会渗透到您的顶层,catch(e) {} 块将得到它。您可以在那里制定不同的策略。

async streamExportOBJ(writer, onProgressCallback) {
    var i, j, k, l, x, y, z;

    var vertices = this._vertices ? this._vertices.array : null;

    //Buffer object, to optimize amount of lines per write
    var writeBuffer = {
        _outputBuffer: "",
        _currBuffer: 0,
        _bufferLineLimit: 10000,
        _progress: 0,
        _expectedProgress: 1 + (vertices ? vertices.length / 3 : 0) + (uvs ? uvs.length / 2 : 0) + (normals ? normals.length / 3 : 0) + (indices ? indices.length / 3 : vertices.length / 3),

        writeLine: async function (data) {
            this._outputBuffer += data;
            this._currBuffer++;
            if (this._currBuffer >= this._bufferLineLimit)
                return this.flush();
        },

        flush: async function () {
            if (this._outputBuffer) {
                await writer(this._outputBuffer);
                this._outputBuffer = "";
                this._progress += this._currBuffer;
                this._currBuffer = 0;
                onProgressCallback(this._progress / this._expectedProgress * 100);
            }
        }
    }

    await writeBuffer.writeLine('o export\n');

    //vertices
    if (vertices !== undefined && vertices && vertices.length >= 3) {
        for (i = 0; i < vertices.length; i += 3) {
            x = vertices[i];
            y = vertices[i + 1];
            z = vertices[i + 2];

            await writeBuffer.writeLine('v ' + x + ' ' + y + ' ' + z + '\n');
        }
    }

    //Some more data..

   return writeBuffer.flush();
}

async function someFunction() {
    const fileStream = streamSaver.createWriteStream('export.obj');
    const writer = fileStream.getWriter();
    const encoder = new TextEncoder;

    try {
        await object.streamExportGeometry(async data => {
            console.log("writerQueued");
            await writer.write(encoder.encode(data));
            console.log("writerDone");
        }, onProgress);
    } catch(e) {
        // not sure what you want to do here when there 
        // was an error somewhere in object.streamExportGeometry()
    } finally {
        // always close
        writer.close()
    }
}

仅供参考,如果这是我的代码,我会将所有 writeBuffer 功能移到它自己的类中,然后将其从 streamExportObj 中取出。它似乎是通用缓冲功能,可以单独实现/测试,然后streamExportOBJ() 的逻辑将看起来更易于理解和遵循。

【讨论】:

  • 对不起,还是一样。在完成任何写入之前都会调用所有写入。
  • @Jonzi - 那么writer.write(encoder.encode(data)); 可能并没有等待在它真正完成写入之前解决它返回的承诺。我在这里无能为力,因为我没有任何代码可供查看。所有异步操作都必须正确返回一个只有在完成后才能解决的承诺,以便您正确排序。你不能await一个对你说谎的承诺。
  • @Jonzi - 如果这个github.com/jimmywarting/StreamSaver.js/blob/master/….write() 操作的代码,那么它似乎根本没有返回承诺,而你原来的`writer.write(encoder.encode( data)).then(() => { setTimeout(resolve) })` 在尝试使用 .then() 时存在缺陷。为了对事物进行排序,您必须修复 .write() 以返回仅在实际完成写入时才解析的 Promise。
  • @Jonzi - 仅供参考,write() 代码上的 cmets 似乎作为待办事项列出,它不能处理背压(一次写太多),需要添加。
  • 几个小时后,我开始工作了,类似于你的回答。感谢您的努力:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-19
  • 1970-01-01
  • 2022-01-17
  • 2020-10-17
  • 1970-01-01
相关资源
最近更新 更多