Part1.模塊一:函數式編程與 JS 異步編程、手寫 Promise

簡答題

一、談談你是如何理解JS異步編程的,EcentLoop、消息隊列都是做什么的,什么是宏任務,什么是微任務?

  • JS 異步編程:
    • 解答:
      ? ? ? ?JavaScript語言的執行環境是單線程,單線程是指一次只能完成一個任務,如果有多個任務,則需要排隊,等待前一個任務完成后,才能開始后一個任務。基于這種原因而產生了兩種執行任務的模式:同步模式和異步模式,且隨著JavaScript面臨的需求要來越多,它可以運行在瀏覽器、服務器上等,為了滿足這些需求,使得JavaScript的規模和復雜性也在持續增長,所以JavaScriptd中的異步編程也在不斷地調整,往更友好的方向發展,JavaScript異步編程經歷了回調函數、Promise、生成器函數Generator、以及現在Async/Await等幾個發展階段。
      ? ? ? ?在第一階段使用的是回調函數,它是最基本的異步操作方式,以Ajax請求最為常見,它是最簡單、容易理解和實現的異步編程;但是不利于代碼的閱讀和維護,各部分之間高度耦合,使得程序結構混亂,流程難以追蹤,每個任務只能指定一個回調函數,不能使用try catch捕獲錯誤,不能直接return,且極易出現回調地獄導致的調式困難,以及控制反轉導致的一系列信任問題
ajax(urlA, () => {
    // 處理邏輯
    ajax(urlB, () => {
        // 處理邏輯
        ajax(urlC, () => {
            // 處理邏輯
        })
    })
})

? ? ? ?在第二階段引入了Promise,它是ES6推出的一種異步編程的解決方案。Promise是承諾的意思,這個承諾在未來某個時刻會有一個確定的答復,該承諾有三種狀態:等待中(pending)、完成(resolved)、拒絕(rejected)。Promise是個構造函數,接受一個函數作為參數。作為參數的函數有兩個參數:resolve和reject,分別對應完成和拒絕兩種狀態。我們可以選擇在不同時候執行resolve或reject去觸發下一個動作,執行then方法里的函數。Promise實現了鏈式調用,每次調用then之后返回的都是一個Promise對象,如果在then使用了return,return返回的值會被Promise.resolve()包裝。它很好的解決了回調函數中的回調地獄,解決了控制反轉導致的信任問題,將代碼的執行主動權拿了回來;但是Promise一旦狀態從等待改變為其他狀態就不再可變了,還有如果不設置回調函數,Promise內部拋出的錯誤。

new Promise((resolve, reject) => {   
    console.log('new Promise');   
    resolve('success'); }) 
    console.log('end');

? ? ? ?第三階段使用生成器函數Generator,它是一種特殊的函數,其最大的特點是控制函數的執行。可以讓我們用同步的方式寫代碼,可以分步執行并得到異步操作的結果,能夠知曉異步操作的過程,以及切入修改異步操作的過程。但是需要手動去控制next(...),將回調成功的返回數據送回JavaScript的主流程中;

function *foo(x) {
  let y = 2 * (yield (x + 1));
  let z = yield (y / 3);
  return (x + y + z);
}
let it = foo(5);
console.log(it.next());   // => {value: 6, done: false}
console.log(it.next(12)); // => {value: 8, done: false}
console.log(it.next(13));// => {value: 42, done: true}

? ? ? ?最新階段的Async/Await異步處理編程,其中async函數返回一個 Promise 對象,就是將函數返回使用Promise.resolve(),和then處理返回值一樣,可以使用then方法添加回調函數。await后邊一般跟Promise對象,async函數執行遇到await后,等待后面的Promise對象的狀態從pending變成resolve后,將resolve的參數返回并自動往下執行直到下一個await或結束。它解決了Generator需要手動控制next(...)執行的問題。但它存在一個缺陷是如果多個異步代碼沒有依賴性卻使用了await會導致性能降低。

