006JS同步异步

1. 同步异步简介

javascript是一门单线程的语言,不同于java这些语言可以通过开辟一个新的线程达到多线程“同时”工作,JS不能同时进行多个任务和流程。
同步和异步其本质都是在只有一条流水线,也就是单线程,它们之间的差异就是在这个流水线上各个流程的执行顺序不同。
同步任务,所有的任务在主线程上排队,只有前一个任务执行完毕,才能执行后一个任务;异步任务,要执行的任务并不进入主线程,而是进入任务队列,等待主线程任务执行完毕,任务队列通知主线程,请求执行任务,此时异步任务才会进入主线程执行。
所谓的异步就是一件事情并不是连续完成的,可以分为多个阶段完成的,任务执行一段后会暂停,转而执行其他任务,过段时间又会再次执行这个任务,然后循环这样的任务执行切换,直至任务完成。
相反,同步是指一个任务是无间断的连续的执行完成的,上一个任务不完成,下一个任务永远无法开始。

2. promise对象

2.1 基本介绍

因为异步任务是在同步任务执行之后才会执行,故我们很难预测到何时才会将异步任务执行完毕,为了找到异步任务执行完毕后进行操作,JavaScript起初引入了回调函数和事件的解决方案。但回调函数在进行多层嵌套后就会产生回调地域问题,给程序开发者和js解析器带来了很大的挑战。
ES6引入了Promise对象,并统一了用法。Promise对象简单的说,就是一个容器,对象中保存着某个未来才会结束的事件结果。Promise可以获取异步操作的消息,同时统一了API,保证了各种异步操作都可以使用同一种方法进行处理。
Promise对象的状态只受异步执行结果的影响,状态有pending(进行中)、fulfilled(已成功)、rejected(已失败),一旦对象的状态转为fulfilled或rejected,就意味着状态不能在改变。promise可以将异步操作以同步操作的方式表达出来,避免了层层嵌套的回调函数。

2.2 基本用法

ES6规定,Promise对象是一个构造函数,用来生成Promise实例。

// resolve和reject两个函数由JS引擎提供,不用自己部署
let promise = new Promise((resolve,reject) => {
   
	if(){
   
		resolve('successed!');
	}else{
   
		reject('error');
	}
});
// promise实例完成状态转换后,使用then方法指定resolve和reject状态的回调函数
promise.then((value) => {
   
		/*scuccess*/},(error) => {
   
		/*error*/
	});
// catch是then方法的别名,用于指定发生错误时的回调函数,reject能抛出错误,若resolve后再抛出错误时无效的
// 建议使用promise时使用下面的书写方式
promise.then(value => {
   })
.catch(error => {
   });

// Promise.all();方法用于将多个Promise实例包装成一个新的Promise实例,
// 只有所有的实例均成功,新实例才会成功,若不是promise实例调用resolve函数
let p = Promise.all([p1,p2]);

// Promise.race()方法同样是将多个promise实例包装成一个新的promise实例
// 多个实例总只要有一个实例率先改变的状态就代表了新实例的状态,若不是promise实例调用resolve函数
Promise.race([p1.p2]);

// Promise.resolve()方法将现有对象转成Promise对象 
Promise.resolve('foo') /*等价于*/new Promise(resolve => resolve('foo'););
// Promise.reject()方法与Promise.resolve方法类似,只不多返回的实例状态是rejected

// done()方法用于最后做到处理未能捕捉到的错误,总是处于回调链的尾端,保证万无一失
promise.then()
.catch()
.done();

// finally()方法无论实例最终装填如何均会执行,
// 与donn方法的不同之处是接收一个普通的回调函数作为参数,该函数不管怎样必须执行
promise.then()
.catch()
.done()
.finally();

// Promise.try()可以不用区分同步函数或异步函数,它会使同步函数同步执行,异步函数异步执行,与async相同
Promise.try()
.then()
.catch()
.done()
.finally();

3.Generator函数

3.1 基本介绍

Generator函数是ES6提供了一种异步编程解决方案,语法行为与传统函数完全不同。Generator函数可以理解成是一个状态机,内部封住了多个状态,执行Generator函数会返回一个遍历器对象,而非像普通函数那样返回一个函数执行结果,通过遍历遍历器对象获取函数内部的每一个状态。
Generator函数在形式上与普通函数并没有太大的区别:function命令与函数名之间有一个星号;函数体内部使用yield表达式定义不同的内部状态。
Generator函数调用之后并不立即执行,返回的也不是一个执行结果,而是一个指向内部状态的指针对象,只有在调用next方法才会将指针移向下一个状态,并执行两个状态之间的代码。在指针执行的过程中会产生一个状态结果对象,即{value:当前yield表达式结果,done:false/true},其中value的结果遵循若next函数传入参数,next没传入便执行yield后边的表达式结果,done若遇到最后一个yield或return便会转为true,表示结束当前Generator函数。

function* func (){
   
		yield 状态1;
		yidld 状态2;
		return;
	}
let hw = func();

3.2 基本使用

Generator函数调用之后并不立即执行,返回的也不是一个执行结果,而是一个指向内部状态的指针对象,只有在调用next方法才会将指针移向下一个状态,并执行两个状态之间的代码。在指针移动的过程中会产生一个状态结果对象,即{value:当前yield表达式结果,done:false/true},其中value的结果遵循若next函数传入参数,next没传入便执行yield后边的表达式结果,done若遇到最后一个yield或return便会转为true,表示结束当前Generator函数。
yield表达式若用在表达式中,必须放在小括号内:console.log('yield' + yield 123);
yield表达式本身没有返回值,或者说返回值是undefined,next方法可以带一个参数充当yield表达式的返回值。next方法的参数表示的是上一次yield表达式的返回值,故在第一次执行next方法时传入的参数是无效的,且V8引擎也会自动忽略掉第一次使用next的参数,所以第一次使用next方法不用携带参数,若真的想在第一次使用next方法就传入参数,就在Generator函数外边再包一层。

function* func (){
   
		yield 状态1;
		yidld 状态2;
		return;
	}
let hw = func();

// 遍历器对象遍历方式1:next
hw.next();
hw.next();
hw.next();
// 遍历器对象遍历方式2:for循环,done为true时就会停止,且不包含返回对象
for(let f of hw){
   
	console.log(f); // 注意不能用forEach方式循环,forEach函数参数为普通对象
}

// 扩展运算符,解构赋值,Array.from方法等内部都是遍历器接口,均可将Generator函数返回的Iterator对象当做参数
[...hw];
Array.from(hw);
let [x,y,z] = hw;


原生的JavaScript对象并没有遍历接口,故无法使用for…of循环,但通过Generator函数为它加上接口就可以使用了。

// 方式1:
function* objectEntries(obj){
   
	let propKeys = Reflect.ownKeys(obj);
	for(let propKey of propKeys){
   
		yield [propKey,obj[propKey]];
	}
}

for(let [key,value] of objectEntries({
   k:val1,k2:val2})){
   
	console.log(key,value);
}

// 方式2
function
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值