一个同步登录实现
程序丢失登录状态时, 在执行后端 API 时需要中途更新登录, 我看过不少小程序的代码, 对这方面的处理是粗漏, 甚至根本上处理的思路都是混乱的.
下面这个实现在丢失状态的并发 API 请求处理. 当第一个 API 请求遇到丢失登录状态, 就将其实加入队列 queue 中, 并执行登录方法. 在登录请求完成前发生的并发请求会陆续加入队列中, 当登录完成后再将队列缓存的请求以新的登录状态完成请求. 代码中截取项目中的相关部分, 以作参考.
App 对象的登录方法 login 在登录完成后会执行回调函数 openidCallback, 并传入登录后获取到的 token.
- login:function(options){
- wx.login({
- success: (e)=>{
- wx.request({
- url: config.server_url+"loginopen",
- data: {
- onlaunch:JSON.stringify(options),
- code: e.code
- },
- method: "POST",
- header: {
- "Content-Type": "application/x-www-form-urlencoded"
- },
- success: (a)=>{
- this.globalData.userinfo.openid = a.data.open_id;
- this.globalData.userinfo.unionid = a.data.unionid;
- this.globalData.userinfo.nickname = a.data.wx_nickname;
- if (this.openidCallback) {
- this.openidCallback(a.data.open_id);
- }
- },
- fail: function () {
- }
- })
- }
- });
- },
对于过时的浏览器, 使用工具 bluebird.JS 来支持 ES6 Promise 对象
- http://bluebirdjs.com/docs/getting-started.html
- let config = require("../../utils/config.js");
- var e = function(e) {
- return e && e.__esModule ? e : {
- default: e
- }
- }(require("../js/bluebird.min.js"));
- var trycount = 0;
- var queue = [];
- module.exports = {
- fetchApi: function(t, r, i) {
- if( t.indexOf("http")!==0 ) t = config.server_url+t;
- return new e.
- default ((e, a)=>{
- var n = t.match(/^http[s]{0,1}:\/\/([a-zA-Z0-9\-]+\.)*?idol001.com/i),
- c = null;
- c = n && o.cookie ? {
- "Content-Type": "GET" == i ? "application/json" : "application/x-www-form-urlencoded; charset=utf-8",
- Cookie: o.cookie
- } : {
- "Content-Type": "GET" == i ? "application/json" : "application/x-www-form-urlencoded; charset=utf-8"
- },
- n && (r.app_platform = "wxxbillboard", r.version = "1"),
- wx.request({
- url: "" + t,
- data: Object.assign({}, r),
- method: i,
- header: c,
- success: (res)=>{
- let App = getApp();
- if( res.data.state=="unlogin"){
- let item = {url:t,data:r,method:i,succ:e,fail:a};
- if( queue.length ) {
- return queue.push(item);
- }else{
- queue.push(item);
- }
- if( ++trycount%9==0 ) return;
- wx.showToast({'title':"正在尝试更新登录",duration:3000,icon:"loading"});
- App.openidCallback = (openid)=>{
- r.openid = openid;
- for( let p of queue ){
- console.log( "fetchApi retry with", trycount, openid, p );
- this.fetchApi(p.url,p.data,p.method).then(p.succ,p.fail);
- }
- // this.fetchApi(t,r,i).then(e,a);
- }
- App.login({"msg":"try login"});
- }else e(res);
- },
- fail: a
- })
- })
- },
- needThatThing: function (e) {
- var r = 0;
- return (e += "").split("").forEach(function (e, t) {
- r += e.charCodeAt(0)
- }), r % 1026 == "15"
- },
- getThingIsin: function () {
- var e = "fromCharCode";
- return String[e](24212) + String[e](25588) + String[e](24065)
- }
- };
登录状态丢失的并发处理
演示图上, 两个箭头所指的 API 是需要登录的, 作为测试, 在执行它们之前, 手动清理登录状态, 代码收到后端登录丢失的 unlogin 信息后, 就会开启请求缓存队列, 并重新尝试登录, 完成登录后再执行队列缓存的请求, 通过回调函数完成数据传送, 回调函数所起的作用是重要的.
PS: 打个补丁, 代码中的 for 循环是错误的, 因为队列没有清理, 下次再有登录丢失时这个机制就失效了, 因为条件判断会跳出尝试登录的代码.
- let p = null;
- while( p = queue.pop() ){
如果想尝试使用我手上这个项目, 请微信搜索《偶像影响力》小程序, 欢迎小伙伴围观, 或扫码打开小程序.
偶像影响力微信小程序
一个完整的独立模块实现
- let config = require("../../utils/conf.js");
- let bluebird = require("../../utils/bluebird.min.js");
- var e = function(e) {
- return e && e.__esModule ? e : {
- default: e
- }
- }(bluebird);
- var trycount = 0;
- var queue = [];
- module.exports = {
- fetchApi: function(t, r, i) {
- if( t.indexOf("http")!==0 ) t = config.server_url+t;
- return new e.
- default ((e, a)=>{
- var n = t.match(/^http[s]{0,1}:\/\/([a-zA-Z0-9\-]+\.)*?idol001.com/i),
- c = { "Content-Type": "GET" == i ? "application/json" : "application/x-www-form-urlencoded; charset=utf-8"};
- if( n && o.cookie ) c.Cookie = o.cookie;
- wx.request({
- url: "" + t,
- data: Object.assign({}, r),
- method: i,
- header: c,
- success: (res)=>{
- let App = getApp();
- if( res.data.state=="unlogin"){
- let item = {url:t,data:r,method:i,succ:e,fail:a};
- if( queue.length ) {
- return queue.push(item);
- }else{
- queue.push(item);
- }
- if( ++trycount%9==0 ) return;
- wx.showToast({'title':"正在尝试登录",duration:3000,icon:"loading"});
- this.loginCallback = (openid)=>{
- let p = null;
- while( p = queue.pop() ){
- p.data.openid = openid;
- console.log( "fetchApi retry with", trycount, openid, p );
- this.fetchApi(p.url,p.data,p.method).then(p.succ,p.fail);
- }
- App.loginCallback && App.loginCallback(openid);
- }
- this.login({"msg":"try login"});
- }else e(res);
- },
- fail: a
- })
- })
- },
- login:function(options){
- wx.login({
- success: (e)=>{
- wx.request({
- url: config.server_url+"loginopen",
- data: {
- onlaunch:JSON.stringify(options),
- code: e.code
- },
- method: "POST",
- header: {
- "Content-Type": "application/x-www-form-urlencoded"
- },
- success: (a)=>{
- let App = getApp();
- App.globalData.userinfo.openid = a.data.open_id;
- App.globalData.userinfo.unionid = a.data.unionid;
- App.globalData.userinfo.nickname = a.data.wx_nickname;
- this.loginCallback && this.loginCallback(a.data.open_id);
- },
- fail: function () {
- }
- })
- }
- });
- }
- };
来源: http://www.jianshu.com/p/937d8d6d046a