async function test() {
    console.log('1')
}
console.log(test)   // Promise {<resolve>: "1"}

? ? ? ?整個異步過程都是通過內部的消息隊列和事件循環實現的
? ? ? ?每個階段的突破都是為了解決現有階段的技術問題,異步編程的發展也是一個循序漸進的過程。

  • EventLoop、消息隊列:
    • 解答:
      ? ? ? ?事件循環機制和消息隊列的維護是由事件觸發線程控制的,事件觸發線程是由瀏覽器渲染引擎提供的,它會維護一個消息隊列
      ? ? ? ?EventLoop是事件循環,主要負責監聽調用棧(執行棧)和消息隊列(任務隊列),一旦調用棧中所有的任務都結束了,事件循環就會從消息隊列中取出第一個回調函數,然后壓入到調用棧中,一旦消息隊列中發生了變化,事件循環就會監聽到
      ? ? ? ?消息隊列:消息隊列是類似隊列的數據結構,遵循先入先出(FIFO)的規則。如果把調用棧理解為正在執行的工作表,那么消息隊列則可以理解成待辦的工作表,JS引擎會先做完調用棧中所有的任務,然后通過事件循環從消息隊列中再取一個任務出來繼續執行,以此類推,整個過程隨時可以往消息隊列中再去放任務,這些任務在消息隊列中會排隊等待事件循環
      ? ? ? ?事件循環機制:
      ? ? ? ? ? ?1.JS引擎線程會維護一個執行棧,同步代碼會依次加入執行棧中,然后依次執行并出棧
      ? ? ? ? ? ?2.JS引擎線程遇到異步函數,會將異步函數交給相應的WebApi,并繼續執行后面的任務
      ? ? ? ? ? ?3.WebApi會在條件滿足的時候,將異步對應的回調加入到消息隊列中,等待執行
      ? ? ? ? ? ?4.執行棧為空時,JS引擎線程會去取消息隊列中的回調函數(如果有的話),并加入到執行棧中執行
      ? ? ? ? ? ?5.完成后出棧,繼續執行4的操作,直至消息隊列中的回調函數為空,以上便是事件循環的機制
  • 宏任務、微任務
    • 解答:
      ? ? ? ?在JS中,有兩類任務隊列:宏任務隊列(macrotask)和微任務隊列(microtask),宏任務可以由多個,微任務只有一個
      • macrotask:主代碼塊、setTimeout、setInterval、setImmediate、I/O、UI rendering等(可以看到,事件隊列中的每一個事件都是一個 macrotask,現在稱之為宏任務隊列)
      • microtask:Promise、process.nextTick、Object.observer等

? ? ? ?每次執行棧執行的代碼即是一個宏任務,包括任務隊列(宏任務隊列)中的,因為執行棧中的宏任務執行完后會去取任務隊列(宏任務隊列)中的任務加入執行棧中
? ? ? ?在執行宏任務時遇到Promise等,會創建微任務(.then()里面的回調),并加入到微任務隊列隊尾;微任務必然是在某個宏任務執行的時候創建的,而在下一個宏任務開始之前,瀏覽器會對頁面重新渲染。同時,在上一個宏任務執行完成后,渲染頁面之前,會執行當前微任務隊列中的所有微任務。
? ? ? ?執行機制
? ? ? ? ? ?1.執行一個宏任務(執行棧中沒有就從消息隊列中獲取)
? ? ? ? ? ?2.執行過程中如果遇到微任務,就將微任務添加刀微任務的任務隊列中
? ? ? ? ? ?3.宏任務執行完畢后,立即執行當前微任務隊列中的所有微任務(依次執行)
? ? ? ? ? ?4.當前宏任務執行完畢,開始檢查渲染,然后GUI接管渲染
? ? ? ? ? ?5.喧渲染完畢后,JS引擎線程繼續,開始下一個宏任務(從宏任務隊列中獲取)

