zoukankan      html  css  js  c++  java
  • 抄作业

    了解 async/await 更优雅的异步处理的解决方案

    async/await 是基于 Promise 的进一步的一种优化,处理方式更加优雅。
    从字面意思上理解async/await: async 是异步的意识,await 有等待的意思,而两者的用法上也是如此。async用于声明一个异步的 function,而 await 用于等待一个异步方法执行完成。

    • async/await 是写异步代码的新方法,以前的方式又回调函数和Promise
    • async/await 是基于 Promise 实现的,不能用于普通的回调函数
    • async/await 与 Promise 一样, 是非阻塞的
    • async/await 是的异步代码看起来像同步代码,这是它的魔力所在
    // Promise 示例
    function getUserInfo() {
    	ajaxGetUserInf()
    	.then(data => {
    		return data
    	})
    }
    
    // async await 基础示例
    async function getUserInfo() {
    	let result = await ajaxGetUserInf();
    	console.log(result); // 异步请求的结果
    	return result
    }
    

    基本规则

    • async 表示这是一个 异步函数, await 只能用在这个函数里面
    • await 表示在这里等待 Promise,返回结果了,再继续执行
    • await 后面跟着的应该是一个 Promise 对象,当然,其他返回值也没有关系,只是会立即执行,不过这样就没有意义了。

    async 关键字

    // async 示例
    async function demoFn() {
    	return 100;
    }
    demoFn().then((res) => {
    	console.log(res); // 100
    })
    # async 函数会返回一个 promise 对象,如果函数中返回的是一个值,async直接会用Promise.resolve()包裹一下返回
    
    1. 表明程序里面可能有异步过程: 里面可以有await关键字;当然全部是同步代码也没有关系,但是这样async关键字就显得多余了;
    2. 非阻塞:async函数里面如果有异步过程会等待,但是async函数本身会马上返回,不会阻塞当前线程,可以简单认为,async函数工作在主线程,同步执行,不会阻塞界面渲染,async函数内部由await关键字修饰的异步过程,工作在相应的协程上,会阻塞等待异步任务的完成再返回。
    3. async函数返回类型为Promise对象:这是和普通函数本质上的不同,也是使用时重点注意的地方;
      • return new Promise() 这个符合async函数本意
      • return data 这个是同步函数的写法,这里是要特别注意的,这个时候,其实就相当于Promise.resolve(data) 还是一个Promise对象,但是在调用async函数的地方通过简单的调用是拿不到这个data的。因为返回值是一个Promise对象,所以需要使用 .then(data => {}) 的方式才可以拿到这个data
      • 如果没有返回值,相当于返回了 Promise.resolve(undefined)
    4. 无等待:联想到Promise的特点,在没有await的情况下执行async函数,会立即执行,返回一个Promise对象,并且绝对不会阻塞后面的语句,这和普通返回Promise对象的函数并无二致
    5. await不处理异步error: await是不管异步过程的reject(error)消息的,async函数返回的这个Promise对象的catch函数负责统一抓取内部所有异步过程的错误;async函数内部只要有一个异步发生过错误,整个执行过程就中断,这个返回的Promise对象的catch就能抓取到这个错误;
    6. async函数的执行: async函数执行和普通函数一样,参数个数随意,没有限制,也需要有async关键字;只是返回值是一个Promise对象,可以用then函数得到返回值,用catch抓取整个流程中发生的错误;

    await 关键字

    1. await只能在async函数内部使用: 不能放在普通函数里面,否则会报错
    2. await关键字后面跟Promise对象: 在Pending状态时,相应的协程会交出控制权,进入等待状态,这是协程的本质
    3. await是async await的意识: await的是resolve(data)的消息,并把数据data返回,比如下面代码中,当Promise对象由Pending变成Resolved的时候,变量a就等于data,然后再顺序执行下面的语句console.log(a),这真的是等待,真的是顺序执行,表现和同步代码几乎一模一样
    const a = await new Promise((resolve, reject) => {
    	return resolve(100)
    })
    console.log(a)
    
    1. **await后面也可以跟同步代码: ** 不过系统会提示将其转换成一个Promise对象,比如:
    const a = await 'hello world!'
    // 相当于
    const a = await Promise.resolve('hello world!')
    // 跟同步代码是一样的,还不如省事一点,直接去掉await关键字
    const a = 'hello world!'
    
    1. await对于失败消息的处理: await只关心异步过程成功的消息resolve(data),拿到相应的数据data,至于失败消息reject(error),不关心不处理;对于错误的处理由以下几种方法供选择:
      • 让await后面的Promise对象自己catch
      • 也可以让外面的async函数返回的Promise对象统一catch
      • 像同步代码一样,放在一个try..catch结构中
    async function mount() {
    	// 将异步和同步的代码放在一个try...catch中,异常都能抓到
    	try {
    		let array = null;
    		let data = await asyncFn();
    		if(array.length > 0) { // 抛出异常,在catch中打印异常
    			array.push(data)
    		}
    	} catch (error) {
    		console.log(JSON.stringify(error))
    	}
    }
    
    1. **await对于结果的处理: ** await是个运算符,用于组成表达式,await表达式的运算结果取决于它等的东西,如果它等到的不是一个Promise对象,那么await表达式的运算结果就是它等到的东西,如果是Promise对象,await就忙起来了,会阻塞后面的代码,等着Promise对象resolve,然后得到resolve的值,作为await表达式的运行结果;虽然是阻塞,但async函数调用并不会造成阻塞,它内部所有的阻塞都被封装在一个Promise对象中异步执行,这也正是await必须用在async函数中的原因

    用 async/await 替换 Promise 的不完美 ?

    1. 错误处理示例
    // 定义getJSON
    function getJSON() {
    	return Promise.resolve("ok")
    }
    
    # 在以下的Promise示例中,try/catch不能处理JSON。parse的错误,因为它在Promise中。我们需要使用.catch这样错误处理代码非常冗余。并且,在实际生产代码会更加复杂。  
    function makeRequest() {
    	try {
    		getJSON().then(result => {
    			// JSON.parse 会报错
    			const data = JSON.parse(result)
    			console.log(data)
    		})
    		// 取消注释,处理异步代码的错误
    		//.catch((err) => {
    		//	console.log(err)
    		//})
    	} catch (error) {
    		console.log(error)
    	}
    }
    
    # 使用 async/await 让 try/catch 可以同事处理同步和异步错误。能处理 JSON.parse 错误; async/await 最让人舒服的一点是代码看起来是同步的
    async function makeRequest() {
    	try {
    		const data = JSON.parse(await getJSON())
    		console.log(data)
    	} catch (error) {
    		console.log(error)
    	}
    }
    
    1. 条件语句示例
    # 根据返回数据决定是直接返回,还是继续获取更多的数据
    function makeRequest() {
    	return getJSON()
    		.then(data => {
    			if(data.need) {
    				return makeNeed(data)
    					.then(moreData => {
    						console.log(moreData)
    						return moreData
    					})
    			} else {
    				console.log(data)
    				return data
    			}
    		})
    }
    // 注意:这种多层嵌套并且 return语句很容易让人感到迷茫,而它们只是需要将最终结果传递到最外层的Promise  
    
    # 使用 async/await 这才是真正摆脱回调地狱的正确做法
    async function makeRequest() {
    	const data = await getJSON()
    	if (data.need) {
    		const moreData = await makeNeed(data)
    		console.log(moreData)
    		return moreData
    	} else {
    		console.log(data)
    		return data
    	}
    }
    
    1. 中间值(根据上一次的结果进行下一次调用) -链式调用
    # 场景分析: 调用 promise1,使用 promise1 返回的结果去调用 promise2,然后使用两者的结果去调用 promise3  
    function makeRequest() {
    	return promise1() 
    		.then(value1 => {
    			return promise2(value1)
    				.then(value2 => {
    					return promise3(value1, value2)
    				})
    		})
    }
    // 或者
    function makeRequest() {
    	return promise1()
    		.then(value1 => {
    			return Promise.all([value1, promise2(value1)])
    		})
    		.then(([value1, value2]) => {
    			return promise3(value1, value2)
    		})
    }
    
    // 无论怎么写都会觉得复杂,使用async/await,将复杂的场景简化
    async function makeRequest() {
    	const value1 = await promise1()
    	const value2 = await promise2(value1)
    	return promise3(value1, value2)
    }
    
  • 相关阅读:
    利用子查询解决复杂sql问题
    如何用临时表代替游标进行表记录的拷贝
    SQL新函数, 排名函数 ROW_NUMBER(), RANK(), DENSE_RANK()
    SQL SERVER2005 中的错误捕捉与处理
    用户自定义函数代替游标进行循环拼接
    使用游标进行循环数据插入
    Oracle中利用存储过程建表
    SQL SERVER中强制类型转换cast和convert的区别
    SQL如何修改被计算字段引用的字段类型
    1.官方网站:http://www.mplayerhq.hu/design7/dload.html
  • 原文地址:https://www.cnblogs.com/yuxi2018/p/14469588.html
Copyright © 2011-2022 走看看