Generator与 async

Generator和async是ES6提供的异步编程解决方案。Generator通过yield关键字暂停执行,而async函数则使用await关键字等待Promise的结果。Generator需通过next方法手动执行,async函数会自动执行并返回Promise。两者的使用场景和返回值有所不同,但都为解决异步问题提供了新的思路。
摘要由CSDN通过智能技术生成

Generator(状态机,封装了多个内部状态.通过next方法获取)

  • 也是es6提供的一种异步编程解决方案.内部因为yield的存在 , 所以可以封装多个内部的状态 .
  • 其具有惰性求值的特点. 函数调用时并不会执行. 而是调用next方法去执行内部的状态.
  • 相似于return , 但又不同于return语句:
    • 都返回紧跟在语句后的表达式的值.
    • return只能执行一次. 且不具备记忆的功能.而yield可以执行多次,每次next方法,都是从上次yield的位置执行.
  • yield语句只能用在 Generator函数中 . 而Generator函数中可以没有yield语句 . 没有该语句, 就是个暂缓执行的函数 . 通过next方法执行.
  • 返回的是一个遍历器对象. 因此可以赋值给对象的[Symbol.iterator]属性.
		function* f() {
	            yield 1
	            yield 2
	            return 3
	        }
	    let exec = f()
	    for (let value of exec) {
	        console.log(value)
	    }
	    console.log(exec.next())
        /*
        	1
        	2
        	{value:undefined,done:true}
        	用for...of遍历,{value:3,done:true}该状态已经遍历到了,但是输出的是done:false的值. 
        */
        
       	function* f() {
            console.log('暂缓')
        }
        const exec = f();
        console.log(exec)
        exec.next()
        /*
        	一个含GeneratorState: closed的对象.
        	暂缓
        */  
		
		function* gen(){
		  // some code
		}
		
		var g = gen();
		
		g[Symbol.iterator]() === g
		
		// true . 这个有意思 . 		  
  • next方法的参数
    • yield 表达式本身没有返回值 . 返回值总是undefined .
    • next()方法可以带一个参数. 该参数就是上一个yield表达式的返回值
    • 并且当yield前还有表达式 . yield 语句必须用括号括起来.
	  function* f() {
            let x = 2 + (yield 2)
            return x
        }
        let exec = f()
        console.log(exec.next())
        console.log(exec.next(4))
		
		/*
			{value:2,done:false}
			{value:6,done:true}
		*/
  • next() . throw() . return()
    • 本质上是同一件事,可以放在一起理解。它们的作用都是让 Generator 函数恢复执行,并且使用不同的语句替换yield表达式
    • next()是将yield表达式替换成一个值
    • throw()是将yield表达式替换成一个throw语句.
    • return()是将yield表达式替换成一个return语句
	const g = function* (x, y) {
	  let result = yield x + y;
	  return result;
	};
	
	const gen = g(1, 2);
	gen.next(); // Object {value: 3, done: false}
	
	gen.next(1); // Object {value: 1, done: true}
	// 相当于将 let result = yield x + y
	// 替换成 let result = 1;

	gen.throw(new Error('出错了')); // Uncaught Error: 出错了
	// 相当于将 let result = yield x + y
	// 替换成 let result = throw(new Error('出错了'));
	
	gen.return(2); // Object {value: 2, done: true}
// 相当于将 let result = yield x + y
// 替换成 let result = return 2;
  • yield* 表达式 . 用来在一个 Generator 函数里面执行另一个 Generator 函数.
	var arr = [1, [[2, 3], 4], [5, 6]];

	var flat = function* (a) {
	  var length = a.length;
	  for (var i = 0; i < length; i++) {
	    var item = a[i];
	    if (typeof item !== 'number') {
	      yield* flat(item);
	    } else {
	      yield item;
	    }
	  }
	};
	
	for (var f of flat(arr)) {
	  console.log(f);
	}
	/* 1, 2, 3, 4, 5, 6
		又多了一种扁平化的方法. 真神奇了...
	*/

async

  • 是Generator 函数的语法糖. 而Generator 函数有一个很有意思的概念: 将函数的执行权交出去.再次执行时, 从暂停处开始.
  • async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已.
  • 不同:
    • async函数自带执行器. 不用通过next方法去调用执行.
    • 更好的语义. async是异步的意思. await是需要等待的意思.
    • yield后只能是Thunk函数 (这个还是第一次见)或 Promise对象 . await 后可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象
    • 其返回值是Promise对象. 可以调用then方法处理.而Generator函数返回值是个iterator对象.
	function* f() {
            yield Promise.resolve('成功了')
        }
        const exec = f();
        console.log(exec.next())
        async function f1() {
            let p = await Promise.resolve('成功了')
            console.log(p)
        }
        const p = f1()
        console.log(p)

在这里插入图片描述

  • 这里比较关注的是f1函数中的p 与 f1函数外的p的输出顺序 (因为涉及到了事件循环机制). 是函数外的p先输出 .

  • async函数返回一个promise对象. 且如果内部不抛出错误的情况下 , 其状态为成功 .
  • 函数内部的return值, 会成为then方法回调时候的参数.
  • 该函数返回的Promise对象. 必须等到await命令后的异步操作完成后 , 才会确定状态, 然后执行then方法指定的回调函数.
  • 若遇到return语句. 则会提前结束函数.状态为成功 ; 而抛出错误 ,状态为失败.
  • 对于抛出错误的情况. 若想继续执行, 则要把该命令放在try...catch...
  async function f() {
            let data = await 1
            console.log(data)
            return 'then的参数'
        }
        let p = f()
        p.then(res => console.log(res))
	/*
		1 
		then的参数
	*/
	
	async function f() {
	  throw new Error('出错了');
	}
	
	f().then(
	  value => console.log('resolve', value),
	  err => console.log('reject', err)
	)
	//reject Error: 出错了

  • 自带执行器 . 所以比较好奇的是它是通过什么去判断暂停或继续执行.
    • 因为上述说await是替代了yield . 而yield通过next方法去暂停处继续执行.
    • 因此这里分await后是promise对象 . 不是promise对象 .
      • 不是promise对象的话 . 直接返回语句后的结果
      • 是promise对象的话 . 则放回该对象的结果 . 也就是then 方法所需要的参数值
    • 最后一个例子. 输出p的语句 , return语句 , 函数外的then方法都没有结果的输出.

因为await会等其后的异步操作有结果后 , 再进行. 但例子中并没有确定promise对象的状态. 所以其后的代码, 包括then方法都没有执行 .

	  async function f() {
            console.log('async start')
            let p = await '111'
            console.log('p的值: ', p)
            return 'async end'
        }
        f().then(res => console.log(res))
	
		/*
			async start
			p的值:	111
			async end 
		*/

		async function f() {
            console.log('async start')
            try {
                let p = await Promise.reject('111')
                console.log('p的值: ', p)
            } catch (err) {
                console.log('捕获: ', err)
            }
            return 'async end'
        }
        f().then(res => console.log(res))
        
        /*
			async start 
			捕获:	111
			async end 
		*/

		 async function f() {
            console.log('async start')
            let p = await new Promise((resolve) => {
                console.log('111')
            })
            console.log('p的值:', p)
            return 'async end'
        }
        f().then(res => console.log(res))
        
        /*
			async start
			111
		*/

阮一峰es6入门

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值