代碼題

一、將下面異步代碼使用Promise的方式改進

異步代碼.png

解答:使用Promise的方式改進實現如下:

// 使用Promise改進setTimeout異步代碼
new Promise((resolve, reject) => {
    resolve('hello')
}).then(value => {
    return value + ' ' + 'lagou' // value = hello 
})
.then(value => {
    return value + ' ' + 'I ? U'  // value = hello lagou 
})
.then(value => {
    console.log(value)   // hello lagou I ? U
})

二、基于以下代碼完成四個練習

代碼1-題目.png

代碼2-題目.png
練習1:使用組合函數fp.flowRight()重新實現下面這個函數

練習1-題目.png

解答:fp.flowRight()重新實現如下:

//練習1
let isLastInstock = fp.flowRight(fp.prop('in_stock') , fp.last)
console.log(isLastInstock(cars)) //false   即最后一條數據的in_stock屬性值為fase
練習2:使用fp.flowRight(),fp.prop(),fp.first()獲取第一個car的name

解答:獲取第一個car的name實現如下:

// 練習2
let getFirstCarName = fp.flowRight(fp.props('name'), fp.first)
console.log(getFirstCarName(cars))  //[ 'Ferrari FF' ]
練習3:使用幫助函數_average()重構averageDollarValue,使用函數組合方式實現

練習3-題目.png

解答:重構averageDollarValue實現如下:

let averageDollarValue = fp.flowRight(_average,fp.map(car => car.dollar_value))
console.log(averageDollarValue(cars))  //790700
練習4:使用flowRight寫一個sanitizeName()函數,返回一個下劃線連接的小寫字符串,把數組中的name轉換為這種形式,例如:sanitizeName(["Hello World"]) => ["hello_world"]

練習4-題目.png

解答:使用flowRight寫一個sanitizeName()函數實現如下:

// 練習4
let _underscore = fp.replace(/\W+/g, '_')

//先遍歷數組把里面字符串轉成小寫,在遍歷數組將非單字字符轉換成下劃線
let sanitizeName1 = fp.flowRight( fp.map(_underscore), fp.map(fp.toLower))
//遍歷數組中使用fp.flowRight組合函數,先轉換成小寫,再將非單字字符轉換成下劃線
let sanitizeName2 = fp.flowRight( fp.map(fp.flowRight(_underscore, fp.toLower)))
console.log(sanitizeName2(["Hello World",'LaGou Study']))  //[ 'hello_world', 'lagou_study' ]

三、基于下面提供的四個代碼,完成后續的四個練習

代碼1-題目.png

代碼2-題目.png

代碼3-題目.png
練習1:使用fp.add(x,y)和fp.map(f,x)創建一個能讓functor里的值增加的函數ex1

練習1-題目.png

解答:讓functor里的值增加的函數實現如下:

// 練習1
let ex1 = () => {
    return fp.map(fp.add(1), maybe.map(x => x)._value)
}
console.log(ex1())  //[ 6, 7, 2 ]
練習2:實現一個函數ex2,能夠fp.first獲取列表的第一個元素

練習2-題目.png

解答:獲取列表的第一個元素實現如下:

//練習2
let xs = Container.of(['do', 'ray', 'me', 'fa', 'so', 'la', 'ti', 'do'])

let ex2 = () => {return fp.first(xs.map(x => x)._value)}
console.log(ex2())  //do
練習3:實現一個函數ex3,使用safeProp和fp.first找到user的名字的首字母

練習3-題目.png

解答:使用safeProp和fp.first找到user的名字的首字母實現如下:

// 練習3
let safeProp = fp.curry(function (x, o){
    return Maybe.of(o[x])
})
let user = {id: 2, name: 'Albert'}
let ex3 = () => {
    return fp.first(safeProp(Object.keys(user).indexOf('name'),Object.values(user))._value)
}
console.log(ex3()) //A
練習4:使用MayBe重寫ex4,不要有if語句
練習4.png
// 練習4
let ex4 = function (n) {
    if(n){
        return(parseInt(n))
    }
}

