[ES6 系列] 你真的瞭解ES6嗎(三)

前言

本文是 ES6 系列的第三篇,能夠在 這裏 查看 往期全部內容git

本文的 答案 不必定是最優解釋,若是你有更好的想法或更優雅的寫法,歡迎留言討論es6

若是文章中有出現紕漏、錯誤之處,還請看到的小夥伴多多指教,先行謝過github

如下web

正文

下面的代碼輸出什麼面試

let promise = new Promise((resolve, reject) => {
    console.log(1)
    setTimeout(() => {
        resolve(2)
        console.log(3)
    }, 2000);
    reject('error')
})

promise
.then(res => {
    console.log(5)
})
.catch(err => {
    console.log(err)
})

答案ajax

1 error 3數組

要點解析:promise

  • promise 建立以後會當即執行
  • 狀態一旦改變就不會再變,也就是 rejectresolve 只會執行其中的一個
  • 異步隊列的執行順序

推薦閱讀 Js 執行機制微信


下面代碼輸出什麼異步

const first = () => (new Promise((resolve,reject)=>{
    console.log(1);
    let p = new Promise((resolve, reject)=>{
         console.log(2);
        setTimeout(()=>{
           console.log(3);
           resolve(4); 
        },0)
        resolve(5);
    }); 
    resolve(6);
    p.then((arg)=>{
        console.log(arg);
    });

}));

first().then((arg)=>{
    console.log(arg);
});
console.log(7);

答案

1 2 7 5 6 3

一樣是 promise 結合 js 執行機制的問題

  • promise 建立當即執行,依次輸出 1 2
  • 執行同步任務,輸出 7
  • 在執行上一步的時候已經將 p.then 以及 first.then 加入微任務執行隊列,因此依次輸出 5 6
  • 最後執行宏任務 setTimeout, 輸出 3

下面的代碼輸出什麼

Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)

答案

1

  • 若是參數是一個原始值,或者是一個不具備 then 方法的對象,則 Promise.resolve 方法返回一個新的 Promise 對象,狀態爲 resolved
  • then 方法接受的參數是函數,而若是傳遞的並不是是一個函數,就會致使前一個 Promise 的結果穿透到下面

爲何建議在 promise 最後調用 catch 方法

答案

首先,來看一個例子

Promise.resolve().then(res => {
    throw new Error('error')
}, err => {
    console.log(err)
}).then(res => {
    console.log(1)
})

上面的代碼中,咱們在 then 函數中拋出一個錯誤,想使用 then 中的第二個參數來捕獲這個錯誤。很顯然,錯誤在 Promise 函數體外拋出,冒泡到了最外層,成了未捕獲的錯誤,由於這裏捕獲的老是 以前的 Promise 產生的錯誤

因此,通常老是建議,Promise 對象後面要跟 catch 方法,這樣能夠處理 Promise 內部發生的錯誤

只是咱們須要注意的是 catch 方法也會返回一個新的 Promise 對象,能夠繼續使用 Promise 的方法,一樣也意味着 catch 方法中也可能產生錯誤


實現 mergePromise 函數,把傳進去的數組按順序前後執行,而且把返回的數據前後放到數組 data 中

const timeout = ms => new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve();
    }, ms);
});

const ajax1 = () => timeout(2000).then(() => {
    console.log('1');
    return 1;
});

const ajax2 = () => timeout(1000).then(() => {
    console.log('2');
    return 2;
});

const ajax3 = () => timeout(2000).then(() => {
    console.log('3');
    return 3;
});

const mergePromise = ajaxArray => {
    // 在這裏實現你的代碼

};

mergePromise([ajax1, ajax2, ajax3]).then(data => {
    console.log('done');
    console.log(data); // data 爲 [1, 2, 3]
});

// 要求分別輸出
// 1
// 2
// 3
// done
// [1, 2, 3]

答案

這個問題主要考察的就是咱們使用 Promise 對異步操做的控制

const mergePromise = ajaxArray => {
    // 保存數組在函數執行以後的結果
    let data = []
    
    // 建立一個 Promise 對象控制異步流程
    let p = Promise.resolve()

    // 遍歷數組按次序執行數組中的每一項
    // 將數組中每一項的執行結果保存起來到一個新數組
    ajaxArray.forEach(item => {
        p = p.then(item).then(res => {
            data.push(res)
            return data
        })
    })
    
    // 最終獲得的結果:返回一個新的 Promise 對象
    // return 的結果做爲參數傳遞到下次調用的 then 方法中
    return p
}

