函数式编程与JS异步编程,手写Promise

博客围绕JS异步编程展开,介绍了因JS单线程易阻塞而引入异步编程,通过EventLoop从消息队列取任务执行,区分了宏任务和微任务。还包含用Promise改进异步代码的练习,以及基于给定代码完成多个函数实现练习,最后涉及手写Promise。

一、谈谈对JS异步编程的理解,EventLoop、消息队列都是做什么的,什么是宏任务,什么是微任务?

首先,由于JS是单线程的,这样执行任务会发生线程阻塞。所有JS引入了异步编程,通过回调的方式来解决这种阻塞。

其次,对于像定时器这种异步任务以及IO任务、其它线程发送过来的任务,JS会将其放到消息队列中,通过EventLoop的机制从消息队列里面依次取出任务执行。

最后消息队列里的任务就是宏任务,微任务是promise、mutationObserver、nextTick。每一个宏任务都会配置一个微任务队列,微任务队列的执行时机是当前宏任务执行完毕、主线程退出之前。

二、将下面异步代码使用Promise的方式改进
(1)

setTimeout(()=>{
    var a = 'hello ';
    setTimeout(()=>{
        var b = 'lagou '
        setTimeout(()=>{
            var c = 'i 💓 u'
            console.log(a+b+c);
        },10)
    },10)
},10)

答:

let promise = new Promise((resolve,reject)=>{
    resolve('hello ')
}).then(res=>{
    return res + 'lagou '
}).then(res=>{
    return res + 'i love u'
}).then(res=>{
    console.log(res);
})

(2)基于以下代码完成下面4个练习

const fp = require('lodash/fp')
const cars = [
    {
        name:'Ferrari FF',
        horsepower:660,
        dollar_value:700000,
        in_stock:true
    },
    {
        name:'Spyker C12 Zagato',
        horsepower:650,
        dollar_value:648000,
        in_stock:false
    },
    {
        name:'Jaguar XKR-S',
        horsepower:550,
        dollar_value:132000,
        in_stock:false
    },
    {
        name:'Audi R8',
        horsepower:525,
        dollar_value:114200,
        in_stock:false
    },
    {
        name:'Aston Martin One-77',
        horsepower:750,
        dollar_value:1850000,
        in_stock:true
    },
    {
        name:'Pagani Huayra',
        horsepower:700,
        dollar_value:1300000,
        in_stock:false
    }
]

2.1 使用函数组合fp.flowRight()重新实现下面函数

let isLastInStock = function(cars){
    let last_car = fp.last(cars)
    return fp.prop('in_stock',last_car)
}

答:

const fn = fp.flowRight(fp.prop('in_stock'),fp.last);

2.2 使用fp.flowRight() fp.prop() fp.first()获取第一个car的name

const fn = fp.flowRight(fp.prop('name'),fp.first)

2.3 使用帮助函数_average重构averageDollarValue,使用函数组合的方式实现

let _average = function(xs){
    return fp.reduce(fp.add,0,xs)/xs.length
}
let averageDollarValue = function(cars){
    let dollar_values = fp.map((cars)=>{
        return cars.dollar_value
    },cars)
    return _average(dollar_values)
}

答:

const total = cars=>fp.map(cars=>cars.dollar_value,cars)
const fn = fp.flowRight(_average,total);
console.log(fn(cars));

2.4 使用flowRight写一个sanitizeNames()函数,返回一个下划线连接的小写字符串,把数组中的name转换成这种形式。

let _underscore = fp.replace(/\W+/g,'_');
const sanitizeNames = fp.flowRight(fp.map(_underscore),fp.map(fp.toLower),fp.map(car=>car.name))
console.log(sanitizeNames(cars));

三、基于下面提供的代码,完成以下四个练习

class Container {
    static of(val) {
        return new Container(val)
    }
    constructor(val) {
        this._val = val
    }
    map(fn) {
        return Container.of(fn(this._val))
    }
}

class Maybe {
    static of(x) {
        return new Maybe(x)
    }
    isNothing() {
        return this._val === null || this._val === undefined
    }
    constructor(x) {
        this._val = x
    }
    map(fn) {
        return this.isNothing() ? this : Maybe.of(fn(this._val))
    }
}
module.exports = {Maybe ,Container }

