微信小程序使用Promise
发布于 3 个月前 作者 zouzhenxing 1930 次浏览 来自 分享

看示官方小例子代码

getUserInfo:function(cb){
    var that = this
    if(this.globalData.userInfo){
      typeof cb == "function" && cb(this.globalData.userInfo)
    }else{
      //调用登录接口
      wx.login({
        success: function () {
          wx.getUserInfo({
            success: function (res) {
              that.globalData.userInfo = res.userInfo
              typeof cb == "function" && cb(that.globalData.userInfo)
            }
          })
        }
      })
    }
  },

昨天研究了一下微信小程序的例子,看见了熟悉cb了。我们好不容易从cb走向了Promise,如果开发小程序要回到cb中,这是我不能接受的,搞得我昨晚一晚上没有睡好,今年早一大早就到公司想办法解决问题。

解决思路 1、直接使用Promise,我试了一下,是可行的,但这受限于运行程序的浏览器。不能保证所有浏览器都支持Promise。 2、使用第三方库,bluebird,Q,Defrered等,这样可以不依赖浏览器实现。 说做就做,我最熟悉的是bluebird,于是先就在工程文件夹下执行

npm init
npm i bluebird --save

得到项目结构如下图 untitled1.png 在App.js中写入

var Promise = require("node_modules/node_modules/js/browser/bluebird.js");

通过调试发现Promise为undfine,解决问题失败! 深入分析 难道真如网上所说不能加载第三方JS?我觉得应该不可能,如果不能使用第三方程序,什么都靠自己写,累都累死。忽然想到一段代码

logs.js
var util = require('../../utils/util.js')

util.js
module.exports = {
  formatTime: formatTime
}

如果能在logs.js中引入util.js,就一定能引第三方包,只是我没有搞清楚这个加载机制。看上面的代码好像是CMD。我想来想去,最终在浏览器发现了这个。

define("utils/util.js", function(require, module){var window={Math:Math}/*兼容babel*/,location,document,navigator,self,localStorage,history,Caches;

module.exports = {
  formatTime: formatTime
}

})

这是浏览加载后的代码,通过代码分析,总结出如下经验: 1、原来小程序是自己定义了一套加载机制,不是CMD也不是AMD,到有点与NG相同。 2、小程序会为每个js文件加一个包头,每个包中都增加一个window对象,所以在小程序中,window对象是一个局部变量。 3、document对象不一定有值 4、require是一个函数,module是一个对象这点与CMD一至 再次尝试 要在小程序中使用第三方包,就必须修改加载头。当我打开个bluebird源码时,立马就懵逼了,看不懂。所以就选择了Q,这个简单些,先看没有修改之样的。

