This article has been authorized to be exclusively used by the public account of the Nuggets Developer community, including but not limited to editing and marking original rights.

Introduction to the

Wechat applets message subscription is a function used in most applets scenarios. As a basic development, this kind of API should be packaged in advance and stored as a tool class. Easy to use when team members subscribe to messages.

In most cases, subscription messages are just configuration items and mediation methods. The front end only needs to call the API of wechat, and then notify the specific model of subscription to the back end. The back end sends the corresponding template data through the request interface sent after subscription.

The standard belongs to the sharing article, does not involve too many complex knowledge points, most of the front end does not exist reading obstacles.

Wechat small program & TaroJS

For TaroJS and wechat applet, the code on the ontology will not change too much, so it is generally used in theory. If there is a problem, it is most likely that part of ES API on wechat applet is not supported, and 80% of the problems will be solved by simple Polifill.

Take a look at their API calls:

= > WeChat

  wx.requestSubscribeMessage({
  tmplIds: [' '],
  success (res) { }
})
Copy the code

TaroJS =>

Taro.requestSubscribeMessage({
  tmplIds: [' '].success: function (res) {}})Copy the code

As you can see, both apis are perfectly restored, mostly the same except where the source is inconsistent. Even Taro supports the form of the callback function, which returns a Promise, meaning that we can use the Promise Status callback to make error and successful code callbacks.

It is recommended to use Promise for callbacks in TaroJS. Some interfaces (payment) will throw error after the callback function, resulting in frequent error burying monitoring.

How to configure a Data source

Here, the data source is divided into two parts, one is the current template ID, and the other is the request parameter. Each subscription has at least one template ID and one interface request, which are fixed parameters.

It is recommended to create a config.js to store such things separately.

// config.js
subScriptionTemplateConfig = {
	test: ['templateId']
}

subScriptionRequestConfig = {
	test: [{ a: 1.b: 1}}]Copy the code

Declare entry functions

The onSubscriptionTick entry function, as a call main function, requires the interface to have two array parameters, one is a list of template ids and the other is a list of request parameters. Before we start, we check the parameters. If they don’t match, we throw error and go catch status. If we check them, we subscribe to the message. It is important to note that, in order to make the function less complex, the message subscription also abstracts a method to handle the results of the user subscription

/** * Messages subscribe to the public message class *@param { Array<string> } TemplateId wechat templateId *@param { Array<Object> } ParamList Subscription parameters *@exports utils/onSubscriptionTick
 * @example
 * onSubscriptionTick(['templateid'], [object: OBject]).then()
 * @returns { Promise<any> } Current subscription status */
export async function onSubscriptionTick(templateId = [], paramList = []) {
  if(! templateId) {throw new Error("Throw error: wechat subscription template ID does not exist");
  }

  if(! paramList) {throw new Error("Throw error: wechat subscription request parameter does not exist");
  }

  if(templateId.length ! == paramList.length) {throw new Error("Throw Error: Inconsistent message and request parameters for subscription template");
  }

  const asyncCurrentRequestList = [];
  await subscriptionStatus(templateId)
    .then((res) = > {
      // After the subscription succeeds, a message needs to be sent
      res.forEach((currentMessage) = > {
        asyncCurrentRequestList.push(
          putSubscribeNews(paramList[currentMessage?.successIndex])
        );
      });

      if (asyncCurrentRequestList.length > 0) {
        promiseAllSettled(asyncCurrentRequestList).then((result) = > {
          for (let index = 0; index < result.length; index++) {
            if (result[index].status === "rejected") {
              throw new Error(
                "Throw Error: Message subscription interface failed, subscription task scheduling failed"); }}return true;
        });
      } else {
        throw new Error("Throw Error: Interface request parameter does not exist");
      }
    })
    .catch((err) = > {
      // Subscribe failed callback
      throw err;
    });
}

Copy the code

Processing of message subscriptions

It should be noted that when there are multiple subscription messages in the small program of wechat, if the user cancels one of them, the ID of the successful subscription message should be filtered to ensure the accuracy of the notification to the back-end interface as much as possible.

There are three messages A,B and C that need to be subscribed, and the user selects the requirements of B and C. At this time, the code needs to do A insist to see which template ID is Accept, and the non-Accept is not A successful subscription. Therefore, we only need to use the key as the value of the template ID attribute to determine whether the following is accept or not.

/** * Handle wechat callback messages *@param { Array<string> } TemplateIds wechat template ID list *@returns { Promise<any> }* /
function subscriptionStatus(templateIds = []) {
	return new Promise((resolve, reject) = > {
		Taro.requestSubscribeMessage({
			tmplIds: templateIds,
		}).then(res= > {
			// Determine the status of the current task
			const successTemplateResult = []
			templateIds.forEach((id, index) = > {
				if (res[id] === 'accept') {
					successTemplateResult.push({
						successId: id,
						successIndex: index,
					})
				}
			})
			// Check whether the length of the subscription ID is greater than 0. If the current allowed subscription ID is 0, the subscription fails
			if (successTemplateResult.length > 0) {
				resolve(successTemplateResult)
			} else {
				reject(new Error('Subscription error: current subscription has no permitted message record'))
			}
		}).catch(err= > {
			// throw error 
			reject(err)
		})
	})
}
Copy the code

Concurrent request, interface status only

Promises adds a new method called Promise.allSettled, which executes multiple promises and consolidates their results and states into a callback, whether settled successfully or not. It’s a very convenient interface, but for compatibility reasons, we decided to implement a Promise task queue by hand. The implementation code is very simple and simply returns as a result. This helps you determine the subscription status.

If an interface request failed when the promise.allSettled result set state is in rejected, then the message is a failed subscription. The user subscribed to the front end message, but the back end never had to send it to him.

/** * promise. allSettled method, *@param { Array<Promise<any>> } Promises Stack of promises to implement *@returns { Promise<Array<any>> } Promise outputs the set */
export function promiseAllSettled(promises) {
	let resultArr = []
	let runtimeCount = 0
	console.log('Currently sent message', promises)
	return new Promise((resolve) = > {
		function finish(){// Execution result
			if (runtimeCount == promises.length){
				resolve(resultArr)
			}
		}
		promises.forEach((promiseTask) = > {
			promiseTask.then((data) = > {
				resultArr.push({
					status: 'fulfilled'.value: data,
				})
				runtimeCount++
				finish()
			}, (data) = > {
				resultArr.push({
					status: 'rejected'.value: data,
				})
				runtimeCount++
				finish()
			})
		})
	})
}
Copy the code

You can optimize it a little bit easier

  • SubscriptionStatus method, in fact, does not need new Promise, just need to make a layer of packaging through async, throw error where errors occur, and return the correct result, it will be more elegant.

  • Why is finally implemented in promiseAllSettled with a callback implementation? After testing, the finally may not be found in the context of some custom computers. Therefore, then & Catch is selected to handle it with better compatibility.

  • The rejected method can also be divided into a special function, and the cyclomatic complexity of this code is around 19, although you can understand it. Do onSubscriptionTick as a main function.

conclusion

The code comes from the team business logic development sharing, the code is not very difficult, mainly if you are developing small programs, in fact, there is no need to write a set of solutions, out of the box, save development time efficiency, fast filtering business logic.

In your free time, grab a cup of coffee and take a closer look at the code. It’s best to understand the current execution logic and basic flow of the Copy code so that you can quickly locate the error.

This share is a small business knowledge, if it is helpful to you can support the author of a thumbs-up oh.