【JavaScript】设计可取消函数

有时候你会有一个长时间运行的任务,并且你可能希望在它完成之前取消它。为了实现这个目标,请你编写一个名为 cancellable 的函数,它接收一个生成器对象,并返回一个包含两个值的数组:一个 取消函数 和一个 promise 对象。

你可以假设生成器函数只会生成 promise 对象。你的函数负责将 promise 对象解析的值传回生成器。如果 promise 被拒绝,你的函数应将该错误抛回给生成器。

如果在生成器完成之前调用了取消回调函数,则你的函数应该将错误抛回给生成器。该错误应该是字符串 "Cancelled"(而不是一个 Error 对象)。如果错误被捕获,则返回的 promise 应该解析为下一个生成或返回的值。否则,promise 应该被拒绝并抛出该错误。不应执行任何其他代码。

当生成器完成时,您的函数返回的 promise 应该解析为生成器返回的值。但是,如果生成器抛出错误,则返回的 promise 应该拒绝并抛出该错误。

在处理这个问题时需要了解一下知识

cancel函数的惯用法。利用promise回调中的闭包来实现,调用cancel函数后可以去调用回调中的reject/resolve,例如:
let cancel
new Promise((resolve, reject) => {
    cancel = () => reject()
})
因为需要给generator传值,所以需要手动遍历,例如:
let p = generator.next()
while (!p.done) {
  // do sth. with p.value
  p = generator.next(v)
}

/**
 * @param {Generator} generator
 * @return {[Function, Promise]}
 */
var cancellable = function(generator) {
     // [1]一个 取消函数 和一个 promise 对象
    let cancel, promise

    promise = new Promise(async (resolve, reject) => {
        cancel = async () => {
            // [5]调用了取消回调函数
            try {
                // [6]应该将错误抛回给生成器。该错误应该是字符串 "Cancelled"
                let p = generator.throw('Cancelled')
                // [7]如果错误被捕获...应该解析为下一个生成或返回的值
                resolve(await p.value)
            } catch (e) {
                // [8]否则...应该被拒绝并抛出该错误
                reject(e)
            }
        }

        try {
            let p = generator.next()
            while (!p.done) {
                try {
                    // [2]生成器函数只会生成 promise 对象
                    let v = await p.value
    
                    // [3]将 promise 对象解析的值传回生成器
                    p = generator.next(v)
                } catch (e) {
                    // [4]如果 promise 被拒绝...应将该错误抛回给生成器
                    p = generator.throw(e)
                }
            }
            // [9]当生成器完成时...应该解析为生成器返回的值
            resolve(await p.value)
        } catch (e) {
            // [10]如果生成器抛出错误...应该拒绝并抛出该错误
            reject(e)
        }
    })
    return [cancel, promise]

};

/**
 * function* tasks() {
 *   const val = yield new Promise(resolve => resolve(2 + 2));
 *   yield new Promise(resolve => setTimeout(resolve, 100));
 *   return val + 1;
 * }
 * const [cancel, promise] = cancellable(tasks());
 * setTimeout(cancel, 50);
 * promise.catch(console.log); // logs "Cancelled" at t=50ms
 */

  • 18
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值