ES6 await强制停止的方法
发布于 2 个月前 作者 pzzcn 1275 次浏览 来自 分享

ES6提供了async/await的语法,但是我实际工作过程中遇到了一些问题,await无法强制关闭,我无法写一个线程(setTimeout)来监视await的运行状况。如果在规定时间内没有操作完成,则强制关闭await。PS:思路是通过网上的例子改进而来。

核心代码:

    const makeCancelable =(promise) => {
        let hasCanceled_ = false;
        let a={},b={};
        const wrappedPromise = new Promise((resolve, reject) => {
            promise.then((val) =>
                //如果Promise执行完成,判断状态是否正常返回
                hasCanceled_ ? null : resolve(val)
            );
            promise.catch((error) =>
                hasCanceled_ ? null : reject(error)
            );
            a=resolve;//将完成函数赋值给a
            b=reject;
        });
        return {
            promise: wrappedPromise,
            cancel() {
                a({isCanceled: true});
                hasCanceled_ = true;
            },
            async start(timeout){
                if(typeof timeout=="number" && timeout>0){
                    let host=this;
                    setTimeout(function(){
                        host.cancel();
                    },timeout)
                }
                return await wrappedPromise;
            }
        };
    };

使用完整示例

function timeout(delay) {
    console.log("延时:"+delay+"ms");
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            try {
                resolve(1)
            } catch (e) {
                reject(0)
            }
        }, delay)
    })
}

const makeCancelable =(promise) => {
    let hasCanceled_ = false;
    let a={},b={};
    const wrappedPromise = new Promise((resolve, reject) => {
        promise.then((val) =>
            //如果Promise执行完成,判断状态是否正常返回
            hasCanceled_ ? null : resolve(val)
        );
        promise.catch((error) =>
            hasCanceled_ ? null : reject(error)
        );
        a=resolve;//将完成函数赋值给a
        b=reject;
    });
    return {
        promise: wrappedPromise,
        cancel() {
            a({isCanceled: true});
            hasCanceled_ = true;
        },
        async start(timeout){
            if(typeof timeout=="number" && timeout>0){
                let host=this;
                setTimeout(function(){
                    host.cancel();
                },timeout)
            }
            return await wrappedPromise;
        }
    };
};

(async () => {
    console.log("开始");
    console.log("测试1");
    let ss=makeCancelable(timeout(30*1000));
    let s1=await ss.start(10*1000);//两种使用方法,1为设置超时时间
    console.log(s1);
    if(s1.isCanceled){
        console.log("await被强制关闭");
    }

    console.log("测试2");
    let ss=makeCancelable(timeout(30*1000));
    setTimeout(function(){
        ss.cancel();//两种使用方法,2为使用cancel方法强制关闭
    },10*1000);
    let s1=await ss.start();
    console.log(s1);
    if(s1.isCanceled){
        console.log("await被强制关闭");
    }

     console.log("结束")
})();
8 回复

内置语法 Promise.race 了解下?

const pTimeout = require('p-timeout');

try {
  const result = await pTimeout(longTask, 50);
} catch (error) {
  // timeout error
}

原理很简单,手写如下:

async function run() {
  const result = await Promise.race([
    longTask(),
    timeout(1000),
  ]);
  console.log(result);
}

run().catch(console.error);

async function longTask() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve('long job is done!');
    }, 2000);
  });
}

async function timeout(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(new Error(`timeout ${ms}ms`));
    }, ms);
  });
}

@atian25 详细看了一个race的用法,看来我的基础知识还是不够啊。非常感谢。

但事实上,楼主所谓await强制停止并未实现,放到await中的代码没有因为另一个任务抛错终止。据我所知,直接取出micro task的方法不存在,只有间接的在异步代码写反复检测是否超时。

先抛开实现代码,思考一个问题,已经将数据请求从 socket 发出到网络中,是否还能阻碍这些数据继续传递下去呢?

Promise 中执行一些资源属性的异步操作时,停止 await 并不是仅仅将 promise 的状态置为 resovle 或者 reject,如何释放/停止已经开始执行的资源,也是一个难点

这正是 AbortSignal / Cancellation API 要考虑的事

回到顶部