一道前端笔试题

clipboard.png

我能想到的办法是记录下任务完成所运行的时间,然后和规定的时间比较,如果大于规定的时间,就输出timeout,如果小于规定的时间,就输出结果。
可是好像和题目的要求有点不符,不知道怎么实时监听这个任务,一旦到达了规定的时间,没有得到想要的结果,就输出timeout

阅读 3.2k
3 个回答

前面几行是实现代码,后面一堆垃圾代码都是测试。并行异步的话,主要还是考虑 Promise, Generator, async function 来实现。如果可以使用库的话,可以参考 js-csp,专为并行协作程序而设计,可以参考我翻译的文章Generator 处理并行任务

// make sure all your callbacks are 'error-first-style'
const promiseFac = task => new Promise((resolve, reject) => {
    const asyncFn = task[0]
    const args = task.slice(1)
    const cb = (err, data) => {
        if (err) reject(err)
        else resolve(data)
    }
    asyncFn(...args, cb)
})

const timeoutFac = duration => new Promise(resolve => {
    setTimeout(() => resolve('timeout'), duration)
})

const runTask = async function({duration, tasks, done, fail, timeout}) {
    const tasksPromises = tasks.map(t => promiseFac(t))
    try {
        const res = await Promise.race([
            Promise.all(tasksPromises),
            timeoutFac(duration)
        ])

        if(res === 'timeout') {
            timeout()
        } else {
            done(...res)
        }
    } catch(err) {
        fail(err)
    }
}

// just for test, any asyncFunc you like , but i write follows.
function asyncFuncA(x, y, cb) {
    setTimeout(() => {
        if (x === 0) cb(`param1 of asyncFuncA can't be ${x}`)
        else cb(null, x + y)
    }, 500)
}
function asyncFuncB(cb) {
    setTimeout(() => cb(null, 'response from asyncFuncB'), 100)
}
function asyncFuncC(x, cb) {
    setTimeout(() => {
        cb(null, x)
    }, 1000)
}
// test 1, done will be call
runTask({
    duration: 2000,
    tasks: [
        [asyncFuncA, 1, 2],
        [asyncFuncB],
        [asyncFuncC, 3]
    ],
    done(x, y, z) {
        console.log(x, y, z)
    },
    fail(err) {
        console.log(err)
    },
    timeout() {
        console.log('it\'s time out')
    }
})
// timeout will be call
runTask({
    duration: 100,
    tasks: [
        [asyncFuncA, 1, 2],
        [asyncFuncB],
        [asyncFuncC, 3]
    ],
    done(x, y, z) {
        console.log(x, y, z)
    },
    fail(err) {
        console.log(err)
    },
    timeout() {
        console.log('it\'s time out')
    }
})
// fail will be call
runTask({
    duration: 2000,
    tasks: [
        [asyncFuncA, 0, 2],
        [asyncFuncB],
        [asyncFuncC, 3]
    ],
    done(x, y, z) {
        console.log(x, y, z)
    },
    fail(err) {
        console.log(err)
    },
    timeout() {
        console.log('it\'s time out')
    }
})

我感觉没那么高大上,其实考察的是你的设计思路,把问题分解开,然后再串起来,单拎出每一个点都很简单。
1 超时判定。开一个timer,并记录当前时间,然后所有方法返回时要做一个是否超时判断,不超时清除timer,调用回调;超时的话就静默不用管了。
2 数组转换成方法参数。写个工具方法,很简单。

function fnCall(list) {
  return list[0].apply(list.splice(1));
}

3 并行执行方法。这个就很多方法了:promise, async, generator,我写个最简单的计数器思路:

// fns = [fn1, fns, fn3, ...];
function parallel(fns, callback) {
  var count = fns.length;
  var results = [];

  // 闭包 防止结果顺序串了
  var closure = function(fn, i) {
    fn(function(data) {
      count = count - 1;
      results[i] = data;

      // 全部返回
      if (count == 0) {
        callback(results);
      }
    });
  };

  for (var i = 0; i < fns.length; i++) {
    closure(fns[i], i);
  }
}

我做了,用setTimeout,延时判断

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题