受欢迎的博客标签

微信小程序Promise、async、await解决异步请求问题系列之开发工具设置

Published

正确操作:

1.不勾选es6转es5的选项

2.勾选“增强编译”的选项

3.开发工具版本号:微信开发工具版本>=1.02.1904282

4.用promise对函数进行封装

总结1:关于启用async await语法

1.async+await是 ES7 的一个特性。在最新的ES7(ES2017)中提出的前端异步特性:async、await。

2.微信开发工具目前仅具有编译ES6 的能力。

3.为了支持ES7 的async+await,微信开发工具通过新增“增强编译”的选项来实现对ES7 的async+await的支持。

4.所以只要保证勾选“增强编译”的选项,即可用async+await来开发小程序。

5.微信开发工具1.02.1904282 以及之后版本,才有增强编译的选项。所以必须下载至少1.02.1904282 之后的版本。

 

增强编译
在 1.02.1904282 以及之后版本的开发工具中,增加了增强编译的选项来增强ES6转ES5的能力,启用后会使用新的编译逻辑以及提供额外的选项供开发者使用。

启用增强编译后的支持对Async/Await 的编译,未启用则不支持对对Async/Await 的编译

官方文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/codecompile.html

 

test

下面的代码,只要勾选了“增强编译”的选项,无论ES6转ES5勾选或者不勾选,运行都是正常的。

//app.js

  async fun() {
    setTimeout(function () {
    }, 3000)
    console.log("test1")
  },

  async fun2() {
    console.log("test2")
  },