(function (definition) {
    "use strict";

    // This file will function properly as a <script> tag, or a module
    // using CommonJS and NodeJS or RequireJS module formats.  In
    // Common/Node/RequireJS, the module exports the Q API and when
    // executed as a simple <script>, it creates a Q global instead.

    // Montage Require
    if (typeof bootstrap === "function") {
        bootstrap("promise", definition);

    // CommonJS
    } else if (typeof exports === "object" && typeof module === "object") {
        module.exports = definition();

    // RequireJS
    } else if (typeof define === "function" && define.amd) {
        define(definition);

    // SES (Secure EcmaScript)
    } else if (typeof ses !== "undefined") {
        if (!ses.ok()) {
            return;
        } else {
            ses.makeQ = definition;
        }

    // <script>
    } else if (typeof window !== "undefined" || typeof self !== "undefined") {
        // Prefer window over self for add-on scripts. Use self for
        // non-windowed contexts.
        var global = typeof window !== "undefined" ? window : self;

        // Get the `window` object, save the previous Q global
        // and initialize Q as a global.
        var previousQ = global.Q;
        global.Q = definition();

        // Add a noConflict function so Q can be removed from the
        // global namespace.
        global.Q.noConflict = function () {
            global.Q = previousQ;
            return this;
        };

    } else {
        throw new Error("This environment was not anticipated by Q. Please file a bug.");
    }

})(function () {
"use strict";

这段代码,我立马就看懂了,这就是一个标准的闭包,definition是定义函数,Q一共适配了CommonJS,RequireJS加载,但可惜能过调试,进入了<script>这个分支,原因很简单,有window对象。但此window不是彼window,所以加载失败。

想明白了就好改了,改后代码如下:

(function (definition) {
    "use strict";
    module.exports = definition();
})(function () {
"use strict";

需要注意的是definition后面一定要带(),表示执行这个函数,我一开始没有执行,结果使用时没有得到Q对象。原因是definition函数返回Q对象,大家看最一行代码。 使用Q改写获取用户 Q的使用很简单,主要改了这样几处地方

//app.js
var Q = require("utils/q.js");
App({
  onLaunch: function () {
    //调用API从本地缓存中获取数据
    var logs = wx.getStorageSync('logs') || []
    logs.unshift(Date.now())
    wx.setStorageSync('logs', logs)
  },
  globalData:{
    userInfo:null
  },
  login : function() {
    var def = Q.defer();
    wx.login({
      success : function() {
        def.resolve();
      }
    });
    return def.promise;
  },
  getUserInfo : function() {
    var that = this;
    var def = Q.defer();
    
    if( this.globalData.userInfo ) {
      def.resolve(this.globalData.userInfo);
    } else {
      this.login().then(function(){
        wx.getUserInfo({
          success : function( res ) {
            that.globalData.userInfo = res.userInfo;
            def.resolve(res.userInfo);
          }
        });
      });
    }

    return def.promise;
  }
})
//index.js
//获取应用实例
var app = getApp()
Page({
  data: {
    motto: 'Hello World',
    userInfo: {}
  },
  //事件处理函数
  bindViewTap: function() {
    wx.navigateTo({
      url: '../logs/logs'
    })
  },
  onLoad: function () {
    console.log('onLoad')
    var that = this
    //调用应用实例的方法获取全局数据
    app.getUserInfo().then(function(userInfo){
      that.setData({
        userInfo:userInfo
      })
    });
    console.log(window.document);
  }
})

总结 1、不要先入为主,网上的东西不能不信,也不能尽信,尽量去自己尝试。 2、X讯自己造了一个封闭的环境,开放?封闭?这个东西好坏得时间来验证。 3、得理解包加载机制,基础的东西最重要。

12 回复

感谢啊,终于有人看明白这篇文章的意义了。 From Noder

很好,加油啊,马克

确实是,微信小程序,还有很多不尽人意的地方,总感觉开发氛围是一个围城,有一堵墙,怕的是,没有活跃的社区,很难活下去。 还有,楼主bluebird是可以使用的,不用去引进bluebird.js,而引入promise.js。

1.首先通过npm包获取bluebird

npm install npm i bluebird --save

2.进入node_modules/bluebird,将node_modules/bluebird/js/release 文件夹拷贝出来。在楼主的目录结构下,就将其拷贝到utils文件夹下。然后在utils/util.js中引入就可以了。

var bluebird = require("./release/promise")()
module.exports.Promise = bluebird

3.尽情的使用Promise,这里提供HTTP的实例

  getApi (url){
  	return new Promise(function(resolve,reject){
  		wx.request({
	 		  url,
			  data: {},
			  header: { 'Content-Type': 'application/json' },
			  success (res) {
			    resolve(res.data)
			  },
			  fail (e) {
			    reject(e)
			  }
	  	})
  	})
  }

哦对了,微信小程序里面是可以用胖箭头的,如果需要的话可以尽情使用。 happy hacking

@chux0519 感谢你认真的读完我的文章,谢谢你帮我补充了我没做到的事。箭头函数的使用会不会与浏览器有关? From Noder

所以说, 一如既往的, 国内互联网公司, 屎一样的接口设计.

@joesonw 哈哈,看到了好多次,接口对开发者不友好,白白浪费时间。不得不说,腾讯的文档写的很差(我是针对微信开发文档说的,初次读个好几遍都没弄很明白…)

@zouzhenxing 也不太清楚,今天我又发现微信小程序是原生支持Promise的

@chux0519 在开发工具中是可以使用的,因为开发工具用的是chrome的内核,但如果在微信中就不一定支持了。

今天看了腾讯云的demo,鹅厂的员工是直接

new Promise((resolve, reject) => {});

demo地址:https://github.com/CFETeam/weapp-demo-websocket

@coolfishstudio 他们还把websocket封装成支持socket.io的包。那个demo非常有阅读的价值。

回到顶部