let ex5 = n =>{
    return Maybe.of(n)._value 
}

let ex6 = n =>{
    return !!n? Maybe.of(n)._value : undefined
}
console.log(ex4(''))
console.log(ex5(''))
console.log(ex6(''))
注:ex5的寫法會在空字符串和null的時候導致輸出和ex4,ex6不一樣

四、手寫實現MyPromise源碼

要求:盡可能還原Promise中的每一個API,并通過注釋的方式描述思路和原理

MyPromise源碼(myPromise.js)
/*由于這個狀態頻繁使用,為了使用這個常量時編輯器有代碼提示并能夠復用,故把它定義為常量*/
const PENDING = 'pending'  //等待
const FULFILLED = 'fulfilled'  //成功
const REJECTED = 'rejected'  //失敗

class MyPromise{
    //構造函數  ==》 立即執行執行器  ==》 指的是傳遞過來的回調函數
    constructor(executor) {

        // 執行器錯誤處理 當執行器中代碼在執行過程中發生錯誤的時候,這個時候就讓promise狀態變成失敗
        try{
            executor(this.resolve, this.reject)
        }catch (e) {
            //捕獲執行器的錯誤
            this.reject(e)
        }
    }

    /*狀態是每個promise對象獨有的,故因該把狀態屬性定義為實例屬性*/
    status = PENDING   //promise狀態  ===》 默認值為等待

    //由于每個promise對象都有自己成功之后的值,都有自己失敗的原因,故應該把這兩個屬性定義為實例的屬性
    value = undefined  //成功之后的值
    reason = undefined //失敗后的原因

    //由于then方法可能會被多次調用,聯想到數組能夠同時存儲多個函數 故在這里將屬性定義為數組
    successCallback = [] //成功回調
    failCallback = []    //失敗回調

    //定義為箭頭函數的目的:將來在直接調用某個普通函數時,這個函數的this指向是window或者undefined,為了能讓this的指向為類的實例對象即promise對象,故而使用箭頭函數
    resolve = value => {

        //為了確保狀態確定后就不可更改,需加以判斷
        //如果狀態不是等待,阻止程序向下執行
        if(this.status !== PENDING) return

        //將狀態更改為成功
        this.status = FULFILLED

        //將傳遞過來的值進行賦值 ==》 保存成功后的值
        this.value = value

        //判斷成功回調是否存在 如果存在 則調用并傳遞相應的參數
        //數組中存儲了多個回調函數,我們需要循環遍歷這個數組,并在循環的過程中調用這個回調函數
        //當數組的長度不為0時,就繼續執行循環體中的代碼
        //考慮到需要從前往后執行,故調用數組的shift方法,把前面的回調函數彈出來
        while(this.successCallback.length) this.successCallback.shift()()
    }

    reject = reason => {

        //為了確保狀態確定后就不可更改,需加以判斷
        //如果狀態不是等待,阻止程序向下執行
        if(this.status !== PENDING) return

        //將狀態更改為失敗
        this.status = REJECTED

        //將傳遞過來的值進行賦值 ==》 失敗后的原因
        this.reason = reason

        //判斷失敗回調是否存在 如果存在 則調用并傳遞相應的參數
        //數組中存儲了多個回調函數,我們需要循環遍歷這個數組,并在循環的過程中調用這個回調函數
        //當數組的長度不為0時,就繼續執行循環體中的代碼
        //考慮到需要從前往后執行,故調用數組的shift方法,把前面的回調函數彈出來
        while(this.failCallback.length) this.failCallback.shift()()
    }

