如何在uni-app项目里让多个uni.request()异步请求按顺序执行——封装uni.request()异步请求按同步的方式执行

如果在你的uni-app项目里,出现以下情况:

1) 你希望用第1个uni.request请求返回的结果作为第2个uni.request请求的参数;

2)如果你发现Storage里存储的数据根本获取不到,或者即使获取到也是上一次没清空的历史数据,Storage传参失败;

3)你希望出现的代码执行顺序并没有按照你的预期顺序执行;

那么很显然,你需要让uni.request()异步请求变成同步请求,因为uni-app的官网没有提供同步请求方法uni.requestSync();

 所以我们需要使用Promise去封装uni.request(),或者使用 async 和 await去封装uni.request(),这样

uni.request()就会按照同步的方式执行,就不会出现uni.request()中参数获得参数值早于其它的uni.request()请求返回的结果

接下来,我会分多个版本的小项目去录屏调式演示出现这种状况的原因:

温馨提示:每个演示项目里都会用的md5.js文件,我上传的md5.js文件下载地址如下:

链接:https://pan.baidu.com/s/1uANsO5zfh7Q4Lw0jvXPZgg
提取码:3wuo
本篇博文很长,请耐心阅读,即使uni-app的官网上也没有这么高质量的文章。

范例1:

项目结构截图如下:

如何在uni-app项目里让多个uni.request()异步请求按顺序执行——封装uni.request()异步请求按同步的方式执行_第1张图片

如何启动真机调试app程序,请按如下截图说明操作,后面几个项目

范例中不再啰嗦同样的话:

如何在uni-app项目里让多个uni.request()异步请求按顺序执行——封装uni.request()异步请求按同步的方式执行_第2张图片

commons\sign-tool.js文件代码如下:

var md5 = require('./md5.js');
module.exports = {
  sign : function(){
	  var greeting = "welcome to my world";
	  var greetingmd5 = md5.hex_md5(greeting)
      uni.setStorageSync("greeting",greeting);
	  uni.setStorageSync("greetingmd5",greetingmd5);
	  console.log('sign-tool.js 开始打印输出以下内容:');
      console.log("明文:"+greeting);
	  console.log("密文:"+greetingmd5);
	  console.log('sign-tool.js 结束打印输出');
   }
}

index\index.vue文件代码如下:


整个v1版本的项目代码已全部贴完,我将录屏演示调试代码的执行流程,即使你知道代码会怎么运行,

再看看我发的小视频又不碍啥事,因为后面的几个项目范例的调试视频你是一定会看的。

范例1演示调试代码的视频如下:

链接:https://pan.baidu.com/s/1PoathVeL6yY8m2vZkn5IzQ
提取码:4azu

范例1调试工具的控制台会输出如下截图内容:

如何在uni-app项目里让多个uni.request()异步请求按顺序执行——封装uni.request()异步请求按同步的方式执行_第3张图片

根据调试代码的视频和输出结果,我们可以得出如下结论:

本范例流程执行正常 能按照我们预期的代码执行顺序运行。

 

范例2:

接下来演示的几个项目范例,我们都会用到PHP实现的Restful api 接口,用Redis作为数据存储服务器,

我将使用ThinkPHP 6.0.2这个最新版本框架来写后台数据接口。

 

在演示范例2之前,我们需要先把后台数据接口写好,接下来我们先来写PHP实现的后台代码吧。

phpStudy v8.1版 下载地址:https://www.xp.cn/download.html 安装到D:\phpstudy

Redis for Windows 64位版 下载地址:https://github.com/microsoftarchive/redis/releases/download/win-3.0.504/Redis-x64-3.0.504.msi

ThinkPHP6.0.2 下载地址:https://github.com/top-think/think/archive/v6.0.2.zip 解压到(WWW文件夹不包括v6.0.2文件夹) D:\phpstudy\WWW

composer下载地址:https://getcomposer.org/Composer-Setup.exe

安装composer.exe程序,一路Next就好,
当安装出现Choose the command-line PHP you want to use:请浏览选择php.exe文件的完整路径
D:\phpstudy\Extensions\php\php7.3.4nts\php.exe

接下来以更新安装的方式安装ThinkPHP项目需要的一切依赖文件
C:\Users\ZiGoo>D:
D:\>cd D:\phpstudy\WWW
D:\phpstudy\WWW>composer update topthink/framework

