• 微信小程序异步回调函数恶梦和解决办法


    问题

    先看看下面的代码,是读写取腾讯cos,因为几个对象间是有层次关系的,要读出一个取值然后作为另一个的条件,再去读,依次有几层关系。 按照官方文档,每一次都要放在回调函数里取结果,这样一层一层嵌套起来,可读性非常的差。 而且还有个致命的问题,这些回调函数都是异步处理的,当同一层并依序并列处理时,因为异步原因,没法按代码顺序来执行。

    1. cos.getBucket({
    2. Bucket: Bucket,
    3. Region: Region,
    4. Prefix: preday, // 这里传入列出的文件前缀
    5. },
    6. function (err, data) {
    7. if (data) {
    8. console.log(data)
    9. var count = 0
    10. var len = data.Contents.length
    11. console.log('len', len)
    12. for (var i = 0; i < len; i++) {
    13. var key2 = data.Contents[i].Key;
    14. cos.getObject({
    15. Bucket: Bucket,
    16. Region: Region,
    17. Key: key2,
    18. }, function (err, data) {
    19. count++;
    20. console.log(data)
    21. if (data) {
    22. var obj = JSON.parse(data.Body);
    23. recent = that.data.recent;
    24. var uname = obj.uname
    25. cos.getObject({
    26. Bucket: Bucket,
    27. Region: Region,
    28. Key: uname,
    29. }, function (err, data) {
    30. var obj = JSON.parse(data.Body);
    31. recent.push({
    32. uid: obj.uid,
    33. date_expire: obj.date_expire
    34. });
    35. })
    36. if (count >= len) {
    37. let s1 = new Set(recent);
    38. recent = Array.from(s1);
    39. console.log('array',recent)
    40. that.setData({
    41. recent: recent
    42. });
    43. console.log('recent', that.data.recent,that.data.list)
    44. }
    45. }
    46. });
    47. };
    48. };
    49. }
    50. );
    51. if (that.data.inputValue != '') {
    52. cos.getObject({
    53. Bucket: Bucket,
    54. Region: Region,
    55. Key: that.data.inputValue,
    56. }, function (err, data) {
    57. //console.log(err || data.Body);
    58. if (data) {
    59. var obj = JSON.parse(data.Body);
    60. var uname = obj.uname;
    61. var ary = uname.split('+');
    62. var remark = "";
    63. if (obj.remark) {
    64. remark = obj.remark
    65. };
    66. that.setData({
    67. corpid: ary[0],
    68. agentid: ary[1],
    69. uid: that.data.inputValue,
    70. userid: ary[2],
    71. remark: remark
    72. });
    73. cos.getObject({
    74. Bucket: Bucket,
    75. Region: Region,
    76. Key: uname,
    77. }, function (err, data) {
    78. if (data) {
    79. var obj = JSON.parse(data.Body);
    80. var date_expire = obj.date_expire;
    81. that.setData({
    82. date_expire: date_expire
    83. });
    84. }
    85. });
    86. cos.getBucket({
    87. Bucket: Bucket,
    88. Region: Region,
    89. Prefix: that.data.corpid,
    90. },
    91. function (err, data) {
    92. //console.log(err || data.Contents);
    93. if (data) {
    94. var list = []
    95. var count = 0
    96. var len = data.Contents.length
    97. for (var i = 0; i < len; i++) {
    98. var key2 = data.Contents[i].Key;
    99. cos.getObject({
    100. Bucket: Bucket,
    101. Region: Region,
    102. Key: key2,
    103. }, function (err, data) {
    104. count++;
    105. if (data) {
    106. var obj = JSON.parse(data.Body);
    107. list = that.data.list;
    108. var arr2 = key2.split('+')
    109. list.push({
    110. uid: obj.uid,
    111. date_expire: obj.date_expire
    112. });
    113. console.log(count, len)
    114. if (count >= len) {
    115. let s1 = new Set(list);
    116. list = Array.from(s1);
    117. that.setData({
    118. list: list
    119. })
    120. }
    121. }
    122. });
    123. };
    124. };
    125. }
    126. );
    127. }
    128. });
    129. };

    解决方法

    可以使用 Promise 来重新包装一下 COS 的接口如下:这样这些函数就变成同步的方式来调用了。

    1. //get bucket contents from prefix
    2. const getBucket = (Prefix) => {
    3. return new Promise((resolve, reject) => {
    4. cos.getBucket({
    5. Bucket: Bucket,
    6. Region: Region,
    7. Prefix: Prefix,
    8. }, function (err, data) {
    9. if (err) {
    10. //console.log('error', err)
    11. reject(err)
    12. } else {
    13. //console.log('success', data)
    14. resolve(data.Contents)
    15. }
    16. });
    17. });
    18. } //end getBucket
    19. //get object from key
    20. const getObject = (Key) => {
    21. return new Promise((resolve, reject) => {
    22. cos.getObject({
    23. Bucket: Bucket,
    24. Region: Region,
    25. Key: Key,
    26. }, function (err, data) {
    27. if (err) {
    28. //console.log('error2', err)
    29. reject(err)
    30. } else {
    31. //console.log('success2', data)
    32. resolve(data.Body)
    33. }
    34. });
    35. });
    36. } //end getObject
    37. //put object to key
    38. const putObject = (Key, Body) => {
    39. return new Promise((resolve, reject) => {
    40. cos.putObject({
    41. Bucket: Bucket,
    42. Region: Region,
    43. Key: Key,
    44. Body: Body
    45. }, function (err, data) {
    46. if (err) {
    47. reject(err)
    48. } else {
    49. //console.log(data)
    50. resolve(data)
    51. }
    52. });
    53. });
    54. } //end putObject

    调用的方式,有几点要求,首先调用的主函数定义前必须加上 async ,其次在调用上面包装好的函数时,要加 await.  如下:

    1. async Test(e){
    2. let rlt1 = await getObject('keyname')
    3. rlt1 = JSON.parse(rlt1)
    4. },

    扩展

    另外 微信小程序的库里本身带的很多函数就是支持这种调用的方式,以支持同步执行的方式如所示:

    1. // wx.showModal 官方文档中的调用方式,这种是异步的方式
    2. // 执行会发现 最后面的 log('3')会先输出,log('2')反而后输出。
    3. console.log('1')
    4. wx.showModal({
    5. title: '提示',
    6. content: '这是一个模态弹窗',
    7. success(res) {
    8. if (res.confirm) {
    9. console.log('用户点击确定')
    10. console.log('2')
    11. } else if (res.cancel) {
    12. console.log('用户点击取消')
    13. console.log('2')
    14. }
    15. }
    16. });
    17. console.log('3')
    18. //可以改成下面的调用方式,就能顺序执行了。
    19. let res = await wx.showModal({
    20. title: '提示',
    21. content: '这是一个模态弹窗'
    22. });
    23. if (res.confirm) {
    24. console.log('用户点击确定')
    25. console.log('2')
    26. } else if (res.cancel) {
    27. console.log('用户点击取消')
    28. console.log('2')
    29. }
    30. console.log('3')

  • 相关阅读:
    高性能mysql-查询性能优化
    DJYOS驱动开发系列一:基于DJYOS的UART驱动编写指导手册
    [答疑]提前进行跑batch或者某种方式汇总购买货物的历史记录
    JAVA -- 把一个大的sql文件分割成多个小sql文件
    JVM在线分析-监控工具(jps, jstat, jstatd)
    ImportError: Unknown magic number 3495 in test.pyc
    李沐动手学深度学习V2-自然语言推断与数据集SNLI和代码实现
    Linux系统中 uboot、内核与文件系统之间的关系
    day17-高速缓冲区的管理机制
    RKMEDIA--VENC/VDEC使用
  • 原文地址:https://blog.csdn.net/fangkailove/article/details/126110218