下面的代碼輸出什麼

function* foo(x) {
  var y = 2 * (yield (x + 1));
  var z = yield (y / 3);
  return (x + y + z);
}

let b = foo(5);
b.next()
b.next(15)
b.return('tadpole')
b.next(12)

答案

// {value: 6, done: false}
// {value: 10, done: false}
// {value: 'tadpole', done: true}
// {value: undefined, done: true}
  • next 的參數是上一次表達式的值
  • return 方法,能夠返回給定的值,而且終結遍歷 Generator 函數

下面的代碼輸出什麼

async function async1() {
    console.log("async1 start");
    await async2();
    console.log("async1 end");
    return 'async return';
}

async function async2() {
    console.log("async2");
}

console.log("script start");

setTimeout(function() {
    console.log("setTimeout");
}, 0);

async1().then(function (message) { console.log(message) });

new Promise(function(resolve) {
    console.log("promise1");
    resolve();
}).then(function() {
    console.log("promise2");
});

console.log("script end")

答案

// 執行同步代碼,遇到 setTimeout 將其加入到宏任務隊列
script start
// 執行 async1()
async1 start
// 遇到await 執行右側表達式後讓出線程,阻塞後面代碼
async2
// 執行 Promise 中的同步代碼 將 .then 推入到微任務隊列
promise1
// 執行同步代碼
script end
// 繼續執行 await 後面的代碼
// 這裏須要注意 async 函數返回的是 Promise 對象
// 將 async1後面的 .then 加入到微任務隊列
async1 end
// 執行前一輪添加到微任務隊列的代碼
promise2
// 後一輪微任務隊列的代碼
async return
// 開始下一輪evenloop,執行宏任務隊列中的任務
setTimeout

使用不一樣的方式實現下面的需求

// 紅燈三秒亮一次,綠燈兩秒亮一次,黃燈一秒亮一次;如何讓三個燈不斷交替重複亮燈
// 使用 Callback/Promise/Genertor/async 分別實現
// 亮燈函數以下

function red(){
    console.log('red');
}

function green(){
    console.log('green');
}

function yellow(){
    console.log('yellow');
}

答案

// callback
function loop() {
    setTimeout(() => {
        red()
        setTimeout(() => {
            green()
            setTimeout(() => {
                yellow()
                loop()
            }, 1000)
        }, 2000)
    }, 3000)
}
loop()

// Promise
function fn(timer, cb) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            cb()
            resolve()
        }, timer);
    })
}

let promise = Promise.resolve()

function loop() {
    promise.then(res => {
        return fn(3000, red)
    }).then(res => {
        return fn(2000, green)
    }).then(res => {
        return fn(1000, yellow)
    }).then(res => {
        loop()
    })
}

// Generator
function fn(timer, cb) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            cb()
            resolve()
        }, timer)
    })
}

function* gen() {
    yield fn(3000, red)
    yield fn(2000, green)
    yield fn(1000, yellow)
}

function loop(iterator, gen) {
    // 執行 Generator 函數
    let result = iterator.next()

    if (result.done) {
        // 這裏須要從新開始執行
        loop(gen(), gen)
    } else {
        result.value.then(res => {
            loop(iterator, gen)
        })
    }
}

loop(gen(), gen)

// Async
function fn(timer, cb) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            cb()
            resolve()
        }, timer)
    })
}

async function loop() {
    while (true) {
        await fn(3000, red)
        await fn(2000, green)
        await fn(1000, yellow)
    }
}

loop()

後記

以上就是本期 ES6 相關的全部內容,主要涉及的是 PromiseGenerator 以及 Async 函數相關的內容,經過幾個常見的面試題以及需求考察對 ES6 相關知識的瞭解程度

留一個筆記,也但願對看到的小夥伴能有些許幫助

感興趣的小夥伴能夠 點擊這裏 ,也能夠掃描下方二維碼關注個人微信公衆號,查看往期更多內容,歡迎 star 關注

image

參考

ECMAScript 6 入門

MDN

一道JavaScript面試題, 考察多種回調寫法

相關文章
相關標籤/搜索