前端那些事系列之基础篇同异步编程(八)

Js执行环境

分析同步异步之前,先了解下线程与进程

  • 线程
    线程是CPU调度的最小单位,是建立在进程的基础上运行的单位,共享进程的内存空间。
  • 进程
    进程是CPU进行资源分配的基本单位

通俗点说,进程就像工厂,线程就像工人。一个进程的内存空间是同享的,每个线程都可以用这些共享内存。一个进程由一个或多个线程构成,线程是一个进程中不同的执行路线。多进程比如听歌的同时聊微信,多线程比如一个浏览器的页面。浏览器主要有以下几种线程

  • GUI渲染线程(解析html、css,渲染页面);
  • JS引擎线程(执行js代码,与渲染线程互斥);
  • HTTP请求线程(异步请求);
  • 事件触发(点击、悬浮);
  • 定时器触发

Js执行环境,众所周知Js是单线程执行的,也就是一个浏览器页面上只会有一个Js线程在执行脚本。也就是所有代码依次排列,在执行完a代码后再去执行b代码。基于这种单线程的工作流带来的的阻塞,就出现了异步编程。

异步编程

常见的异步函数——setTimeout、setInterval、ajax

异步编程方式发展

1)回调函数
function parent(callback){
	setTimeout(callback,1000)
}
function son(){
	console.log("回调成功")
}
parent(son())
  • 可读性强,实现简单。但会陷入回调地狱,不利于维护、各模块高度耦合
2)事件监听
const ev = document.getElementById('ev');
			const event = new CustomEvent('eventTest', {
				detail: {
					message: 'Hello World',
					time: new Date(),
				},
				bubbles: true,
				cancelable: true,
			});
			ev.addEventListener('eventTest', function(e) {
				console.log(e);
			}, );
			setTimeout(function() {
				ev.dispatchEvent(event); //给节点分派一个合成事件
			}, 1000);
  • 事件监听是以方法为中心,利用方法的挂载和监听实现点对点通信
3)发布 / 订阅
	class PubSub(){
		constructor(){
			this.handle={}
		}
		//订阅
		on(eventType,handle){
			if(!this.handles.hasOwnPropery(eventType)){
				this.handles[eventType]=[];
			}
			//传入的回调是函数就push到handles中
			if(typepf handle=='function'){
				this.handles[eventType].push({name:handle});
			}else{
				throw new Error("缺少回调函数")
			}
			//每次返回this可以链式调用
			return this;
		}
		//发布
		emit(eventType,...args){
			if(this.handles.hasOwnPropery(eventType)){
				this.handles[eventType].forEach((item,key,arr)=>{
					item.name.apply(null,args);
				})
			}else{
				throw new Error(`${eventType}事件未注册`);
			}
			return this;
		}
		//删除事件
		off(eventType,handle){
			if(!this.handles.hasOwnPropery(eventType)){
				throw new Error(`${eventType}事件未注册`)
			}else if(typepf handle!='function'){
				throw new Error("缺少回调函数")
			}else{
				this.handles[eventType].forEach((item,key,arr)=>{
					if(item.name==handle){
						arr.splice(key,1)
					}
				})
			}
			return this;
		}
	}

	let callback = function() {
		console.log('im callback');
	}
	let pubsub = new PubSub();
	pubsub.on('completed', (...args) => {
		console.log(args.join(','));
	})
	pubsub.on('completed', callback);
	pubsub.emit('completed', 'im anissa', '18 years old', 'like coding');
	pubsub.off('completed', callback);
	pubsub.emit('completed', 'im dylan', '24 years old', 'like fishing');
  • 以信号为中心,每当异步事件完成,就发出相应信号。所有订阅该信号的方法,都会收到通知并触发相应的处理。
4) promise
    foo.then(run());

    function foo() {
        return new Promise(resolve => {
            setTimeout(function() {
                resovle();
            }, 500)
        })
    }
  • 用链式调用解决了回调地狱的问题,但无法取消promise,错误只能由reject返回
5) async & await
    // 1. 返回一个promise
    // 2. 返回promise函数做await
    // 3. async await成对出现

    function test() {
        return new Promise((resolve, reject) => {
					setTimeout(() => {
						const name = 123;
						console.log('aaa')
						resolve(name);
					})
		})
    }
    async function func() {
        let val = await test();
        console.log(val);
    }
    func();
  • async/await 代码清晰,不用链式调用,await 将异步代码改造成同步代码,如果多个异步操作没有依赖性而使用 await 会导致性能上的降低。
6) 步进 iterator & generator

1、iterator

    // 步进器的实现
    function takeStep(arr) {
        let _index = 0;
        return {
            next: function() {
                return (
                    arr.length > _index
                        ? {
                            value: arr[_index++];
                        } : {
                            done: true
                        }
                )
            }
        }
    }

    let step = takeStep([1, 2])

    console.log(step.next())//value: 1
	console.log(step.next())//value: 2
	console.log(step.next()) //done: true

    // Es6 Symbol.iterator,同时辅助提供了for of
    const makeIterator = arr => {
        [Symbol.iterator]() {
            let _index = 0;
            return {
                next() {
                    return (
                        arr.length > _index
                            ? {
                                value: arr[_index++]
                            } : {
                                done: true
                            }
                    )
                },
                return() {
                    return {
                        done: true
                    }
                }
            }
        }
    }
    for (let value of makeIterator([1, 2, 3])) {
        console.log(value);
        if (value > 1) {
            break;
        }
    }

2、generator
Generator封装的异步函数可以暂停执行,暂停执行的地方用yield注明

function *createGenerator() {
 for(let i=0;i<20;i++) {
 yield i
 }
}

const generator = createGenerator()

console.log(generator.next())
console.log(generator.next())
//{ value: 0, done: false }
//{ value: 1, done: false }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值