迈入大前端的第一章 2021-4-16

本文介绍了函数式编程的概念及其在JavaScript中的应用,如高阶函数和闭包。同时,详细讲解了Promise的使用,包括状态转换、链式调用以及解决回调地狱问题。此外,还提到了Generator作为另一种异步解决方案,并简单实现了Promise的类源码。通过学习,可以加深对前端异步编程的理解。
摘要由CSDN通过智能技术生成

向学姐学习!


前言

今天是学习大前端的第三天,也是人生第一次写IT笔记的一天。4-16是一个值得纪念的日子。
今天我将对我学习的Part1-task1模块进行一个总结


以下是本篇文章正文内容

一、函数式编程是什么?

  • 函数式编程(Functional Programming)简写FP
  • 是编程范式之一,其他还有面向对象编程(new),面向过程编程(感觉自己目前是这样的思维),并列关系
  • 思维方式:把现实世界的事物和事物之间的联系抽象到程序世界(对运算过程进行抽象
  • 程序本质:根据输入通过计算得到相应的输出,程序开发中会有很多这种输入输出的函数就是要对这些函数进行抽象!
  • 函数式编程中的函数指的不是程序中的函数,而是数学中的函数即映射关系,例:y=sin(x),x和y的关系(x确定了y的值也确定了!
  • 相同的输入始终要得到相同的输出纯函数
  • 函数式编程用来描述数据之间的映射(y=fn(x),fn()来描述x和y的关系
  • 举个例子
//非函数式 面向过程编程
let a=1
let b=2
let c=a+b
console.log(c)
//函数式 细粒度 可以重用 组合成高阶函数 
function add(n1,n2)=>{
return  n1+n2
}
let sum=add(1,2)

二、为什么要学习函数式编程?

  • 函数式编程是因为react流行起来
  • Vue3也开始拥抱函数式编程
  • 函数式编程可以抛弃this、
  • 打包过程中可以更好利用tree shaking过滤掉无用代码
  • 方便测试,方便并行处理、
  • 有很多库可以帮助我们函数式开发:lodash,underscore,ramda
  • 以上目前因个人原因都没有使用到 !!!(以后会的)

三、函数是一等公民

  • 在JS中函数是一个普通对象,它可以存储到变量/数组中,可以作为参数和返回值,我们还可以通过new Function(‘alert(1)’)来构造一个函数

四、高阶函数(Higher-order function)

  • 函数可以作为参数和返回值
  • 模拟2个高阶函数 作为参数
//forEach
let forEach=(arr,fn)=>{
	for(let v of arr){
		fn(v)
	}
}
let arr1=[0,1,2,3,4,5]

	forEach(arr1,(item)=>{
		console.log(item)
	})
//filter
let filter=(arr,fn)=>{
	let array=[]
	for(let v of arr){
		if(fn(v)){
			array.push(v)
		} 
	}
	return array
}
let arr2=[13,15,18,20,22]

	filter(arr2,(item)=>{
		return item>=18
	})
  • 模拟JQ的once 作为返回值
//once  应用场景 支付
let once=(fn)=>{
	let first=true
	//这里我用 箭头函数 会发生意外 因为箭头函数没有arguments和 箭头函数没有this指向,this的值要向上一层作用域链this是个空对象 
	return function(){
		if(first){
			first=false
			fn.apply(this,arguments)
		}
	}
}
let pay=once((money)=>{
	console.log(`多少${money}`)
})
pay(5)
pay(5)
pay(5)
pay(5)
pay(5)

  • 意义:代码更简洁,帮我们屏蔽细节只需要关注目标,用来抽象通用的问题

五、闭包(Closure)

  • 在另一个作用域中调用一个函数的内部函数并且访问到该函数的作用域中的成员

六、Promise

  • promise3个状态 peeding,成功onfulfilled,失败onrejected。一旦执行完成,结果不可逆
  • 使用案例-封装ajax
const { reject } = require("lodash");

function ajax(url){
    return new Promise((resolve,reject)=>{
        let xhr=new XMLHttpRequest()
        xhr.open('GET',url)
        xhr.responseType='JSON'
        xhr.onload=()=>{
            if(this.status===200){
                resolve(xhr.response)
            }else{
                reject(new Error(xhr.responseText))
            }
        }
        xhr.send()
    })
}
ajax('testURL').then(res=>{
    console.log(res)
},err=>{
    console.log(err);
})

//误区  回调地狱
ajax('testURL').then(res => {
    ajax(res.url).then(res2 => {
        ajax(res2.url).then(res3 => {
            ajax(res3.url).then(res4 => {
                ajax(res4.url).then(res5 => {

                })
            })
        })
    })
}, err => {

})
//正确写法
ajax('testURL').then(res=>{
    console.log(res)
},err=>{
    console.log(err);
}).then(res=>{
	console.log(res)
}).then(res=>{
	console.log(res)
})
  • Promise对象的then方法会返回一个Promise全新对象
  • 后面的then是为上一个then返回的Promise对象注册回调
  • 前面then回调函数的返回值会作为后面then方法中的回调函数的参数
  • 如果回调函数返回的是Promise,那后面的then就是为这个Promise注册回调
  • promise.all&promise.race的使用区别
//all 等待所有的任务结束
Promise.all([promise对象1,promise对象2,Promise对象3])
.then(res=>{
	console.log(res)  //res是一个array 返回3个Promise的返回结果
})
.catch(err=>{
	console.log(err)  //err是只要有一个Promise返回失败就会执行catch
})
//race 只会等待第一个执行结束的任务
Promise.race([promise对象1,promise对象2,Promise对象3])
.then(res=>{
	console.log(res) //res是传参的多个Promise对象中第一个执行完毕的Promise回调
})
  • 宏任务和微任务
console.log("start")
setTimeout(()=>{
    console.log('setTimeOut')
},0)
Promise.resolve("promise").then(res=>{
    console.log(res)
})
console.log("end") 

//这里打印顺序是 start-end-promise-setTimeout
  • 一般我们把回调队列中的任务称为宏任务,宏任务执行过程中可以临时新增一些新的额外需求,这些需求可以选择作为一个新的宏任务进入到回调队列中去排队,这时这些任务在回调队列的末尾排队去执行(setTimeOut和大部分异步调用API)就是这种宏任务方式,这些需求还可以选择微任务方式,微任务指的是直接在当前任务结束后立即执行,不需要在当前回调队列末尾去排队执行,Promise&MutationObserver&Node中的process.nextTick都是作为微任务去执行
  • 微任务的目的是为了提高整个应用的响应能力
  • 打个比方,去银行排队办事,你开始是想要存钱,存完钱你想要办张信用卡,这时候你可以直接和柜台人员说你想要办张信用卡,不需要再去队伍后面排队。这时排队的人都是想要存钱的,这些是宏任务,你想要办信用卡这个需求是这个队列中的微任务

七、Generator异步方案

  • 代码示例
function* foo() {
    console.log('start')
    try {
        const res= yield 'foo'
        console.log(res)
    } catch (error) {
        console.log(error)
    }

}

const generator = foo()
const result = generator.next()
console.log(result)
// const result2 = generator.next('bar')
// console.log(result2)
generator.throw(new Error("is error"))

//与promise结合使用
function ajax(url) {
    return new Promise((resolve, reject) => {
        let xhr = new XMLHttpRequest()
        xhr.open('GET', url)
        xhr.responseType = 'JSON'
        xhr.onload = () => {
            if (this.status === 200) {
                resolve(xhr.response)
            } else {
                reject(new Error(xhr.responseText))
            }
        }
        xhr.send()
    })
}

function * main() {
    try {
        const data = yield ajax('json1.json')
        console.log(data)
        const data2 = yield ajax('json2.json')
        console.log(data2)
    } catch (error) {
        console.log(error)
    }

}

function co(generator) {
    const g = generator()

    function handleResult(result) {
        if (result.done) return
        result.value.then(res => {
            handleResult(g.next(res))
        }, err => {
            g.throw(err)
        })
    }
    handleResult(g.next())
}
co(main)
  • es2017 出现的AsyncAwait语法糖可替代Generator
  • 代码示例
async function main() {
    try {
        const data = await ajax('json1.json')
        console.log(data)
        const data2 = await ajax('json2.json')
        console.log(data2)
    } catch (error) {
        console.log(error)
    }

}
const promise= main()
promise.then(res=>{
	console.log(res)
})

八、手写Promise类源码

const PEEDING = "peeding" //等待
const FULFILLED = "fulfilled" //成功
const REJECTED = "rejected" //失败
class Mypromise {
    constructor(executor) {
        try {
            executor(this.resolve, this.reject)
        } catch (error) {
            this.reject(error)
        }

    }
    //promise的状态
    status = PEEDING
    //成功值
    value = undefined
    //失败原因
    reason = undefined
    //成功回调
    successCallBack = []
    //失败回调
    failCallBack = []
    resolve = value => {
        //状态改为成功
        if (this.status !== PEEDING) return
        this.status = FULFILLED
        //保存成功值
        this.value = value
        // this.successCallBack && this.successCallBack(this.value)
        //数组依次执行里面的函数
        while (this.successCallBack.length) this.successCallBack.shift()()
    }
    reject = reason => {
        //状态改为失败
        if (this.status !== REJECTED) return
        this.status = REJECTED
        //保存失败原因
        this.reason = reason
        // this.failCallBack && this.failCallBack(this.reason)
        //数组依次执行里面的函数
        while (this.successCallBack.length) this.successCallBack.shift()()
    }
    then(successCallBack, failCallBack) {
        //使then可以传空参
        successCallBack = successCallBack ? successCallBack : value => value
        failCallBack = failCallBack ? failCallBack : reason => {
            throw reason
        }
        //链式调用
        let promise2 = new Mypromise((resolve, reject) => {
            if (this.status === FULFILLED) {

                //异步调用 得到promise2
                setTimeout(() => {
                    //添加异常报错情况
                    try {
                        let x = successCallBack(this.value)
                        //判断回调是否是Promise函数,不是话执行resolve,是的话根据自身promise返回的结果,来调用resolve或reject
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            } else if (this.status === REJECTED) {
                //异步调用 得到promise2
                setTimeout(() => {
                    try {
                        let x = failCallBack(this.reason)
                        //判断回调是否是Promise函数,不是话执行resolve,是的话根据自身promise返回的结果,来调用resolve或reject
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            } else {
                //异步调用 得到promise2
                setTimeout(() => {
                    //添加异常报错情况
                    try {
                        this.successCallBack.push(() => {
                            try {
                                let x = successCallBack(this.value)
                                //判断回调是否是Promise函数,不是话执行resolve,是的话根据自身promise返回的结果,来调用resolve或reject
                                resolvePromise(promise2, x, resolve, reject)
                            } catch (error) {
                                reject(error)
                            }
                        })
                        this.failCallBack.push(() => {
                            //添加异常报错情况
                            try {
                                let x = failCallBack(this.reason)
                                //判断回调是否是Promise函数,不是话执行resolve,是的话根据自身promise返回的结果,来调用resolve或reject
                                resolvePromise(promise2, x, resolve, reject)
                            } catch (error) {
                                reject(error)
                            }
                        })
                    } catch (error) {
                        reject(error)
                    }
                }, 0)

            }
        })
        return promise2
    }
    catch (failCallBack) {
        return this.then(undefined, failCallBack)
    } finally(callBack) {
        return this.then(value => {
            Mypromise.resolve(callBack()).then(() => value)
        }, reason => {
            Mypromise.resolve(callBack()).then(() => {
                throw reason
            })
        })
    }
    //all方法是个静态方法
    static all(array) {
        let arr2 = []
        let index = 0
        return new Mypromise((resolve, reject) => {
            function addData(index, value) {
                arr[index] = value
                index++
                if (index === array.length) {
                    resolve(arr2)
                }
            }
            array.forEach((item, index) => {
                if (item instanceof Mypromise) {
                    item.then(value => addData(index, value), err => reject(err))
                } else {
                    addData(item, index)
                }
            });
        })
    }
    //resolve静态方法
    static resolve(value) {
        if (value instanceof Mypromise) return value
        return new Mypromise(resolve => {
            resolve(value)
        })
    }
}

function resolvePromise(promise2, x, resolve, reject) {
    if (promise2 === x) {
        return reject(new Error('promise重复调用'))
    }
    if (x instanceof Mypromise) {
        x.then(resolve, reject)
    } else {
        resolve(x)
    }
}

总结

以上就是我part1模块的笔记,上面还有些task1未记录,后续有时间我会尽快补上
to be continued…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值