代码之家  ›  专栏  ›  技术社区  ›  dim

javascript promise finally块内的异步操作

  •  2
  • dim  · 技术社区  · 8 年前

    我正在实现一个函数,该函数返回 Promise . 在它的实现中,我调用另一个函数,它本身返回 承诺 ,在此基础上,我需要对结果进行一点转换。

    像这样:

    function myDoStuff(params) {
        return actuallyDoStuff(params).then(
            (result) => { return "myTransformation " + result; }
        );
    }
    

    现在,我还需要调用一些清理代码,不管这是成功还是失败。我可以加一个 finally 子句到返回的promise,但问题是:在finally子句中我需要做的也是异步的(基本上,另一个函数返回 承诺 再次重申),我需要返回的承诺等待最后定稿完成,然后再定稿。

    似乎我不能在 最后 功能(至少在 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally )

    那么,我是否需要从两个方面调用定稿 then catch 或者有什么方法可以使用 最后 构造?

    在这两种情况下调用finalization并保留 actuallyDoStuff 导致代码丑陋:

    function myDoStuff(params) {
        return actuallyDoStuff(params).then((result) => {
            return doFinalization().then(() => {
                return "myTransformation " + result;
            });   
        }, (err) => {
            return doFinalization().then(() => {
                throw err;
            }), () => {
                throw err;
            });
        });
    }
    
    2 回复  |  直到 8 年前
        1
  •  1
  •   T.J. Crowder    8 年前

    finally

    function myDoStuff(params) {
        return actuallyDoStuff(params)
            .then(
                (result) => { return "myTransformation " + result; }
            )
            .finally(cleanup);
    }
    

    function myDoStuff(params) {
        return actuallyDoStuff(params)
            .then(
                (result) => { return "myTransformation " + result; }
            )
            .finally(() => cleanup().catch(() => {}));
    }
    

    // Note this takes only 10ms
    function actuallyDoStuff(valueOrError, fail = false) {
      return new Promise((resolve, reject) => {
        setTimeout(fail ? reject : resolve, 10, valueOrError);
      });
    }
    
    // Note this takes a full second
    function cleanup(fail = false) {
      return new Promise((resolve, reject) => {
        setTimeout(fail ? reject : resolve, 1000, "cleanup done");
      });
    }
    
    function myDoStuff(...params) {
        return actuallyDoStuff(...params)
            .then(
                (result) => { return "myTransformation " + result; }
            )
            .finally(cleanup);
    }
    
    console.log("start with success");
    myDoStuff("success")
      .then(value => console.log("success", value))
      .catch(error => console.log("error", error))
      .finally(() => {
        console.log("Notice how there was a 1,010ms delay, and that the result was from actuallyDoStuff, not cleanup");
        console.log("start with error");
        myDoStuff("error", true)
          .then(value => console.log("success", value))
          .catch(error => console.error("error", error))
          .finally(() => {
            console.log("Notice how there was a 1,010ms delay");
           });
             });

    async await

    async function myDoStuff(params) {
        try {
            const result = await actuallyDoStuff(params);
            return return "myTransformation " + result;
        } finally {
            await cleanup(); // Allows errors from cleanup
        }
    }
    

    async function myDoStuff(params) {
        try {
            const result = await actuallyDoStuff(params);
            return "myTransformation " + result;
        } finally {
            await cleanup().catch(() => {}); // Suppresses errors from cleanup
        }
    }
    

    try catch

    async function myDoStuff(params) {
        try {
            const result = await actuallyDoStuff(params);
            return "myTransformation " + result;
        } finally {
            try {
                await cleanup()
            } catch (e) { // As of ES2019, you could leave the `(e)` off
                          // That's already at Stage 4
            }
        }
    }
    
        2
  •  1
  •   ponury-kostek    8 年前

    如果要返回原始结果 actuallyDoStuff 之后 doFinalization

    function myDoStuff(params) {
    	return actuallyDoStuff(params).then((result) => {
    		return doFinalization().then(() => {
    			return "myTransformation " + result;
    		}).finally(doFinalization);
    	});
    }
    
    function doFinalization(result) {
    	console.log("Finalizing"); // It can be async or not
    	return Promise.resolve("finalized").then(() => {
    		// return original resolution of actuallyDoStuff
    		return result;
    	});
    }
    
    function actuallyDoStuff(params) {
    	console.log("Doing stuff");
    	return params ? Promise.resolve("ok") : Promise.reject("failed");
    }
    
    myDoStuff(true).then(res => console.log("Result", res)).catch(err => console.error("Error", err));
    myDoStuff(false).then(res => console.log("Result", res)).catch(err => console.error("Error", err));