3-4 JS异步

系列文章目录


好多知识点


一、单线程和异步

  • JS是单线程语言
  • 浏览器和 nodejs 已支持JS启动进程,如 Web Worker
  • JS 和 DOM 渲染共用同一个线程,因为 JS 可修改 DOM 结构
  • 遇到等待(网络请求,定时任务)不能卡住
  • 需要异步
  • 回调 callback 形式调用

异步和同步

  • 基于 JS 是单线程语言
  • 异步不会阻塞代码执行
  • 同步会阻塞代码执行

异步应用场景

  • 网络请求,如 ajax 图片加载
  • 定时任务,如 setTimeout

二、Promise

const url1 = '/data1.json';
const url2 = '/data2.json';
const url3 = '/data3.json';
getData(url1).then(data1 => {
    console.log(data1);
    return getData(url2);
}).then(data2 => {
    console.log(data2);
    return getData(url3);
}).then(data3 => {
    console.log(data3);
}).catch(err => console.log(err));

function getData(url) {
    return new Promise((resolve, reject) => {
            $.ajax({
                url,
                success(data) {
                    resolve(data)
                },
                error(err) {
                    reject(err)
                }
            })
        }

    )
}

三种状态

  1. pending resolved rejected
  2. pending->resolved或pending->rejected
  3. 变化不可逆

状态的表现和变化

  1. pending状态,不会触发then和catch
  2. resolved状态,会触发后续的then回调函数
  3. rejected状态,会触发后续的catch回调函数

then和catch对状态的影响

  1. then正常返回resolved,里面有报错则返回rejected
  2. catch正常返回resolved,里面有报错则返回rejected
// catch正常返回resolved情况
const p1 = Promise.reject('1').catch(err => {
    console.error(err)
})
console.log('p1',p1); // resolved 注意! 触发 then 回调
p1.then(() => {
    console.log(11)
})

const p2 = Promise.reject('2').catch(err => {
    throw new Error('catch err')
})
console.log('p2',p2); // rejected 触发 catch 回调
p2.then(() => {
    console.log(2)
}).catch(() => {
    console.log('打印')
})

手写Promise

  • 初始化 & 异步调用
  • then catch 链式调用
  • API .resolve .reject .all .race
const p1 = new MyPromise((resolve,reject) => {
    resolve(100);
    // serTimeout(() => {
    //     resolve(100)
    // },500)
})

const p11 = p1.then(data => {
    return data + 1;
})
const p12 = p11.then(data => {
    return data + 2;
})
const p13 = p12.catch(err => console.error(err));


const p2 = MyPromise.resolve(200);
const p3 = MyPromise.reject('err..');
const p4 = MyPromise.all([p1,p2]);
const p5 = MyPromise.race([p1,p2]);
class MyPromise {
    state = 'pending'; // 状态,'pending' 'fulfilled' 'rejected'
    value = undefined; // 成功后的值
    reason = undefined; // 失败后的原因

    resolveCallbacks = []; // pending 状态下,存储成功的回调
    rejectCallbacks = []; // pending 状态下,存储失败的回调

    constructor(fn) {
        const resolveHandler = (value) => {
            if(this.state === 'pending') {
                this.state = 'fulfilled';
                this.value = value;
                this.resolveCallbacks.forEach(fn => fn(this.value));
            }
        }
        
        const rejectHandler = (reason) => {
            if(this.state === 'pending') {
                this.state = 'rejected';
                this.reason = reason;
                this.rejectCallbacks.forEach(fn => fn(this.reason));
            }
        }

        try {
            fn(resolveHandler,rejectHandler)
        } catch (err) {
            rejectHandler(err)
        }
    }

    then (fn1,fn2) {
        // 当 pending 状态下, fn1 fn2会被存储到 callbacks 中
        fn1 = typeof fn1 === 'function' ? fn1 : (v) => v;
        fn2 = typeof fn2 === 'function' ? fn2 : (e) => e;
        
        if(this.state === 'pending') {
            const p1 = new MyPromise((resolve,reject) => {
                this.resolveCallbacks.push(() => {
                    try {
                        const newValue = fn1(this.value);
                        resolve(newValue);
                    } catch (err) {
                        reject(err)
                    }
                })

                this.rejectCallbacks.push(() => {
                    try {
                        const newReason = fn2(this.reason);
                        reject(newReason);
                    } catch (err) {
                        reject(err)
                    }
                })

            })
        }

        if(this.state === 'fulfilled') {
            const p1 = new MyPromise((resolve,reject) => {
                try {
                    const newValue = fn1(this.value);
                    resolve(newValue);
                } catch (err) {
                    reject(err);
                }
            })
            return p1;
        }

        if(this.state === 'rejected') {
            const p1 = new MyPromise((resolve,reject) => {
                try {
                    const newReason = fn2(this.reason);
                    reject(newReason);
                } catch (err) {
                    reject(err);
                }
            })
            return p1;
        }

    }

    // 就是then的一个语法糖,简单模式
    catch (fn) {
        return this.then(null,fn);
    }
}

MyPromise.resolve = function(value){
    return new MyPromise((resolve,reject) => resolve(value)); 
}

MyPromise.reject = function(reason){
    return new MyPromise((resolve,reject) => reject(reason)); 
}

// all传入promise数组,等待所有都fulfill之后,返回新promise,包含前面所有的结果

MyPromise.all = function (promiseList = []){
    const p1 = new MyPromise((resolve,reject) => {
        const result = []; // 存储promiseList所有信息
        const length = promiseList.length;
        let resolvedCount = 0;
    
        promiseList.forEach(p => {
            p.then(data => {
                result.push(data);
                // resolvedCount必须在then里面++
                // 不能用index
                resolvedCount++;
                if(resolvedCount === length){
                    // 已经遍历到最后一个promise
                    resolve(result);
                }
            }).catch(err => {
                reject(err);
            })
        })
    })
    return p1;
}

// race传入promise数字,只要有一个fulfill即可返回
MyPromise.race = function (promiseList = []){
    let resolved = false; // 标记
    const p1 = new MyPromise((resolve,reject) => {
        promiseList.forEach(p => {
            p.then(data => {
                if(!resolved) {
                    resolve(data)
                    resolved = true
                }
            }).catch((err) => {
                reject(err);
            })
        })
    })
    return p1;
}

三、event loop(事件循环/事件轮询)

  • JS是单线程运行的
  • 异步要基于回调来实现
  • event loop就是异步回调的实现原理
  • DOM事件也是使用回调,基于event loop

event loop过程

  • 同步代码,一行行放在call stack执行
  • 遇到异步,会先“记录”下,等待时机(定时、网络请求等)
  • 时机到了,就移动到callback queue
  • 如call stack为空(即同步代码执行完)event loop开始工作
  • 轮询查找callback queue,如有则移动到call stack执行
  • 然后继续轮询查找

四、async/await

  • 执行async函数,返回的是Promise对象
  • await相当于Promise的then
  • try...catch 可捕获异常,代替了Promise的catch

五、宏任务 macroTask 和 微任务 microTask

  • 宏任务:setTimeout,setInterval,Ajax,DOM事件
  • 微任务:Promise,async/await
  • 微任务执行时机比宏任务要早

event loop和DOM渲染

  • 每次Call Stack清空(即每次轮询结束),即同步任务执行完
  • 都是DOM重新渲染的机会,DOM结果如有改变则重新渲染
  • 然后再去触发下一次Event Loop

微任务和宏任务的区别

  • 宏任务:DOM渲染后触发,如setTimeout
  • 微任务:DOM渲染前触发,如Promise


总结

JS异步知识笔记

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值