WWW\config\cache.php文件代码如下:

 env('cache.driver', 'file'),

    // 缓存连接方式配置
    'stores'  => [
        'file' => [
            // 驱动方式
            'type'       => 'File',
            // 缓存保存目录
            'path'       => '',
            // 缓存前缀
            'prefix'     => '',
            // 缓存有效期 0表示永久缓存
            'expire'     => 0,
            // 缓存标签前缀
            'tag_prefix' => 'tag:',
            // 序列化机制 例如 ['serialize', 'unserialize']
            'serialize'  => [],
        ],
        // redis缓存
        'redis'   =>  [
            // 驱动方式
            'type'   => 'redis',
            // 服务器地址
            'host'       => '127.0.0.1',
            // 缓存前缀
            'prefix'     => '',
            // 缓存有效期 0表示永久缓存
            'expire'     => 0,
            // 序列化机制 例如 ['serialize', 'unserialize']
            'serialize'  => [],
        ],  
        // 更多的缓存连接
    ],
];

WWW\route\app.php文件代码如下:


// +----------------------------------------------------------------------
use think\facade\Route;

// GET 'http://2977a2v278.zicp.vip/public/index.php/zigoo.token.generate'
Route::get('zigoo.token.generate','Token/generateToken');

// GET http://2977a2v278.zicp.vip/public/index.php/zigoo.tutorial.sign.call
Route::get('zigoo.tutorial.sign.call','Tutorial/callSign');

WWW\app\controller\Token.php文件代码如下:

 $session_create_id,
            'time'  => $time
        );
        Cache::store('redis')->set($token['token'],$token['time'],3600);
		exit(json_encode(['status' => 'ok','data' => $token]));
	}
	
}

WWW\app\controller\Tutorial.php文件代码如下:

request->param('version');
		Cache::store('redis')->incr('counter'); //记录接口被访问的次数
		checkSign();//如果用户想获得本接口返回的数据,必须通过签名验证
		return json_encode(['status' => 'ok', 'data' => '你访问的是被签名保护的Restful api 接口','version' => $version]);
		
	}
}

WWW\app\common.php文件代码如下:

PHP后台代码已全部贴完。

uni-app项目结构截图如下:

如何在uni-app项目里让多个uni.request()异步请求按顺序执行——封装uni.request()异步请求按同步的方式执行_第4张图片

commons\sign-tool.js文件代码如下:

var md5 = require('./md5.js');
module.exports = {
	sign : function(apiServer,params = {}){ 
		uni.request({
			url: apiServer+'zigoo.token.generate',
			method: 'GET',
			success: res => {
				console.log(res);
				if(res.data.status != 'ok'){return ;}
				var data = res.data.data;
                console.log('明文:token'+data.token +' time:' + data.time);
				var datamd5 = md5.hex_md5(data.token + data.time) + '-' + data.token;
				console.log('密文:'+ datamd5);
				// 记录在本地
				uni.setStorageSync("token",datamd5);
				uni.setStorageSync("time",data.time);	
			},
			fail:function(e){
				console.log(JSON.stringify(e));
			}
		});
	}
}

index\index.vue文件代码如下:


main.js文件代码如下:

import Vue from 'vue'
import App from './App'

Vue.config.productionTip = false

Vue.prototype.apiServer = 'http://2977a2v278.zicp.vip/public/index.php/';
App.mpType = 'app'

const app = new Vue({
    ...App
})
app.$mount()

范例2演示调试代码的视频如下:

链接:https://pan.baidu.com/s/1e-GK0lYFDkE1drp89LNQ1w
提取码:d9sh

从调试代码的执行流程视频中,我们可以得出这样的结论:

多个异步请求uni.request()函数,全部异步的请求函数,每个请求输入参数的初始化都赋值完毕后,

才执行第1个异步请求,这样代码的执行逻辑就不对啦,我们需要的是第1个异步请求返回值作为第2

个异步请求的输入参数,因为异步请求输入参数获得参数值的执行时间早于所有异步请求GET和POST请求发出。

所以Storage传参就自然失败啦,这是个典型的错误范例,在范例3中我将封装异步请求按照同步的方式执行来更正这个错误的范例。

 

范例3:

项目结构截图如下,这是一个正确的范例:

如何在uni-app项目里让多个uni.request()异步请求按顺序执行——封装uni.request()异步请求按同步的方式执行_第5张图片