3.1 使用fp.add(x,y) fp.map(f,x)创建一个能让functor里的值增加的函数exl

let maybe = Maybe.of([5, 6, 1])
let exl = (x) => {
    return maybe.map(fp.map(a => fp.add(a, x)))
}
console.log(exl(2));

3.2 实现一个函数ex2 ,能使用fp.first获取列表的第一个元素

let xs = Container.of(['do','ray','me','fa','so','la','ti','do'])
let ex2 = ()=>{
    return xs.map(fp.first)
    //.map(item=>console.log(item))
}

3.3 实现一个函数ex3,使用safeProp和fp.first找到user的名字的首字母。

let safeProp = fp.curry((x,o)=>Maybe.of(o[x]))
let user = {id:2,name:'Albert'}
let ex3 = ()=>{
    let safe = safeProp('name',user)
    let names = safe.map(name=>name.split('')).map(fp.first)
    return names
}
console.log(ex3());

3.4 使用Maybe重写ex4 不要有if语句

// let ex4 = (n)=>{
//     if(n){
//         return parseInt(n)
//     }
// }

let ex4 = (n)=>{
  return Maybe.of(n).map(parseInt)
}

console.log(ex4(3.5));

四、手写Promise

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected'

class MyPromise {
    constructor(executor) {
        try {
            executor(this.resolve, this.rejected)
        } catch (error) {
            this.rejected(error)
        }
    }
    // 状态
    status = PENDING;
    // 成功后的值
    value = undefined;
    // 失败后的原因
    err = undefined;
    // 成功回调
    successCb = [];
    // 失败回调
    failCb = []
    resolve = value => {
        if (this.status !== PENDING) return
        this.status = FULFILLED;
        this.value = value;
        // this.successCb && this.successCb(this.value)
        while (this.successCb.length) {
            this.successCb.shift()()
        }
    }
    rejected = err => {
        if (this.status !== PENDING) return
        this.status = REJECTED;
        this.err = err;
        // this.failCb && this.failCb(this.err)
        while (this.failCb.length) {
            this.failCb.shift()()
        }
    }
    then(successCb, failCb) {
        successCb = successCb ? successCb : value => value;
        failCb = failCb ? failCb : err => { throw err }
        let promise2 = new MyPromise((resolve, reject) => {
            if (this.status === FULFILLED) {
                setTimeout(() => {
                    try {
                        let x = successCb(this.value)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            } else if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        let x = failCb(this.err)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            } else {
                //等待
                this.successCb.push(() => {
                    setTimeout(() => {
                        try {
                            let x = successCb(this.value)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                });
                this.failCb.push(() => {
                    setTimeout(() => {
                        try {
                            let x = failCb(this.err)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                });
            }
        })
        return promise2;
    }
    catch(cb){
        return this.then(undefined,cb)
    }
    finally(cb) {
        return this.then(value => {
            return MyPromise.resolve(cb()).then(() => value);
        }, err => {
            return MyPromise.resolve(cb()).then(() => { throw err })
        })
    }
    static all(arr) {
        let result = [];
        let index = 0;

        return new MyPromise((resolve, reject) => {
            function addData(key, value) {
                result[key] = value;
                index++;
                if (index === arr.length) {
                    resolve(result)
                }
            }
            for (let i = 0; i < arr.length; i++) {
                let current = arr[i];
                if (current instanceof MyPromise) {
                    current.then(value => addData(i, value), err => reject(err))
                } else {
                    addData(i, arr[i])
                }
            }

        })
    }
    static resolve(value) {
        if (value instanceof MyPromise) {
            return value
        } else {
            return new MyPromise((resolve) => resolve(value))
        }
    }
}

function resolvePromise(promise2, x, resolve, reject) {
    if (promise2 === x) {
        return reject(new TypeError('重复引用了'))
    }
    if (x instanceof MyPromise) {
        // x.then(value=>resolve(value),err=>reject(err))
        x.then(resolve, reject)
    } else {
        resolve(x)
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值