微信小程序全栈开发实践 第三章 微信小程序开发常用的API介绍及使用 -- 3.4 网络接口简介(四)Promise三个方法any、all与race的使用介绍

零、回顾

在上节课我们主要介绍了Promise,
这节课我们开始实践多个网络请求并发执行的处理策略,
并着手将原来的登录代码模块,使用Promise改写一下。

我们设想有这样一个场景,在页面启动的时候,我们需要加载多个接口,从多个接口中拉取页面初始化所需要的数据。
如果我们对这些接口的调用,采用完成一个加载一个的方法的话,就是对小程序并发优势的浪费了。

在Chrome浏览器中,对于同一域名下的资源加载量,最大并发数字是6,默认这个数字是6,其他浏览器稍有差别,但是一般都不会超过10个。
为了优化这个问题,有网站将资源分成几个域名,分别进行加载,一个域名不到10个,那多个域名加起来就大于10了。

在小程序中,并发原本是有限制的,像wx.request、wx.uploadFile、wx.downloadFile这些资源请求加起来,并发总数不能超过10个,
如果超出了,超出的请求将会被丢弃。开发者因为害怕这个链接被莫名地丢弃,所以在写代码的时候,都小心翼翼地维护并发的总数。

后来微信在20177月发布了基础库1.4.0版本,对网络请求做了优化,对超过并发限制的请求,做了队列处理,
超过10个数字的请求,不会再被丢弃了。对于开发者来讲我们不用管同时有几个请求,我们只需要以一种机制让网络请求并发最大化就可以了。
其他的交给小程序逻辑层去处理就可以了。

在上节课,留了一个问题,如何进行多服务器ip的连接,接下来我们在本课的源码中实践一下,下面这三个方法的具体应用。
promise.any()
promise.all()
promise.race()

注意

API Promise化链接:
https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/extended/utils/api-promise.html
`这个网址打开,现在是404`

在这里插入图片描述

异步 API 返回 Promise

基础库 2.10.2 版本起,异步 API 支持 callback & promise 两种调用方式。当接口参数 Object 对象中不包含 success/fail/complete 时将默认返回 promise,否则仍按回调方式执行,无返回值。

注意事项

  1. 部分接口如 downloadFile, request, uploadFile, connectSocket, createCamera(小游戏)本身就有返回值, 它们的 promisify 需要开发者自行封装。
  2. 当没有回调参数时,异步接口返回 promise。此时若函数调用失败进入 fail 逻辑, 会报错提示 Uncaught (in promise),开发者可通过 catch 来进行捕获。
  3. wx.onUnhandledRejection 可以监听未处理的 Promise 拒绝事件。

代码示例

`callback 形式调用`
wx.chooseImage({
  success(res) {
    console.log('res:', res)
  }
})


`promise 形式调用`
wx.chooseImage().then(res => console.log('res: ', res))

一、将wx.request这个接口转化为返回Promise对象的接口

在默认情况下,wx.request返回的是RequestTask对象,我们需要将它修改为Promise对象、
现在小程序确实不再是一个简单的前端框架,当我们需要将接口实现Promise化的时候,
微信团队提供了这样一个模块,miniprogram-api-promise,它可以扩展微信小程序API,使API支持promise编程。


API Promise化链接:
https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/extended/utils/api-promise.html
这个网址打开,现在是404

安装:
npm install --save miniprogram-api-promise


在使用npm指令安装以后,我们进行初始化。

import { promisifyAll, promisify } from 'miniprogram-api-promise';
const wxp = {}
promisifyAll(wx, wxp)

// 示例
wxp.getSystemInfo().then(console.log)
......

App({
	wxp:wxp 
})

上面我们现在看到的这个,就是一个初始化的代码,从第一行到第三行是它的初始化代码。
在初始化以后,wxp将可以替代wx,提供接口调用服务。
在小程序中,并没有像小游戏那样有一个GameGlobal这样的一个对象。
wx它是一个全局对象,在任何页面中都可以直接使用,
为了方便使用,刚才我们创建的wxp,我们可以将wxp挂载于App对象上,
然后在调用的时候我们可以通过getApp取到App对象,
然后再间接地取到wxp对象,这样就可以使用,就可以方便在每个页面上去使用它了。