commons\sign-tool.js文件代码如下:

var md5 = require('./md5.js');
module.exports = {
	// 注意async 和 await 的修饰写法,意思是让异步请求uni.request()封装到同步函数sign里执行
	async sign(apiServer,params = {}){ 
		// GET请求返回数据:{"data":{"status":"ok","data":{"token":"5qraetfdq8kqi339u4m2if6k0e","time":1589808256}}
		var [e,res] = await uni.request({
			url: apiServer+'zigoo.token.generate',
			method: 'GET'
		});
		console.log(res);
		if(res.data.status != 'ok'){return ;}
		var data = res.data.data;
		console.log('明文:token'+data.token +' time:' + data.time);
		var datamd5 = md5.hex_md5(data.token + data.time) + '-'+ data.token;
		console.log('密文:'+ datamd5);
		// 记录在本地
		uni.setStorageSync("token", datamd5);   // 1f3907e22469764866dce02aba5e26a2-5qraetfdq8kqi339u4m2if6k0e
		uni.setStorageSync("time", data.time);	// 1589808256
		/*uni.setStorage({
			key: 'token',
			data: datamd5,
			success: function () {
				console.log('success1');
			}
		});
		uni.setStorage({
			key: 'time',
			data: data.time,
			success: function () {
				console.log('success2');
			}
		});*/
		return;
	}
}

index\index.vue文件代码如下:


 main.js文件代码如下:

import Vue from 'vue'
import App from './App'

Vue.config.productionTip = false

Vue.prototype.apiServer = 'http://2977a2v278.zicp.vip/public/index.php/';
App.mpType = 'app'

const app = new Vue({
    ...App
})
app.$mount()

范例3演示调试代码的视频如下:

链接:https://pan.baidu.com/s/1FThCIzp6J4j_wX9aP-MFOw
提取码:p8mq

从调试代码的视频中,我们很直观看到代码能够按照我们期望的自然顺序来执行代码啦,结论:范例3代码正确。

接下来在范例4中我将使用Promise来替代async和await来实现范例3同样的同步执行效果。

 

范例4:

项目结构截图如下,这也是一个正确的范例:

如何在uni-app项目里让多个uni.request()异步请求按顺序执行——封装uni.request()异步请求按同步的方式执行_第6张图片

commons\sign-tool.js文件代码如下:

var md5 = require('./md5.js');
module.exports = {
	sign(apiServer, params = {}) {
		//注意 Promise取代 async 和 await的写法,同步函数sign把异步请求uni.request封装成同步的方式执行
		return new Promise((resolve, reject) => {
			// GET请求返回数据:{"data":{"status":"ok","data":{"token":"5qraetfdq8kqi339u4m2if6k0e","time":1589808256}}
			uni.request({
				url: apiServer + 'zigoo.token.generate',
				method: 'GET',
				success: (res) => {
					console.log(res);
					if (res.data.status != 'ok') {
						return;
					}
					var data = res.data.data;
					console.log('加密之前:token' + data.token + ' time:' + data.time);
					var datamd5 = md5.hex_md5(data.token + data.time) + '-'+ data.token;
					console.log('加密输出结果:' + datamd5);
					// 记录在本地
					uni.setStorageSync("token", datamd5); // 1f3907e22469764866dce02aba5e26a2-5qraetfdq8kqi339u4m2if6k0e
					uni.setStorageSync("time", data.time); // 1589808256
					resolve(res);
				},
				fail: (err) => {
					console.log('request fail', err)
					reject(err)
				}
			})
		})
	}
}

index\index.vue文件代码如下:


 main.js文件代码如下:

import Vue from 'vue'
import App from './App'

Vue.config.productionTip = false

Vue.prototype.apiServer = 'http://2977a2v278.zicp.vip/public/index.php/';
App.mpType = 'app'

const app = new Vue({
    ...App
})
app.$mount()

范例4演示调试代码的视频如下,个人感觉范例4的代码写法没有范例3运行得流畅:

链接:https://pan.baidu.com/s/1vLDbfB25At8oAWI_ujCl3w
提取码:t74g

从调试代码的视频中,我们很直观看到代码能够按照我们期望的自然顺序来执行代码啦,结论:范例4代码正确。

本篇博文全部内容已更新完毕。

你可能感兴趣的:(uni-app)