1 | import {
|
2 | onAndSyncApis,
|
3 | noPromiseApis,
|
4 | otherApis,
|
5 | initPxTransform,
|
6 | Link
|
7 | } from '@tarojs/taro'
|
8 | import { cacheDataSet, cacheDataGet } from './data-cache'
|
9 | import { queryToJson, getUniqueKey } from './util'
|
10 |
|
11 | const RequestQueue = {
|
12 | MAX_REQUEST: 5,
|
13 | queue: [],
|
14 | pendingQueue: [],
|
15 |
|
16 | request (options) {
|
17 | this.queue.push(options)
|
18 | return this.run()
|
19 | },
|
20 |
|
21 | run () {
|
22 | if (!this.queue.length) return
|
23 |
|
24 | while (this.pendingQueue.length < this.MAX_REQUEST) {
|
25 | const options = this.queue.shift()
|
26 | let successFn = options.success
|
27 | let failFn = options.fail
|
28 | options.success = (...args) => {
|
29 | this.pendingQueue = this.pendingQueue.filter(item => item !== options)
|
30 | this.run()
|
31 | successFn && successFn.apply(options, args)
|
32 | }
|
33 | options.fail = (...args) => {
|
34 | this.pendingQueue = this.pendingQueue.filter(item => item !== options)
|
35 | this.run()
|
36 | failFn && failFn.apply(options, args)
|
37 | }
|
38 | this.pendingQueue.push(options)
|
39 | return tt.request(options)
|
40 | }
|
41 | }
|
42 | }
|
43 |
|
44 | function taroInterceptor (chain) {
|
45 | return request(chain.requestParams)
|
46 | }
|
47 |
|
48 | const link = new Link(taroInterceptor)
|
49 |
|
50 | function request (options) {
|
51 | options = options || {}
|
52 | if (typeof options === 'string') {
|
53 | options = {
|
54 | url: options
|
55 | }
|
56 | }
|
57 | const originSuccess = options['success']
|
58 | const originFail = options['fail']
|
59 | const originComplete = options['complete']
|
60 | let requestTask
|
61 | const p = new Promise((resolve, reject) => {
|
62 | options['success'] = res => {
|
63 | originSuccess && originSuccess(res)
|
64 | resolve(res)
|
65 | }
|
66 | options['fail'] = res => {
|
67 | originFail && originFail(res)
|
68 | reject(res)
|
69 | }
|
70 |
|
71 | options['complete'] = res => {
|
72 | originComplete && originComplete(res)
|
73 | }
|
74 |
|
75 | requestTask = RequestQueue.request(options)
|
76 | })
|
77 | p.abort = (cb) => {
|
78 | cb && cb()
|
79 | if (requestTask) {
|
80 | requestTask.abort()
|
81 | }
|
82 | return p
|
83 | }
|
84 | return p
|
85 | }
|
86 |
|
87 | function processApis (taro) {
|
88 | const weApis = Object.assign({ }, onAndSyncApis, noPromiseApis, otherApis)
|
89 | const preloadPrivateKey = '__preload_'
|
90 | const preloadInitedComponent = '$preloadComponent'
|
91 | Object.keys(weApis).forEach(key => {
|
92 | if (!(key in tt)) {
|
93 | taro[key] = () => {
|
94 | console.warn(`头条小程序暂不支持 ${key}`)
|
95 | }
|
96 | return
|
97 | }
|
98 | if (!onAndSyncApis[key] && !noPromiseApis[key]) {
|
99 | taro[key] = (options, ...args) => {
|
100 | options = options || {}
|
101 | let task = null
|
102 | let obj = Object.assign({}, options)
|
103 | if (typeof options === 'string') {
|
104 | if (args.length) {
|
105 | return tt[key](options, ...args)
|
106 | }
|
107 | return tt[key](options)
|
108 | }
|
109 |
|
110 | if (key === 'navigateTo' || key === 'redirectTo') {
|
111 | let url = obj['url'] ? obj['url'].replace(/^\//, '') : ''
|
112 | if (url.indexOf('?') > -1) url = url.split('?')[0]
|
113 |
|
114 | const Component = cacheDataGet(url)
|
115 | if (Component) {
|
116 | const component = new Component()
|
117 | if (component.componentWillPreload) {
|
118 | const cacheKey = getUniqueKey()
|
119 | const MarkIndex = obj.url.indexOf('?')
|
120 | const hasMark = MarkIndex > -1
|
121 | const urlQueryStr = hasMark ? obj.url.substring(MarkIndex + 1, obj.url.length) : ''
|
122 | const params = queryToJson(urlQueryStr)
|
123 | obj.url += (hasMark ? '&' : '?') + `${preloadPrivateKey}=${cacheKey}`
|
124 | cacheDataSet(cacheKey, component.componentWillPreload(params))
|
125 | cacheDataSet(preloadInitedComponent, component)
|
126 | }
|
127 | }
|
128 | }
|
129 |
|
130 | const p = new Promise((resolve, reject) => {
|
131 | ['fail', 'success', 'complete'].forEach((k) => {
|
132 | obj[k] = (res) => {
|
133 | options[k] && options[k](res)
|
134 | if (k === 'success') {
|
135 | if (key === 'connectSocket') {
|
136 | resolve(
|
137 | Promise.resolve().then(() => Object.assign(task, res))
|
138 | )
|
139 | } else {
|
140 | resolve(res)
|
141 | }
|
142 | } else if (k === 'fail') {
|
143 | reject(res)
|
144 | }
|
145 | }
|
146 | })
|
147 | if (args.length) {
|
148 | task = tt[key](obj, ...args)
|
149 | } else {
|
150 | task = tt[key](obj)
|
151 | }
|
152 | })
|
153 | if (key === 'uploadFile' || key === 'downloadFile') {
|
154 | p.progress = cb => {
|
155 | if (task) {
|
156 | task.onProgressUpdate(cb)
|
157 | }
|
158 | return p
|
159 | }
|
160 | p.abort = cb => {
|
161 | cb && cb()
|
162 | if (task) {
|
163 | task.abort()
|
164 | }
|
165 | return p
|
166 | }
|
167 | }
|
168 | return p
|
169 | }
|
170 | } else {
|
171 | taro[key] = (...args) => {
|
172 | const argsLen = args.length
|
173 | const newArgs = args.concat()
|
174 | const lastArg = newArgs[argsLen - 1]
|
175 | if (lastArg && lastArg.isTaroComponent && lastArg.$scope) {
|
176 | newArgs.splice(argsLen - 1, 1, lastArg.$scope)
|
177 | }
|
178 | return tt[key].apply(tt, newArgs)
|
179 | }
|
180 | }
|
181 | })
|
182 | }
|
183 |
|
184 | function pxTransform (size) {
|
185 | const {
|
186 | designWidth = 750,
|
187 | deviceRatio = {
|
188 | '640': 2.34 / 2,
|
189 | '750': 1,
|
190 | '828': 1.81 / 2
|
191 | }
|
192 | } = this.config || {}
|
193 | if (!(designWidth in deviceRatio)) {
|
194 | throw new Error(`deviceRatio 配置中不存在 ${designWidth} 的设置!`)
|
195 | }
|
196 | return parseInt(size, 10) / deviceRatio[designWidth] + 'rpx'
|
197 | }
|
198 |
|
199 | export default function initNativeApi (taro) {
|
200 | processApis(taro)
|
201 | taro.request = link.request.bind(link)
|
202 | taro.addInterceptor = link.addInterceptor.bind(link)
|
203 | taro.cleanInterceptors = link.cleanInterceptors.bind(link)
|
204 | taro.getCurrentPages = getCurrentPages
|
205 | taro.getApp = getApp
|
206 | taro.initPxTransform = initPxTransform.bind(taro)
|
207 | taro.pxTransform = pxTransform.bind(taro)
|
208 | }
|