一、any

any方法目前是处于试验阶段,处于草案提案当中,并未被所有的宿主环境所支持。
在小程序的Promise对象上,并没有any这个方法,我们目前只能换一种方式,去间接地实现它

安装
在这里插入图片描述
工具–构建npm
在这里插入图片描述

app.js
在这里插入图片描述
index.wxml
在这里插入图片描述

<view class="page-section">
	<text class="page-section__title">3.4 any & all  & race</text>
	<view class="btn-area">
    <button bindtap="any"  type="primary">请求1</button>

	</view>
</view>

index.js
在这里插入图片描述

 any(e){
    const app = getApp();
    // 1.先创建3个promise子实例
    let promise1 =   app.wxp.request({url: "http://localhost:30001"})
      .catch(err => { console.log("promise1")});
    let promise2 = app.wxp.request({ url: "http://localhost:30002/hi" })
      .catch(err => { console.log("promise2") });
    let promise3 = app.wxp.request({ url: "http://localhost:30001/user/home" })
      .catch(err => { console.log("promise3") });
    // 2.在通过Promise.any集合成为一个总的实例,然后进行执行
    let promise = Promise.any([promise1, promise2, promise3]).then(res=>{
      console.log("res1",res);
    },err=>{
      console.log("err1", err);
    })
    // 3.我们期许的结果是,这三个接口任何一个接口调用成功,会走到res里面,
    // 所有的调用失败才会走到err里面


  },