onLaunch: async function () { //当小程序初始化完成时,会触发onLaunch(全局只触发一次)

    await this.fun()
    await this.fun2()

    console.log("fun()已执行完成!")

output:

test1
app.js? [sm]:42 test2
app.js? [sm]:50 fun()已执行完成!

总结2:关于不勾选es6转es5的选项

使用案例:https://github.com/pampa0629/EntryOutdoor

 

在上面的基础上,微信小程序客户端如果使用了用promise进行封装的函数, async + await,会报这个错误
原因:async+await是 ES7 的一个特性。在最新的ES7(ES2017)中提出的前端异步特性:async、await。如果微信小程序IDE里开启了ES6转ES5,则会报这个错误。

ReferenceError: regeneratorRuntime is not defined

解决方案:
第一种方法:微信小程序IDE里,详情->本地设置 里,不勾选es6转es5,开启,【增强编译】

开发工具勾选ES6转ES5的情况下使用ES7的async,await

解决方案

引入 regenerator runtime.js


demo:https://github.com/TencentCloudBase/tcb-demo-basic/tree/master/client/libs

以操作适用开发工具勾选ES6转ES5的情况

step 1:先导入 regenerator-runtime

regenerator,使用 regenerator,这是 facebook 下的一个工具,用于编译 ES6 的 generator 函数。

在需要使用async/await特性的代码文件中,引入regenerator库
js

// miniprogram/pages/adminEmployee/login/index.js

//step 1: use runtime.js
const regeneratorRuntime = require('../../../lib/regenerator-runtime/runtime')

or

import regeneratorRuntime from '../../libs/regenerator-runtime'

download url for regenerator-runtime.js:

https://github.com/facebook/regenerator/tree/master/packages/regenerator-runtime

 

总结3:关于对函数用promise进行封装以便使用async await语法

在这块里头,有三个分支可以选择,开发者可以选择其中的一种:

分支1:对函数用promise进行封装以便使用-直接使用promise进行封装

1.对云函数的封装及其调用方法

page.js

//从数据库中获取管理后台密码 同步方式
  async getAdminPassword() {

    const db = wx.cloud.database();
    await db.collection(configCollection.Setting).where({
      Name: "AdminPassword"
    }).get({
      success: res => {
        this.setData({
          AdminPassword: res.data[0], //返回的是一个数组,取第一个,

        })
      },
      fail: err => {
        console.log(err)
      }
    })
  },

call

/**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {

    this.init();
  },
async init() {
    try {
      await this.getAdminPassword();
      console.log('run await getAdminPassword() ok')
    } catch (error) {
      console.log('run await getAdminPassword() error')
    }
  },
2.1.对  wx.request函数的封装及其调用方法

函数加上async关键字,在原wx.request函数基础上用promise将其包裹起来,然后添上resolve(res);reject(err);即完成了封装

//获取1个员工对象
  getEmployeesByOpenIdPromiseFromApi2: async function (openid) {
    return new Promise((resolve, reject) => {

      wx.request({
        url: 'https://api.demo.com/api/Employee/EmployeesByOpenid/' + openid, //仅为示例,并非真实的接口地址
        data: {

        },
        header: {
          'content-type': 'application/json' // 默认值
        },
        success(res) {
          console.log(res.data)
        

          if (res.data.length > 0 && res.statusCode == 200) {
            getApp().globalData.Employee = res.data[0];
         
          }
          else {
            console.log("app.js获取的员工信息失败:res.statusCode==" + res.statusCode)
          }

          resolve(res);

        },
        fail: function (res) {
          console.log("失败" + res);
          reject(err);
        }

      })
    });


  },

call

page.js的原有函数,我们不动它,只将onload加上一个async关键字

old

onLoad:  function (options)

new

onLoad: async function (options)

然后用await关键字进行调用

 onLoad: async function (options) {

   
    //首先查找用户是否存在
    var openid = getApp().globalData.openid;

    //用async/await 函数调用
    try {
      let res = await app.getEmployeesByOpenIdPromiseFromApi2(openid);
      console.log('pages/adminEmployee/index/index->Onload() Info: call app.getEmployeesByOpenIdPromiseFromApi2(openid) ok res=' ,res)
    } catch (error) {
      console.log('pages/adminEmployee/index/index->Onload() Info:app.getEmployeesByOpenIdPromiseFromApi2(openid) err,eror=' ,error)
    }

  


  },

 

 if (res.data.length > 0 && res.statusCode == 200) {
            getApp().globalData.Employee = res.data[0];
            // this.app.globalData.Employee = res.data[0];
            console.log("app.js获取的员工信息OK:getApp().globalData.Employee=" , getApp().globalData.Employee)
          }
          else {
            console.log("app.js获取的员工信息失败:res.statusCode==" + res.statusCode)
          }

 

分支2:对函数用promise进行封装以便使用-使用wxPromisify.js库进行封装

案例:https://github.com/bandazhenxin/htMeow

utils/webServer/asyn/wxAsyn.js
/**
 * 同步化封装原厂开放接口
 */
const wxPromisify = require('wxPromisify.js');

//api list
const getLocation = wxPromisify(wx.getLocation); //获取经纬度
const showModal = wxPromisify(wx.showModal);     //弹窗
const getSetting = wxPromisify(wx.getSetting);   //判断权限
const getUserInfo = wxPromisify(wx.getUserInfo); //获取用户信息
const login = wxPromisify(wx.login);             //登录
const openSetting = wxPromisify(wx.openSetting); //弹出授权

module.exports = {
  getLocation: getLocation,
  showModal: showModal,
  getSetting: getSetting,
  getUserInfo: getUserInfo,
  login: login,
  openSetting: openSetting
}

分支3:TypeScript 2.1

1.小程序客户端中支持使用async/await有四种模式

目前,小程序中支持使用async/await有四种模式:

1.1纯原生es7的async/await模式

1.2勾选es6转es5,勾选增强编译;一般是因为调用了第三方的es5插件,通过增强编译支持async/await。

1.3勾选es6转es5,不勾选增强编译;手工引入runtime.js支持async/await

1.4 微信小程序]使用TypeScript2.1 async/await 

2.小程序客户端中支持使用async/await四种模式详细情况说明

1、不勾选es6转es5,不勾选增强编译;该模式是纯原生es7的async/await,需要基础库高版本。

从线上运行的结果来看,不支持原生async/await的手机型号已经没有了(或者少到我们发现不了了),所以已经没理由再用es5下的async/await了,放弃它。