    //then要被定義在原型對象中,并接受成功回調和失敗回調兩個參數
    then (successCallback, failCallback){

        //在調用then方法不傳遞任何參數的時候,要將最先的成功狀態依次傳遞給有回調函數的then方法
        successCallback = successCallback? successCallback : value => value
        failCallback = failCallback? failCallback : reason => {throw reason}

        //then要實現鏈式調用,then方法必須返回promise對象,上一個回調的返回值傳遞給下一個then成功的回調
        let promise2 = new MyPromise((resolve, reject)=>{

            //判斷狀態并調用對應的回調函數并傳遞相應的參數
            if(this.status === FULFILLED){

                //由于promise2還沒被實例完,在實例過程中獲取不到,故使用異步實現,讓同步代碼先實現,再來執行異步代碼,這時候就能獲取到promise2
                setTimeout(()=>{

                    //then方法中的回調函數在執行過程中報錯,這個錯誤要在下一個then的reject中捕獲到
                    try{
                        let x = successCallback(this.value)
                        resolvePromise( promise2, x, resolve, reject)
                    }catch (e) {
                        //捕獲then回調的錯誤
                        reject(e)
                    }
                }, 0)
            }else if(this.status ===REJECTED){

                //由于promise2還沒被實例完,在實例過程中獲取不到,故使用異步實現,讓同步代碼先實現,再來執行異步代碼,這時候就能獲取到promise2
                setTimeout(()=>{

                    // then方法中的回調函數在執行過程中報錯,這個錯誤要在下一個then的reject中捕獲到
                    try{
                        let x = failCallback(this.reason)
                        resolvePromise( promise2, x, resolve, reject)
                    }catch (e) {
                        //捕獲then回調的錯誤
                        reject(e)
                    }
                }, 0)
            }else{

                //說明當前狀態等待,但不知是調用成功還是失敗的回調
                //故將成功回調和是失敗回調存儲起來
                this.successCallback.push(() => {
                    successCallback()
                    setTimeout(()=>{
                        try{
                            let x = successCallback(this.value)
                            resolvePromise( promise2, x, resolve, reject)
                        }catch (e) {
                            //捕獲then回調的錯誤
                            reject(e)
                        }
                    }, 0)
                })
                this.failCallback.push(() => {
                    setTimeout(()=>{
                        try{
                            let x = failCallback(this.reason)
                            resolvePromise( promise2, x, resolve, reject)
                        }catch (e) {
                            //捕獲then回調的錯誤
                            reject(e)
                        }
                    }, 0)
                })
            }
        });
        return promise2
    }

    //無論當前這個promise對象最終的狀態是成功還是失敗,finally中的這個回調函數始終都會執行一次e
    //在finally方法的后面可以鏈式的調用then方法拿到當前這個promise對象返回的結果
    finally (callBack){
        //如何得到當前promise對象的狀態  ==》 this.then方法可以
        return this.then(value=>{
            //在finally中return了一個promise對象
            return MyPromise.resolve(callBack()).then(()=>value)
        },reason=>{
            return MyPromise.resolve(callBack()).then(()=> {throw reason})
        })
    }

    //用于當前promise對象失敗的情況,如果沒有傳遞失敗的回調函數,則會被catch捕獲到
    catch(failCallback){
        return this.then(undefined, failCallback)
    }

    // all方法是用來解決異步并發問題的,它允許我們按照異步代碼調用的順序得到異步執行的結果
    // all的返回值也是一個promise對象,在后面可以鏈式對用then方法
    // 在all中的promise對象都是成功的,那么all最后的結果也是成功,如果有一個失敗,那么結果就是失敗的
    // 通過類調用,故為靜態方法,該方法接收一個數組作為參數
    static all (array){
        let results = []
        let index = 0

        return new MyPromise((resolve, reject) => {
            function addData(key, value) {
                results[key] = value
                index++
                // 針對異步情況下,判斷index的值和數組的長度相等,說明數組中所有的內容都執行完了,從而而決定是否調用resolve回調函數
                if(index === array.length){
                    resolve(results)
                }
            }

            //循環該數組
            for(let i = 0; i < array.length; i++){
                let current = array[i]
                if(current instanceof MyPromise){
                    //promise對象,若成功的話將成功的值添加到數組中,若有一個失敗的話失敗的話則將失敗的原因通過reject回調
                    current.then(value => addData(i, value), reason => reject(reason))
                }else{
                    //普通值 則直接添加到數組中
                    addData(i, array[i])
                }
            }

        })
    }

