一道面試題:sleep函數實現

源碼地址:github.com/flitrue/ts-…前端

先看題目:ios

  1. 請實現以下函數;
function sleep(timeout: number): Promise {
  // 待實現
}
複製代碼
  1. 請修改上述函數的接口和實現,讓該函數支持取消。也就是說,能夠在sleep沒有結束前,promise提早resolve;
  2. 請爲2中實現的函數提供幾組單元測試,示意便可;
  3. 如何證實2中實現的函數不會內存泄露。

下面咱們開始分析這道面試題:git

  1. 明白sleep函數是幹嗎用的;
  2. 從僞代碼中咱們能夠看出,這道題用到了typescript;
  3. 並且sleep函數返回一個promise類型的值,說明須要用promise實現。

sleep函數是能夠暫停函數在一段時間內執行,在沒有promise的時代,sleep函數基本都是經過setTimeout控制的,promise出現之後,貌似前端coder發現了新大陸,各類花裏胡哨的擼它,創造出各類各樣的異步編程庫,好比目前最流行的axios。github

首先咱們不考慮ts實現,下面是我初版的實現:面試

function sleep(timeout) {
    return new Promise(resolve => setTimeout(resolve, timeout))
}
複製代碼

看着很簡單又簡潔,經過返回一個Promise實例,到了指定的時間執行resolve方法。可是這種實現只知足了面試題中的第一個問題。接下來咱們須要考慮如何中斷promise,實現提早結束讓程序繼續執行。typescript

也許喜歡專研的同窗,看到這裏確定會想到axios庫中有個CancelToken,能夠取消請求。CancelToken基本使用以下:編程

var CancelToken = axios.CancelToken;
var source = CancelToken.source();

axios.get('/user/12345', {
  cancelToken: source.token
}).catch(function(thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // handle error
  }
});

// cancel the request (the message parameter is optional)
source.cancel('Operation canceled by the user.');
複製代碼

下面是個人改進,在promise增長一個cancel屬性,返回resolve方法axios

function sleep(timeout) {
    var res;
    var promise = new Promise(function (resolve) {
        res = resolve;
        setTimeout(function () {
            resolve('done');
        }, timeout);
    });
    promise.cancel = res;
    return promise;
}
複製代碼

第一個和第二個問題解決了,咱們寫幾個測試用例,驗證咱們的函數正確性。promise

// 測試用例1
function test1() {
    console.info('test1 start');
    sleep(2000).then(function (res) {
        console.log('2s later ' + res);
    });
}
test1(); // result: 2s later done
複製代碼
// 測試用例2
function test2() {
    console.info('test2 start');
    var p = sleep(5000);
    p.then(function (res) {
        console.log(res);
    });
    setTimeout(function () {
        p.cancel('2s later end');
    }, 2000);
}
test2(); // result: 2s later end
複製代碼

你覺得這樣就結束了嗎?第四個問題咱們尚未解決,既然問了這麼問題,那必然是有緣由的。異步

當sleep暫停時間尚未結束前,咱們中斷了sleep函數,setTimeout函數其實還佔用着內存,致使內存泄露,因此咱們須要將定時器在執行cancel的時候取消掉。

function sleep(timeout) {
    var res,timer;
    var promise = new Promise(function (resolve) {
        res = resolve;
        timer = setTimeout(function () {
            resolve('done');
        }, timeout);
    });
    var cancel = function (data) {
      res(data);
      clearTimeout(timer)
    }
    promise.cancel = cancel;
    return promise;
}
複製代碼

到此,支持中斷的sleep函數書寫完畢,你看廢了嗎? 接下來我將ts版的實現貼出來,僅供你們參考,如何有更好的實現,能夠在留言區告訴我。

type CancelablePromise = Promise<any> & { cancel: any }

function sleep(timeout: number): CancelablePromise {
  let res: (v: string) => void, timer: NodeJS.Timer;
  let promise = new Promise(resolve => {
    res = resolve
    timer = setTimeout(() => {
      resolve('done')
    }, timeout)
  }) as CancelablePromise
  let cancel = function (data: string) {
    res(data)
    clearTimeout(timer)
  }
  promise.cancel = cancel;
  return promise
}

export default sleep;
複製代碼

今天是2020年6月1日兒童節,祝各位大朋友、小朋友,今天只作小孩,保持咱們的童心,敢作夢、敢實現。

關注個人公衆號(全棧碼農)或加我wx(w34638660),和我一塊兒成長。

相關文章
相關標籤/搜索