小程序(包括工具)已经原生支持async/await了,直接用就行了。(别勾es6转es5

案例项目:

https://github.com/pampa0629/EntryOutdoor/blob/master/project.config.json

{
	"description": "项目配置文件",
	"packOptions": {
		"ignore": []
	},
	"setting": {
		"urlCheck": true,
		"es6": false,
		"enhance": true,
		"postcss": true,
        ...
       },
      "libVersion": "2.8.3",

 

2、勾选es6转es5,勾选增强编译;一般是因为调用了第三方的es5插件,通过增强编译支持async/await。

3、勾选es6转es5,不勾选增强编译;手工引入runtime.js支持async/await。

线上版本报错:

在使用async await时回报
VM4677:1 thirdScriptError 
 sdk uncaught third Error 
 Function(...) is not a function 
 TypeError: Function(...) is not a function
Page is not constructed because it is not found.

 使用async await出现regeneratorRuntime is not defined错误

原因是:

runtime.js 更新了,改东西!!!

到此下载可以使用的版本

https://github.com/sxshuang/19613regenerator-runtime

https://blog.csdn.net/sxs7970/article/details/91880231

 

TypeScript2.1 微信小程序]使用 async/await 

https://www.cnblogs.com/emeryao/p/6208429.html

 

TypeScript 支持
如果项目需要使用 TypeScript 语言开发,开发者工具在创建项目选择快速启动模板时,提供了使用 TypeScript 语言的 QuickStart 项目,可以选择创建此项目并进行后续开发。
要构建并使用 TypeScript 项目,可能需要安装 npm。通过配置编译前的预置命令,可以实现在编译前运行 tsc 以将其编译到 js 文件。
如需配置 TypeScript 编译选项,请参考 tsconfig.json 的配置。
注:小程序仅支持运行 JS 文件,因此所有的 TS 文件都默认不会被打包上传。
Git 状态展示

come from office doc:https://developers.weixin.qq.com/miniprogram/dev/devtools/edit.html#TypeScript-支持

据最近更新情况,原生的函数已经大部分同时原生支持同步化了,不需要本方案转化了,直接加上await即可;比如wx.chooseImage、wx.showModal

 

ES6 转 ES5
在 0.10.101000 以及之后版本的开发工具中,会默认使用 babel 将开发者 ES6 语法代码转换为三端都能很好支持的 ES5 的代码,帮助开发者解决环境不同所带来的开发问题。

需要注意的是:

为了提高代码质量,在开启 ES6 转换功能的情况下,默认启用 javasctipt 严格模式,请参考 "use strict"
增强编译
在 1.02.1904282 以及之后版本的开发工具中,增加了增强编译的选项来增强ES6转ES5的能力,启用后会使用新的编译逻辑以及提供额外的选项供开发者使用。

https://developers.weixin.qq.com/miniprogram/dev/devtools/codecompile.html

 

https://developers.weixin.qq.com/community/develop/article/doc/0008ee7efe4cf0a25799a071c5b013

我们做小程序开发时,要使得自己代码变得整洁,异步操作时避免回调地狱.应该使用

es6的promise.

es7的async,await .


云函数:promise在小程序和云开发的云函数里都可以使用. async和await只能在云开发的云函数里使用.

小程序客户端使用async,await过程

step 1:勾上增强编译

 

step 2:引入 regenerator

https://codeload.github.com/facebook/regenerator/zip/master

https://github.com/facebook/regenerator/tree/master/packages

├─lib
│  ├─regenerator-runtime    runtime.js
│  └─wxParse   
├─pages
│  ├─auth

在根目录下创建 lib 文件夹,并将 https://github.com/facebook/regenerator/tree/master/packages 里面的 regenerator-runtime 文件夹放进去。


然后在使用async-awiat的页面中引入:

 

step 3:

js

const regeneratorRuntime = require('../../../lib/regenerator-runtime/runtime')

 

step 4:改造wx.abcd()方法

使用promise()对现有函数进行封装。

函数声明: async function foo() {}
函数表达式: const foo = async function() {}
对象的方式: let obj = { async foo() {} }
箭头函数: const foo = async () => {}

 

https://developers.weixin.qq.com/community/develop/doc/00064622cc42802e908875c4456800