    //如果是普通值,則創建一個promise對象,被將這個值包裹在promise對象中,然后把創建出來的promise對象作為resolve方法的返回值,才能在后面鏈式調用then方法
    //如果是promise對象,則原封不動的將這個promise對象再作為resolve方法的返回值,所以才能在后面調用then方法,通過then方法的成功回調拿到這個promise對象的返回值
    static  resolve (value){
        if(value instanceof  MyPromise) return value
        return new MyPromise(resolve => resolve(value))
    }
}

//判斷 x 值時普通值還是promise對象
//如果是普通值,直接調用resolve
//如果是promise對象 查看promise對象返回的結果
//再根據promise對象返回的結果 決定調用resolve 還是調用reject
function resolvePromise(promise2, x, resolve, reject){
    //相等表示自己返回自己(Promise對象自返回),這時應該調用reject回調函數
    if(promise2 === x){
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    if( x instanceof  MyPromise){
        //promise對象
        x.then(resolve,reject)
    }else{
        //普通值
        resolve(x)
    }
}

//導出當前類
module.exports = MyPromise;

測試代碼(index.js)
/**
 * 了解promise原理及原理代碼實現
 * 1.Promise 就是一個類 在執行這個類的時候 需要傳遞一個執行器進去 執行器會立即執行 故放在promise類的構造器中
 * 2.Promise 中有三種狀態 分別為 成功(fulfilled) 失敗(rejected) 等待(pending)
 *  pending -> fulfilled
 *  pending -> rejected
 ** 一旦狀態確定就不可更改
 * 3.resolve和reject函數是用來更改狀態
 * resolve:fulfilled
 * reject:rejected
 * 4.then方法內部做的事情就是判斷狀態 如果狀態成功 調用成功的回調函數 如果狀態失敗 調用失敗的回調函數 then被定義為原型對象當中
 * 5.then成功回調有一個參數 表示成功之后的值 then失敗回調有一個參數 表示失敗的原因
 **/
//導向MyPromise
const MyPromise = require('./myPromise')

//創建promise對象    resolve  reject 兩個函數參數
let promise = new Promise((resolve, reject) => {
    //把狀態變成成功 參數為成功后的值
    resolve()

    //把狀態編程失敗  參數為失敗的原因
    reject()
})

//需實現promise的then方法,要先了解其中傳遞兩個回調函數及其含義
//調用then方法時,首先要去判斷promise狀態,成功的話則調用成功回調函數,失敗的話則調用失敗回調函數
//由于then能被任意一個promise對象調用,故應該將它定義在原型對象中
//then成功回調有一個參數(value) 表示成功之后的值 then失敗回調有一個參數(reason) 表示失敗的原因
promise.then(value=>{},reason=>{})


/** 1.類核心邏輯實現調用 **/
/*let promise1 = new MyPromise((resolve, reject) => {
    resolve('成功')

    // reject('失敗')
})

promise1.then(value => {
    console.log(value)  // 成功
}, reason => {
    console.log(reason)  // 失敗
})*/

/** 2.在Promise類中加入異步邏輯 **/
/*let promise2 = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('成功')
    },2000)

    // reject('失敗')
})

promise2.then(value => {
    console.log(value)  // 等待2s后輸出成功
}, reason => {
    console.log(reason)  // 等待2s后輸出失敗
})*/

/** 3.實現then方法多次調用添加多個處理函數 **/
/*let promise3 = new MyPromise((resolve, reject) => {
    resolve('成功')

    // reject('失敗')
})

promise3.then(value => {
    console.log(1)  // 1
    console.log(value)  // 成功
}, reason => {
    console.log(reason)  // 失敗
})

promise3.then(value => {
    console.log(2)  // 2
    console.log(value)  // 成功
}, reason => {
    console.log(reason)  // 失敗
})

promise3.then(value => {
    console.log(3)  // 3
    console.log(value)  // 成功
}, reason => {
    console.log(reason)  // 失敗
})*/

/** 4./5.實現then方法的鏈式調用 **/
//后面then方法拿到的值實際上是上一個回調函數的返回值
/*let promise4 = new MyPromise((resolve, reject) => {
    resolve('成功')

    // reject('失敗')
})
//測試4 then中返回值的情況
promise4.then(value => {
    console.log(value)  // 成功
    return 100
}).then(value => {
    console.log(value)
})
//測試5  then中返回promise情況
function other(){
    return new MyPromise((resolve, reject) => {
        resolve('other')
    })
}
promise4.then(value => {
    console.log(value)  // 成功
    return other()
}).then(value => {
    console.log(value)  // other
})*/

/** 6.then方法鏈式調用識別Promise對象自返回 **/
/*let promise6 = new MyPromise((resolve, reject) => {
    resolve('成功')
    // reject('失敗')
})

let p6 = promise6.then(value => {
    console.log(value)
    return p6
})

p6.then(value => {
    console.log(value)  //成功
},reason => {
    console.log(reason.message)  //Chaining cycle detected for promise #<Promise>
})*/

/** 7.捕獲錯誤及then鏈式調用其他狀態代碼補充 **/
// 執行器錯誤   then方法中的回調函數在執行過程中報錯,這個錯誤要在下一個then的reject中捕獲到
/*let promise7 = new MyPromise((resolve, reject) => {
    // throw new Error('executor error')
    // resolve('成功')
    reject('失敗')
})

promise7.then(value => {
    console.log(value)  //成功
},reason => {
    console.log(reason.message)  //executor error
})

promise7.then(value => {
    console.log(value)  //成功
    throw new Error('then error')
},reason => {
    console.log(reason.message)  //executor error
    return 10000
}).then(value => {
    console.log(value)  // 成功  10000
    // throw new Error('then error')
},reason => {
    console.log('xxx')   //xxx
    console.log(reason.message)  //then error
})*/

/** 8.then中方法編程可選參數 **/

/*let promise8 = new MyPromise((resolve, reject) => {
    resolve('成功')
    // reject('失敗')
})
promise8.then().then().then(value =>
    console.log(value) //成功  失敗
)*/


function p1() {
    return new MyPromise((resolve, reject) => {
        setTimeout(() => {
            resolve('p1')
        }, 2000)
    })
}

function p2() {
    return new MyPromise((resolve, reject) => {
        // resolve('p2')
        reject('失敗')
    })
}

/** 9.promise.all方法的實現 **/
/*MyPromise.all(['a', 'b', p1(), p2(), 'c']).then(result =>
    console.log(result)  // [ 'a', 'b', 'p1', 'p2', 'c' ]

)*/

/** 10.promise.resolve方法的實現 **/
/*MyPromise.resolve(100).then(value => console.log(value))
MyPromise.resolve(p1()).then(value => console.log(value))*/

/** 10.promise.finally方法的實現  **/
/*p2().finally(()=>{
    console.log('finally')
    return p1()
}).then(value=>{
    console.log(value)  // p2
},reason=>{
    console.log(reason)
})*/

/** 11.promise.catch方法的實現 **/
/*p2().then(value => console.log(value))
    .catch(reason => console.log(reason))*/
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,208評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,746評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,666評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,477評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,960評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,200評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,726評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,617評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,807評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,049評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,425評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,674評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,432評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,769評論 2 372