VM1031:1 thirdScriptError
Promise.any is not a function; [Component] Event Handler Error @ pages/api/index#bound any
TypeError: Promise.any is not a function
    at Se.any (http://127.0.0.1:16793/appservice/pages/api/index.js:30:27)
    at Object.r.safeCallback (http://127.0.0.1:16793/appservice/__dev__/WAService.js:2:1555740)
    at http://127.0.0.1:16793/appservice/__dev__/WAService.js:2:1675073
    at c (http://127.0.0.1:16793/appservice/__dev__/WAService.js:2:1683089)
    at http://127.0.0.1:16793/appservice/__dev__/WAService.js:2:1674998
    at r (http://127.0.0.1:16793/appservice/__dev__/WAService.js:2:1627525)
    at http://127.0.0.1:16793/appservice/__dev__/WAService.js:2:1627647
    at http://127.0.0.1:16793/appservice/__dev__/WAService.js:2:805361
    at n (http://127.0.0.1:16793/appservice/__dev__/asdebug.js:1:28029)
    at e.exports.<anonymous> (http://127.0.0.1:16793/appservice/__dev__/asdebug.js:1:28398)


Promise.any is not a function
any这个方法目前在草案这个提案当中,它不是一个正式发布的方法。
现在我们如果要实现这样的一个功能,我们怎么去做?
如果我们还想用any这个方法的话,我们可以自己去实现,
因为javascript它作为一种动态语言,它就有这种好处,我们可以没有的方法,我们可以自己动手去实现。
/**
 * @param {Array<Promise>} promises
 * @returns {Promise}
 */
//我们直接把这个方法写在Promise类对象上,我们就可以直接使用  Promise.any
//接受一个数组作为它的参数,
Promise.any = (arr) => {

  // 一共有多少个子实例
  let numTotal = arr.length;
  // 状态已经改变了多少个,作为一种计数
  let numSettled = 0;
  // 它是否已经是接受状态了
  let resolved = false;
  
  // 然后里面也是返回promise对象,同时它接受的也是一个匿名函数
  return new Promise((reslolve, reject) => {
  
    // for循环
    for (let j = 0; j < numTotal;j++){
      // 每个promise实例,我们可以先取出来
      let p =  arr[j];
      // 然后在作为一个监听
      p.then(res=>{
        // 如果有一个成功,就代表本身成功
        // 我们把resolved变量设置为true
        resolved = true;

        //同时调它本身的回调函数
        reslolve();
 
      },err=>{
        console.log("any err",err)

      }).finally(res=>{

        // 首先是计量,numSettled 它有多少个状态改变了,递增
        numSettled++
        // 递增之后,我们要检查一下,当前我们改变状态的数字,是不是已经达到了总数,
        // 如果达到了总数,并且它目前还不出于resolved解决状态
        // 这个就相当于所有的执行失败了,我们再调用reject方法,

        if (numSettled >= numTotal && !resolved) reject("all failed"); 
   
      })

    }



  });
}


在这里插入图片描述

3个接口都是fail的前提下,
刚刚出现的问题是,我们在外面的子实例上面然后加了catch,加了catch以后,没有进去,注释catch,就可以进入到err1中。
所以说我们目前对于any的实现,它其实说并不是特别完整,它只能说在一定条件之下,可以满足我们的需求

在这里插入图片描述

二、all

all这种方式,是所有的子实例的成功才算成功,有一失败便是失败。

index.wxml
在这里插入图片描述

<view class="page-section">
	<text class="page-section__title">3.4 any & all  & race</text>
	<view class="btn-area">
    <button bindtap="any"  type="primary">any</button>
    <button bindtap="all"  type="primary">all</button>
	</view>
</view>

在这里插入图片描述
index.js

  `3.4 all  all本身它是属于promise对象的一个方法,不需要我们去模拟实现了`
  all(e) {
    const app = getApp();
    // 1.先创建3个promise子实例
    let promise1 = app.wxp.request({ url: "http://localhost:30001" })
    // .catch(err => { console.log("promise1")});
    let promise2 = app.wxp.request({ url: "http://localhost:30002/hi" })
    // .catch(err => { console.log("promise2") });
    let promise3 = app.wxp.request({ url: "http://localhost:30001/user/home" })
    // .catch(err => { console.log("promise3") });

    // 2.在通过Promise.any集合成为一个总的实例,然后进行执行
    let promise = Promise.all([promise1, promise2, promise3]).then(res => {
      console.log("res1", res);
    }, err => {
      console.log("err1", err);
    })
    

  },

在这里插入图片描述

 `3.4 all  all本身它是属于promise对象的一个方法,不需要我们去模拟实现了`
  all(e) {
    const app = getApp();
    // 1.先创建3个promise子实例
    let promise1 = app.wxp.request({ url: "http://localhost:3000" })
    // .catch(err => { console.log("promise1")});
    let promise2 = app.wxp.request({ url: "http://localhost:3000/hi" })
    // .catch(err => { console.log("promise2") });
    let promise3 = app.wxp.request({ url: "http://localhost:3000/user/home" })
    // .catch(err => { console.log("promise3") });

    // 2.在通过Promise.any集合成为一个总的实例,然后进行执行
    let promise = Promise.all([promise1, promise2, promise3]).then(res => {
      console.log("res1", res);
    }, err => {
      console.log("err1", err);
    })
    

  },

三、race

有一个成功就算成功,有一个失败也算失败,就看哪个子实例执行的快。

index.wxml
在这里插入图片描述

<view class="page-section">
	<text class="page-section__title">3.4 any & all  & race</text>
	<view class="btn-area">
    <button bindtap="any"  type="primary">any</button>
    <button bindtap="all"  type="primary">all</button>
    <button bindtap="race"  type="primary">race</button>
	</view>
</view>

在这里插入图片描述

`3.4 race  是赛跑机制,只要这三个里面有一个有结果了,然后就马上返回一个结果。`
  race(e) {
    const app = getApp();
    // 1.先创建3个promise子实例
    let promise1 = app.wxp.request({ url: "http://localhost:30001" })
    // .catch(err => { console.log("promise1")});
    let promise2 = app.wxp.request({ url: "http://localhost:30001/hi" })
    // .catch(err => { console.log("promise2") });
    let promise3 = app.wxp.request({ url: "http://localhost:3000/user/home" })
    // .catch(err => { console.log("promise3") });

    
    let promise = Promise.race([promise1, promise2, promise3]).then(res => {
      console.log("res1", res);
    }, err => {
      console.log("err1", err);
    })


  },

四、总结

这节课我们主要实践练习了Promise的三个方法,any、all、race,
其中any还处于草案阶段,不过对Javascript这样的动态语言,对于缺失的方法我们可以自行补全。
下节课我们尝试将登录模块,使用Promise变成的方式进行改写。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值