综述
网上有很多关于 Promise
,async await
的使用教程了,在这里不赘述,介绍两个相关教程
async_await详解(彻底摆脱回调地狱)
阮一峰的 es6教程之 Promise
这里做的笔记分享,主要是针对第一个视频的。旨在记录如何在一个async
函数中实现同步和异步
实例
调用的代码模板(部分为伪代码)
templateFunction = async (param_1, param_2) => {
try {
let host = await getHostAsyncFunc();
let session = await getSessionAsyncFunc(host);
let requestURL = await gererateReqAsyncFunc(session,host);
} catch ( error => {
console.log(error);
});
}
//...
function getHostAsyncFunc() {
return new Promise ((resolve,reject) => {
if (goRight) {
resolve(true);
} else {
reject('error running');
}
});
}
这里来做一个简单的说明。
因为网络请求是一个天生的异步调用情况,因此以此为例。
通常我们做一个网络请求的时候,会先去获取多个相应的参数。
而在React Native
开发中,异步调用(不单单包括网络请求),获取参数是非常常见的情况。例如,原生开放接口供 RN
调用,返回的结果通常就是异步返回的。
因为 Promise
对象通过then
和catch
捕获返回的结果
Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数
Promise 实例具有then方法,也就是说,then方法是定义在原型对象Promise.prototype上的。它的作用是为 Promise 实例添加状态改变时的回调函数。then方法的第一个参数是resolved状态的回调函数
当异步返回需要等待上一步执行(实质上是一种同步需求)时,就产生了嵌套
。
嵌套,其实我们很熟悉了,包括OC
中用block
或GCD
做嵌套,JS
中使用then
,
最后代码都会写成形如下面这样的 N 级嵌套,俗称造火箭
then (
then (
then (
then ()
)
)
)
Async await 的使用
视频里说的很详细了,这里就不做赘述。简而言之,从上面那段实例代码中可以看出:
- await 后头可以跟一个
Promise
对象,用来接收他的resolve
(或者可以看做then
)的执行结果await 是一个有兼容性的语法,后头并不仅仅跟
Promise
对象,普通的函数调用结果也可以接收 - catch 接收的是所有 Promise 中产生的错误。通俗的理解,只要
await
后头执行的东西产生了错误,那么就会立即停下,进入catch
.这也带来了一个问题,也许我
await
了N 个异步函数,但是catch
的时候我不知道究竟是哪个错误执行到了。这就要求我们在各个异步函数中将reject
的内容要标注好,便于调试
同步和异步
啰嗦了半天,终于到了最需要注意的地方了。
需要声明的是:我们这里说的同步和异步,严格意义上说,是这个
async
函数内部的执行是同步的还是异步的。因为从外来看,整个async
函数一定是一个异步函数,毋庸置疑。
同步
同步就是上面说的那种情况了,我的后一个函数需要依赖前一个函数的执行结果,那么就需要等待他的返回。
异步
举一个开发中的实例来说明:
- 现在我有
N
张图,后台返回给我的是一个可以查询到这些图片 URL 地址的 key_id 数组:
[image_key1,image_key2,image_key3,image_key4]
- 有一个异步函数
getImageURL(imageKeysArray:Array)
, 可以通过上面的key_id
返回对应的url
数组, - 我等待拿到所有的 URL 组成的数组
[image_url1,image_url2,image_url3,image_url4]
后,返回给下一个异步函数showImage(urlArray:Array)
,异步加载这些图片
这里就涉及到了这个问题:
key => url 的过程,是异步的,但是我必须知道你所有的 key 都转化完成的时机,然后才能返回生成的 url 数组。这时候又是同步的
代码说明:
showImages = async (imageKeyID_array:Array, sucCallback:Function, failCallback:Function) => {
try {
let promiseArray = []
for (let keyID of imageKeyID_array) {
promiseArray.push(getImgURLAsyncFunc(keyID));
}
let urls = await Promise.all(promiseArray);
let imageComponentsArray = [];
urls.map((url,index) => {
imageComponentsArray.push(<Image source={uri:url} key={index}/>)
})
sucCallback(imageComponentsArray);
} catch (e){
if (failCallback != null)
failCallback(e);
}
}
function getImgURLAsyncFunc() {
return new Promise ((resolve,reject) => {
if (goRight) {
resolve(true);
} else {
reject('error running');
}
});
}
这里,将所有获取图片 URL 的函数返回的Promise 对象放在一个数组里,让他一次去执行。
let urls = await Promise.all(promiseArray);
这句会等待所有的异步操作都执行完毕.
最后,试想下,如果用gcd
来做,是不是要用到dispatch_barrier
?
2018.4.4 补充
使用 Promise
进行异步和异步搭配使用
参考资料
当你创建一个 Promise 实例的时候,任务就已经开始执行了,比如下面代码:
function fn(resolve, reject) {
console.log('hello');
// ...
}
console.log('before');
const promiseGetter = () => new Promise(fn); // fn 没有立即执行
console.log('after');
把 const promiseGetter = () => new Promise(fn)
叫做 PromiseGetter
你会在控制台里依次看到 before、hello 和 after。这是因为你传递给 Promise 的函数 fn 是被立即执行的
我们现在需要执行的需求是这样的:
这里先声明下iOS
系统下上传图片的限制:
假设并发上传9张大图,单次上传的数据量有限制,如果9张图同时并发,就会造成后面还没开始传的图片超时。
这里我如果使用Promise.all()
来做上传,在 ios 系统下是会有问题的。
所以,我们实际的需求为:
每次传3张图,这次上传的3张是并发的。等到3张传完后,再继续3张,重复前面的步骤。
示意图
用同步异步的来解释,先做3张异步,都传完的时间点,是同步的。抓包看到的效果如下:
// 这里简化下代码,也就是通过一个循环,做了9次操作,把9个 promiseGetter 函数放进这个数组
let dentryID_array = [];//用来存储图片识别码的数组
uploadImgPromiseGetter.push(()=>{return _uploadImg(uploadImgParams)}
if (Platform.OS === 'ios') {
// ios 需要作一个判断,根据机型,一般单次取3个图片作异步上传,完成后再取3张
for (let index = 0; index < 3; index ++) {
let tempArray = uploadImgPromiseGetter.splice(0,3);//如果 数组是[],那么做了 splice 还是返回[]
let uploadImgPromises = [];
tempArray.map(promiseGetter => {
if (promiseGetter) {
uploadImgPromises.push(promiseGetter());
}
});
if (uploadImgPromises.length > 0) { // 判断这个数组中是否存了 promiseGetter 函数
let dentryID = await Promise.all(uploadImgPromises);
dentryID_array.push(...dentryID);
}
}
} else {
let uploadImgPromises = [];
uploadImgPromiseGetter.map(promiseGetter => {
if (promiseGetter) {
uploadImgPromises.push(promiseGetter());
}
});
let dentryID = await Promise.all(uploadImgPromises);
dentryID_array.push(...dentryID);
}
网友评论