函数式编程 rxjs
SMS messages can reach over 4.5 billion text-enabled devices to notify people about upcoming appointments, emergencies, traffic disruptions, or commercial promotions. Sending SMS messages programmatically enables you to reach many people almost simultaneously. With Twilio Programmable SMS you can create a Node.js application that sends many messages and reports when each of them has been delivered — or not.
SMS消息可以到达超过45亿个启用文本的设备,以通知人们即将到来的约会,紧急情况,交通中断或商业促销。 以编程方式发送SMS消息使您几乎可以同时与许多人联系。 使用Twilio可编程SMS,您可以创建一个Node.js应用程序,该应用程序将在发送或不发送时发送许多消息和报告。
Twilio Programmable SMS includes a helper library for Node.js that makes it easy to interact with the SMS API without having to create and manipulate connections to the API endpoints. Once an SMS message request is created with the helper library its status is emitted as a JavaScript Promise. While that is great for creating a request asynchronously, Promises only resolve once, and the message request will pass through more than one state as it makes its way — or not — to the recipient.
Twilio可编程SMS包括Node.js的帮助程序库,可轻松与SMS API进行交互,而无需创建和操纵与API端点的连接。 使用帮助程序库创建SMS消息请求后,其状态将作为JavaScript Promise发出。 尽管这对于异步创建请求非常有用,但是Promises只解析一次,并且消息请求在传递给接收者时会经过一个以上的状态(无论是否通过)。
You can create a mechanism for monitoring and reporting the status of a message request using ReactiveX for JavaScript (RxJS) Observables, which can emit new results asynchronously as the data from an underlying source changes. By creating an Observable wrapper around each message request and calling the helper library’s status method periodically, you can get message delivery information for each number and asynchronously report the status for each number as it changes.
您可以使用ReactiveX for JavaScript(RxJS) Observables创建一种用于监视和报告消息请求状态的机制,当来自底层源的数据更改时,该机制可以异步发出新结果。 通过围绕每个消息请求创建一个Observable包装器并定期调用帮助程序库的status方法,您可以获得每个数字的消息传递信息,并在每个数字变化时异步报告每个状态。
Important compliance note: There are rules for using SMS messaging and they vary between countries. Familiarize yourself with the rules of the countries in which you’ll be sending messages with the Twilio Regulatory Guidelines for SMS.
重要的合规性说明:使用SMS消息传递有一些规则,各国之间有所不同。 熟悉《 Twilio短信监管条例》中将要发送消息的国家/地区的规则。
了解教程项目 (Understanding the tutorial project)
This tutorial will show you how to create a Node.js application that sends an SMS message to a list of phone numbers and reports the status of each message. You’ll use Twilio Programmable SMS to send the messages by using the Twilio Helper Library for Node.js in your program. You’ll create a RxJS wrapper, a mechanism that enhances existing code with new functionality, around the SMS functionality in the helper library.
本教程将向您展示如何创建一个Node.js应用程序,该应用程序将SMS消息发送到电话号码列表并报告每条消息的状态。 您将使用Twilio可编程SMS通过在程序中使用Node.js的Twilio帮助器库来发送消息。 您将围绕助手库中的SMS功能创建一个RxJS包装器,该机制通过新功能增强现有代码。
You’ll learn how to create an Observable from scratch and how to emit the status of an SMS request with an Observable. You’ll find out how to use the RxJS operators map, distinct, merge, tap, and catchError. You’ll also create a timeout mechanism using the RxJS timer function to abandon status polling when a timeout interval elapses.
您将学习如何从头开始创建Observable,以及如何通过Observable发出SMS请求的状态。 您将了解如何使用RxJS运算符map , distinct , merge , tap和catchError 。 您还将使用RxJS计时器函数创建超时机制,以在超时间隔过去后放弃状态轮询。
先决条件 (Prerequisites)
To accomplish the task in this post you will need the following:
要完成本文中的任务,您将需要以下内容:
Node.js and npm (The Node.js installation will also install npm.)
Node.js和npm (Node.js安装还将安装npm。)
Twilio account (Sign up for free using this link and receive a $10 account credit.)
Twilio帐户(使用此链接免费注册并获得10美元的帐户信用。)
You should also have a working knowledge of the core elements of JavaScript, asynchronous JavaScript mechanics, and ReactiveX programming.
您还应该对JavaScript,异步JavaScript机制和ReactiveX编程的核心元素有一定的了解。
There is a companion repository for this post available on GitHub.
在GitHub上有此文章的配套存储库。
获取您的Twilio帐户凭据 (Getting your Twilio account credentials)
To use the Twilio CLI and interact with the Twilio APIs you’ll need two essential pieces of information from your Twilio Console Dashboard: Account SID and Auth Token. You can find them on the top right hand-side of the dashboard.
要使用Twilio CLI并与Twilio API进行交互,您需要从Twilio控制台仪表板上获得以下两个基本信息:帐户SID和Auth令牌。 您可以在仪表板的右上角找到它们。
These are user secrets, so be sure to store them in a safe place.
这些是用户机密,因此请确保将其存储在安全的地方。
To use your credentials in development, you’ll want to store them as environment variables or in a .env file. If you choose to store them in a file, be sure that the filename is included in your .gitignore file so you don’t inadvertently check them into a public repository. For the purposes of this tutorial, you’ll store your secrets as environment variables.
要在开发中使用凭据,您需要将它们存储为环境变量或.env文件。 如果您选择将它们存储在文件中,请确保文件名包含在.gitignore文件中,以免您无意中将它们检入公共存储库。 在本教程中,您将机密存储为环境变量。
If you are using a Unix-based operating system, such as Linux or macOS, you can set environment variables using the following commands:
如果使用的是基于Unix的操作系统,例如Linux或macOS,则可以使用以下命令设置环境变量:
export TWILIO_ACCOUNT_SID=<your account sid>
export TWILIO_AUTH_TOKEN=<your authentication token>
If you are a Windows user, use the following commands:
如果您是Windows用户,请使用以下命令:
setx TWILIO_ACCOUNT_SID <your account sid>
setx TWILIO_AUTH_TOKEN <your authentication token>
获取Twilio电话号码 (Getting a Twilio Phone Number)
Twilio Programmable SMS messages are sent using Twilio phone numbers, which provide instant access to local, national, mobile, and toll-free phone numbers in more than 100 countries with a developer-friendly API. You can get a Twilio phone number for free as part of your trial account.
Twilio可编程的SMS消息是使用Twilio电话号码发送的,该号码可通过开发人员友好的API即时访问100多个国家/地区中的本地,国家/地区,移动和免费电话号码。 作为试用帐户的一部分,您可以免费获得Twilio电话号码。
Once you’ve created a Twilio account you can get a Twilio phone number using the Twilio CLI.
创建Twilio帐户后,您可以使用Twilio CLI获取Twilio电话号码。
Note: The Twilio CLI is in beta status as of the date of this post. If you’ve previously installed it, be sure you have the latest version by executing the following command:
注意:截至发布之日,Twilio CLI处于beta状态。 如果以前已经安装了它,请通过执行以下命令来确保您具有最新版本:
npm update -g twilio-cli
If you’ve stored your Twilio credentials as environment variables, the Twilio CLI will use them automatically. If you’ve stored them in some other way, you’ll have to login first using the following command:
如果将Twilio凭据存储为环境变量,则Twilio CLI将自动使用它们。 如果以其他方式存储它们,则必须首先使用以下命令登录:
twilio login
To list the phone numbers available for registration, use the following command, substituting the appropriate ISO 3166 alpha-2 country code for “US”, if necessary:
要列出可供注册的电话号码,请使用以下命令,必要时将相应的ISO 3166 alpha-2国家/地区代码替换为“ US”:
twilio api:core:available-phone-numbers:local:list --country-code US
You should see a list similar to the following output:
您应该看到类似于以下输出的列表:
Phone Number Region ISO Country Address Requirements
+13852101305 UT US none
+14077922414 FL US none
+16033712156 NH US none
+16036367116 NH US none
+18312751816 CA US none
+14693316717 TX US none
+18312751822 CA US none
Copy one of the numbers from the list and register it to your Twilio account using the following command:
复制列表中的数字之一,并使用以下命令将其注册到您的Twilio帐户:
twilio api:core:incoming-phone-numbers:create --phone-number="+13852101305"
If your registration attempt is successful, you should see the following:
如果您的注册尝试成功,您应该看到以下内容:
SID Phone Number Friendly Name
PN3ef900000000000000000000000000d9 +13852101305 (385) 210-1305
Once registered, the phone number is available for your use (until you release it using the CLI or Twilio Console). Note that the SID associated with the phone number is a user secret and should be handled securely. Store registered phone number under the TWILIO_PHONE_NUMBER
environment variable in E.164 format.
注册后,您就可以使用该电话号码(直到您使用CLI或Twilio控制台释放它)。 请注意,与电话号码关联的SID是用户密码,应安全处理。 将注册的电话号码以E.164格式存储在TWILIO_PHONE_NUMBER
环境变量下。
If you use Linux, Unix, or macOS:
如果您使用Linux,Unix或macOS:
export TWILIO_PHONE_NUMBER=+1234567890
If you’re Windows user:
如果您是Windows用户:
setx TWILIO_PHONE_NUMBER +1234567890
You can verify the number has been successfully added to your account by sending a test SMS to an SMS-enabled phone number:
您可以通过向启用SMS的电话号码发送测试SMS来验证该号码已成功添加到您的帐户中:
twilio api:core:messages:create --from $TWILIO_PHONE_NUMBER --to "SMS receiver phone number" --body "Hello world"
Note that with a trial account you can only send messages to phone numbers you’ve previously registered to your account. The SMS-enabled phone number you used to sign up for your Twilio account is the first number you’ve registered.
请注意,使用试用帐户时,您只能将消息发送到您先前注册到您的帐户的电话号码。 您用来注册Twilio帐户的启用SMS的电话号码是您注册的第一个电话号码。
The API will return a response similar to the below output to indicate that SMS message has been successfully received and is queued to be sent:
API将返回类似于以下输出的响应,以指示已成功接收SMS消息并将其排队发送:
SID From To Status Direction Date Sent
SM4a447328e80a43ceb8e61dda9f3d4cb6 +13852101305 +16463974810 queued outbound-api null
Within a short time you should receive an SMS message on your phone:
在短时间内,您应该会在手机上收到一条短信:

You can check status of message creation request using the following CLI command:
您可以使用以下CLI命令检查消息创建请求的状态:
twilio api:core:messages:fetch --sid SM4a447328e80a43ceb8e61dda9f3d4cb6
As a result, you will see:
结果,您将看到:
SID From To Status Direction Date Sent
SM4a447328e80a43ceb8e61dda9f3d4cb6 +13852101305 +16463974810 delivered outbound-api Mar 13 2020 14:17:20 GMT+0100
初始化Node.js项目 (Initializing the Node.js project)
Once you’ve registered and tested the phone number, you can initialize the project and its Git repository with a series of command-line instructions.
注册并测试了电话号码后,您可以使用一系列命令行说明来初始化项目及其Git存储库。
Open a console window and execute the following instructions in the directory where you want to create the project directory:
打开控制台窗口,并在要创建项目目录的目录中执行以下说明:
mkdir twilio-sms-rxjs
cd twilio-sms-rxjs
git init
npx license mit > LICENSE
npx gitignore node
npm init -y
git add -A
git commit -m "Initial commit"
You can learn more about initializing Node.js projects in this post by Twilio’s Phil Nash.
您可以在Twilio的Phil Nash的这篇文章中了解有关初始化Node.js项目的更多信息。
Install the dependencies you are going to use:
安装您将要使用的依赖项:
npm install esm rxjs twilio
使用Twilio SMS和Node.js发送您的第一条消息 (Sending your first message with Twilio SMS and Node.js)
Create a sms-basics.js file in the project’s root directory and place the following JavaScript code inside:
在项目的根目录中创建一个sms-basics.js文件,并将以下JavaScript代码放入其中:
import twilio from 'twilio';
const client = twilio(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN);
client.messages.create({
body: 'Hello World!',
from: process.env.TWILIO_PHONE_NUMBER,
to: '+16463974810' //replace this with your registered phone number
})
.then(result => {
console.log(result);
return result.sid;
})
.then(sid => client.messages(sid).fetch())
.then(console.log);
The program flow for the code above is depicted in the following diagram:
下图描述了以上代码的程序流程:

The program starts with the initialization of the Twilio client using your Twilio Account SID and Auth Token loaded from the environment variables. Once the client
is initialized you can send a message with Twilio Programmable SMS API. To do that you’ve called a client.messages.create
method and passed to it an object containing the message body body
, recipient to
and sender from
.
该程序从使用环境变量加载的Twilio帐户SID和身份验证令牌开始,初始化Twilio客户端。 初始化client
,您可以使用Twilio可编程SMS API发送消息。 要做到这一点你叫client.messages.create
方法,并传递给它包含消息体的对象body
,受体to
和发件人from
。
The client.messages.create
method of the Twilio helper library returns a Promise object which resolves with the results of the SMS creation request sent to the Twilio Programmable SMS API, shown in green on the diagram. You’ve sent it to the console with the first console.log
statement:
Twilio帮助器库的client.messages.create
方法返回一个Promise对象,该对象用发送到Twilio可编程SMS API的SMS创建请求的结果来解决,该图以绿色显示。 您已使用第一个console.log
语句将其发送到控制台:
{ accountSid: 'xxxxxx',
apiVersion: '2010-04-01',
body: 'Hello World!',
dateCreated: 2020-02-27T21:22:57.000Z,
dateUpdated: 2020-02-27T21:22:57.000Z,
dateSent: null,
direction: 'outbound-api',
errorCode: null,
errorMessage: null,
from: '+xxxxxxxxx',
messagingServiceSid: null,
numMedia: '0',
numSegments: '1',
price: null,
priceUnit: 'USD',
sid: 'SM926d88f994c946f3872011524e20272b',
status: 'queued',
subresourceUris:
{ media:
'/2010-04-01/Accounts/ACe52e8ee9a0993322ce10707c978721fa/Messages/SM926d88f994c946f3872011524e20272b/Media.json' },
to: '+16463974810',
uri:
'/2010-04-01/Accounts/ACe52e8ee9a0993322ce10707c978721fa/Messages/SM926d88f994c946f3872011524e20272b.json' }
From the above data, you’ve picked up a sid
value, which is a unique identifier of your request, and passed it to the next link in the promise chain. In the chained function you’ve invoked the client.messages.fetch
method, which returns another Promise. That Promise resolves with the current status of the SMS creation request, shown in blue on the diagram. In the last then
you’ve printed that result to the console.
从上面的数据中,您获得了一个sid
值(它是请求的唯一标识符),并将其传递到promise链中的下一个链接。 在链接的函数中,您调用了client.messages.fetch
方法,该方法返回另一个Promise。 该承诺将以SMS创建请求的当前状态来解决,该状态在图中以蓝色显示。 在过去then
你打印出的结果到控制台。
Ensure you’ve set up the environment variables TWILIO_ACCOUNT_SID
, TWILIO_AUTH_TOKEN
, and TWILIO_PHONE_NUMBER
and run the program:
确保已设置环境变量TWILIO_ACCOUNT_SID
, TWILIO_AUTH_TOKEN
和TWILIO_PHONE_NUMBER
并运行程序:
node -r esm sms-basics.js
Your console output should be similar to:
您的控制台输出应类似于:
{ accountSid: 'ACe52e8ee9a0993322ce10707c978721fa',
apiVersion: '2010-04-01',
body: 'Hello World!',
dateCreated: 2020-03-22T12:54:49.000Z,
dateUpdated: 2020-03-22T12:54:49.000Z,
dateSent: null,
direction: 'outbound-api',
errorCode: null,
errorMessage: null,
from: '+14252797117',
messagingServiceSid: null,
numMedia: '0',
numSegments: '1',
price: null,
priceUnit: 'USD',
sid: 'SM01a388f69dda4b0da4cffb24fb17b290',
status: 'queued',
subresourceUris:
{ media:
'/2010-04-01/Accounts/ACe52e8ee9a0993322ce10707c978721fa/Messages/SM01a388f69dda4b0da4cffb24fb17b290/Media.json' },
to: '+16463974810',
uri:
'/2010-04-01/Accounts/ACe52e8ee9a0993322ce10707c978721fa/Messages/SM01a388f69dda4b0da4cffb24fb17b290.json' }
{ accountSid: 'ACe52e8ee9a0993322ce10707c978721fa',
apiVersion: '2010-04-01',
body: 'Hello World!',
dateCreated: 2020-03-22T12:54:49.000Z,
dateUpdated: 2020-03-22T12:54:49.000Z,
dateSent: 2020-03-22T12:54:49.000Z,
direction: 'outbound-api',
errorCode: null,
errorMessage: null,
from: '+14252797117',
messagingServiceSid: null,
numMedia: '0',
numSegments: '1',
price: '-0.00750',
priceUnit: 'USD',
sid: 'SM01a388f69dda4b0da4cffb24fb17b290',
status: 'sent',
subresourceUris:
{ media:
'/2010-04-01/Accounts/ACe52e8ee9a0993322ce10707c978721fa/Messages/SM01a388f69dda4b0da4cffb24fb17b290/Media.json',
feedback:
'/2010-04-01/Accounts/ACe52e8ee9a0993322ce10707c978721fa/Messages/SM01a388f69dda4b0da4cffb24fb17b290/Feedback.json' },
to: '+16463974810',
uri:
'/2010-04-01/Accounts/ACe52e8ee9a0993322ce10707c978721fa/Messages/SM01a388f69dda4b0da4cffb24fb17b290.json' }
If you haven’t been following along with the coding and want to catch up to this step using the code from the GitHub repository, execute the following commands in the directory where you’d like to create the project directory:
如果您还没有遵循编码要求,并且想使用GitHub存储库中的代码来完成此步骤,请在您要创建项目目录的目录中执行以下命令:
git clone https://github.com/maciejtreder/twilio-sms-rxjs.git
cd twilio-sms-rxjs
git checkout step1
npm install
使用RxJS Observables包装器将SMS消息发送到多个电话号码并监视消息状态 (Sending SMS messages to multiple phone numbers and monitoring message status with an RxJS Observables wrapper)
Now that you’ve got Twilio SMS basics under your belt you can create an RxJS wrapper for the Twilio SMS API which is a part of the twilio
library.
现在您已经掌握了Twilio SMS的基础知识,您可以为Twilio SMS API创建一个RxJS包装器,它是twilio
库的一部分。
Create a new file called rxjs-twilio.js in the project root directory. Start coding from introducing import statements and initializing the Twilio client by inserting the following code:
在项目根目录中创建一个名为rxjs-twilio.js的新文件。 从引入导入语句开始代码,并通过插入以下代码初始化Twilio客户端:
import { Subject, timer } from 'rxjs';
import { distinct } from 'rxjs/operators';
import twilio from 'twilio';
const client = twilio(process.env.ACCOUNT_SID, process.env.AUTH_TOKEN);
Define the sendSMS
function, which is an entry point of the rxjs-twilio
file. Insert the following JavaScript code at the bottom of the rxjs-twilio.js file:
定义sendSMS
函数,它是rxjs-twilio
文件的入口。 在rxjs-twilio.js文件的底部插入以下JavaScript代码:
export function sendSMS(phoneNumber, body) {
const subject = new Subject();
client.messages.create({
body: body,
from: process.env.TWILIO_PHONE_NUMBER,
to: phoneNumber
})
.then(msg => {
subject.next(msg);
pollStatus(msg.sid, subject, 20); // to be done
}).catch(error => {
subject.error(error);
});
return subject.pipe(distinct(response => response.status));
}
The sendSMS
function accepts two parameters: the recipient’s phone number and the message body. A constant subject
represents the Observable that is returned by the function. Subject
is one of the implementations of the Observable
interface.
sendSMS
函数接受两个参数:收件人的电话号码和消息正文。 常量subject
表示该函数返回的Observable。 Subject
是Observable
接口的实现之一。
The client.messages.create
function creates an SMS message creation request through the Twilio API. When the Promise returned by the client.messages.create
function resolves, the status of the creation request is emitted through the subject
Observable.
client.messages.create
函数通过Twilio API创建SMS消息创建请求。 当client.messages.create
函数返回的Promise解析后,通过subject
Observable发出创建请求的状态。
The pollStatus
method, which you’ll implement next, monitors the state of the Observable returned by the Twilio helper library. If the message creation request sent to the Twilio SMS API fails, the error is emitted through the subject
Observable inside the catch
block.
接下来将实现的pollStatus
方法监视Twilio帮助程序库返回的Observable的状态。 如果发送到Twilio SMS API的消息创建请求失败,则会通过catch
块内的subject
Observable发出错误。
The sendSMS
function uses the distinct
operator to avoid emitting a duplicate status value. If the message status has not changed from one invocation of pollStatus
to the next.
所述sendSMS
函数使用distinct
操作者,以避免发光重复状态值。 如果消息状态没有从pollStatus
一次调用pollStatus
为下一次。
Insert the following code at the bottom of the rxjs-twilio.js file:
在rxjs-twilio.js文件的底部插入以下代码:
const messageDeliveryStatuses = [`delivered`, `undelivered`, `failed`];
let stopPolling = [];
function pollStatus(sid, subject, timeout = 20, watchdog = null) {
if (!watchdog) {
watchdog = timer(timeout * 1000).subscribe(() => stopPolling[sid] = true);
}
client.messages(sid).fetch().then(response => {
subject.next(response);
if (messageDeliveryStatuses.includes(response.status) || stopPolling[sid]) {
subject.complete();
watchdog.unsubscribe();
stopPolling.splice(sid);
} else {
pollStatus(sid, subject, null, watchdog);
}
});
}
The constant messageDeliveryStatuses
is an array of strings representing the Finalized Message Delivery Status values for a message.
常量messageDeliveryStatuses
是一个字符串数组,表示消息的最终消息传递状态值。
The stopPolling
array will contain a dictionary of flags indicating if the polling timeout has elapsed for each pending SMS message request. This is necessary because the “sent” status can indicate either that the message is in the process of being delivered or it was delivered and Twilio did not receive a delivery confirmation, or other status, from the carrier.
stopPolling
数组将包含一个标志字典,该标志指示每个未决SMS消息请求的轮询超时是否已经过去。 这是必要的,因为“已发送”状态可以指示该消息正在传递中,或者已被传递,并且Twilio尚未从运营商处收到传递确认或其他状态。
The pollStatus
function accepts up to four parameters, the last two are optional:
pollStatus
函数最多接受四个参数,最后两个是可选的:
sid
– the ID of the message creation request to pollsid
–要轮询的消息创建请求的IDsubject
– the status of the message creation requestsubject
–消息创建请求的状态timeout
– the time, in seconds, after which polling should stoptimeout
–时间(以秒为单位),之后应停止轮询watchdog
– the subscription of an Observable created with thetimer
method, which determine when to flip the flag in thestopPolling
array to true for the associated message IDwatchdog
–使用timer
方法创建的Observable的预订,该方法确定何时将关联消息ID的stopPolling
数组中的标志翻转为true
If the status of your message creation request changes to one of the messageDeliveryStatuses
values or the stopPolling[sid]
flag is set to true, the unsubscribe
method abandons the watchdog and cleans up the callback queue and the splice
method removes the entry from the stopPolling
dictionary to avoid creating a memory leak.
如果您的消息创建请求的状态更改为messageDeliveryStatuses
值之一,或者将stopPolling[sid]
标志设置为true,则unsubscribe
方法将放弃看门狗并清理回调队列,而splice
方法将从stopPolling
词典中删除该条目。以避免造成内存泄漏。
If the request status is not one of the finalized delivery status values the pollStatus
function is called recursively. To avoid setting up a new watchdog for each recursive execution of the function in the inner pollStatus
invocations, the existing watchdog
is passed as an argument in the else
clause.
如果请求状态不是最终的交付状态值之一, pollStatus
以递归方式调用pollStatus
函数。 为避免在内部pollStatus
调用中为函数的每次递归执行设置新的看门狗,将现有的watchdog
作为参数传递给else
子句。
The client.messages(sid).fetch()
method returns a Promise that resolves with an object representing the state of each SMS request. When the Promise resolves, the result is emitted through the subject
Observable, which was passed as a parameter from the sendSMS
function.
client.messages(sid).fetch()
方法返回一个Promise,该Promise使用表示每个SMS请求状态的对象进行解析。 当Promise解析后,结果通过subject
Observable发出,该subject
作为参数从sendSMS
函数传递。
The wrapper flow is depicted in the diagram below:
包装流程如下图所示:

测试RxJS Observables包装器 (Testing the RxJS Observables wrapper)
To put the Observables wrapper to use and see how it handles an unpredictable sequence of responses from the SMS API, you’ll need a program to iterate through a series of phone numbers and gather the Observables from each number into a collection. Then you can report on the status of each SMS message each time an Observable in the collection emits new information indicating a change in the status of the associated message request.
要使用Observables包装器并查看其如何处理来自SMS API的不可预测的响应序列,您需要一个程序来迭代一系列电话号码并将每个数字中的Observables收集到一个集合中。 然后,每次集合中的Observable发出指示关联消息请求状态发生变化的新信息时,您就可以报告每个SMS消息的状态。
Create a file called sms.js in the project root and insert the following JavaScript code:
在项目根目录中创建一个名为sms.js的文件,并插入以下JavaScript代码:
import { sendSMS } from './rxjs-twilio';
import { of, merge } from 'rxjs';
import { map, catchError, tap } from 'rxjs/operators';
const phoneNumbers = [
'+15017122661', // Use your registered mobile phone number here
'non-existing',
'+484110677' // Use a landline phone number here
];
const requests = [];
phoneNumbers.forEach(number => {
requests.push(
sendSMS(number, `Hello world!`).pipe(
map(response => {
return { number: number, status: response.status };
}),
catchError(error => of({number: number, status: 'error', details: error})),
map(response => {
response.time = new Date();
return response;
})
)
);
});
merge(...requests).pipe(
tap(() => console.log(`\n-------------------------------\n`))
).subscribe(console.log);
The code creates an array of phone numbers to send an SMS message. It iterates through each element of the array, invoking the sendSMS
function and passing a “Hello World!” message to it along with the phone number.
该代码创建电话号码数组以发送SMS消息。 它遍历数组的每个元素,调用sendSMS
函数并传递“ Hello World!”。 消息以及电话号码。
For testing purposes, use phone numbers that can accept SMS messages, like your registered number. Also include numbers, like landlines, that are valid numbers but can’t accept SMS messages. Include values that aren’t valid phone numbers to test how the program and the API handle invalid data.
为了进行测试,请使用可以接受SMS消息的电话号码,例如您的注册号码。 还包括有效号码,但不能接受SMS消息,例如座机号码。 包含不是有效电话号码的值,以测试程序和API如何处理无效数据。
The Observable returned by the sendSMS
is piped to the following operators:
sendSMS
返回的Observable通过管道传递给以下运算符:
map
removes some information from the Twilio API response, leaving only the phone number and current statusmap
从Twilio API响应中删除了一些信息,仅保留了电话号码和当前状态catchError
catches errors that eventually occur and returns an Observable emitting the identity of the request that failed and the failure reasoncatchError
捕获最终发生的错误,并返回一个Observable,发出失败的请求的标识和失败原因map
adds a timestamp to the response.map
将时间戳添加到响应。
Each Observable returned by sendSMS
is pushed to the requests
array, which is then passed as a parameter to the merge
method to consolidate the array into one Observable.
sendSMS
返回的每个Observable均被推送到requests
数组,然后将其作为参数传递给merge
方法,以将该数组合并为一个Observable。
The consolidated Observable is piped through the tap function, which performs a side action every time a new result is emitted by the Observable, creating a line in the output between each set of results as one of the SMS message requests is updated.
合并的Observable通过Tap函数通过管道传输,该函数在Observable每次发出新结果时都会执行副作用,从而在更新一组SMS消息请求时,在每组结果之间的输出中创建一行。
The action performed by the subscribe
operator sends the results emitted by the Observable to the console.
subscribe
操作员执行的操作会将Observable发出的结果发送到控制台。
Run the program:
运行程序:
node -r esm sms.js
The output should be similar to:
输出应类似于:
{ number: 'non-existing',
status: 'error',
details:
{ Error: The 'To' number is not a valid phone number.
status: 400,
message: 'The \'To\' number is not a valid phone number.',
code: 21211,
moreInfo: 'https://www.twilio.com/docs/errors/21211',
detail: undefined },
time: 2020-04-02T18:52:55.532Z }-------------------------------{ number: '+484110677',
status: 'error',
details:
{ Error: The 'To' number +484110677 is not a valid phone number.
status: 400,
message: 'The \'To\' number +484110677 is not a valid phone number.',
code: 21211,
moreInfo: 'https://www.twilio.com/docs/errors/21211',
detail: undefined },
time: 2020-04-02T18:52:55.538Z }-------------------------------{ number: '+15017122661',
status: 'queued',
time: 2020-04-02T18:52:55.593Z }-------------------------------{ number: '+15017122661',
status: 'sent',
time: 2020-04-02T18:52:56.194Z }-------------------------------{ number: '+15017122661',
status: 'delivered',
time: 2020-04-02T18:52:56.818Z }
The output shows the status of three message creation requests to the Twilio Programmable SMS API through the helper library for Node.js. Whenever the status of any of the requests changes, new output is produced.
输出显示了通过Node.js的帮助程序库对Twilio可编程SMS API的三个消息创建请求的状态。 每当任何请求的状态更改时,都会产生新的输出。
Two of the phone numbers used in the sample code are not able to receive SMS, so the API will return error messages. Those types of errors will usually be returned right away.
示例代码中使用的两个电话号码无法接收SMS,因此API将返回错误消息。 这些类型的错误通常会立即返回。
For phone numbers capable of receiving SMS, the Observable will usually emit data three times because the message request will have three states: queued, sent, and delivered. The exception to this will be when the message can’t be delivered, such as when the phone is turned off, or the carrier doesn’t return a response to Twilio. In those cases the final state will be “sent”.
对于能够接收SMS的电话号码,Observable通常将发出三次数据,因为消息请求将具有三种状态:排队,发送和传递。 例外情况是无法发送消息时(例如,手机关闭时),或者运营商未将响应返回给Twilio。 在这些情况下,最终状态将为“已发送”。
If you haven’t been following along with the coding and want to catch up to this step using the code from the GitHub repository, execute the following commands in the directory where you’d like to create the project directory:
如果您还没有遵循编码要求,并且想使用GitHub存储库中的代码来完成此步骤,请在您要创建项目目录的目录中执行以下命令:
git clone https://github.com/maciejtreder/twilio-sms-rxjs.git
cd twilio-sms-rxjs
git checkout step2
npm install
概要 (Summary)
This post introduced you to using Twilio Programmable SMS with RxJS Observables in a Node.js application. You’ve learned how to perform repetitive API calls and emit responses with Observables. You saw how to combine three Observables to create a new one that emits data whenever one of the inner Observable emits data. Using these techniques you can get updates on the delivery status of SMS messages sent with Twilio Programmable SMS.
这篇文章向您介绍了如何在Node.js应用程序中将Twilio可编程SMS与RxJS Observables一起使用。 您已经了解了如何执行重复的API调用以及如何通过Observables发出响应。 您已经了解了如何组合三个Observable来创建一个新的,只要内部Observable中的一个发出数据,它就会发出数据。 使用这些技术,您可以更新通过Twilio可编程SMS发送的SMS消息的传递状态。
其他资源 (Additional Resources)
Twilio Programmable SMS — Send and receive text messages globally with the API that over a million developers depend on.
Twilio可编程SMS —使用超过一百万开发人员所依赖的API在全球范围内发送和接收文本消息。
ReactiveX introductions and tutorials — The ReactiveX website has an extensive list of resources for learning more about Reactive Programming and the various language implementations. They’re 3rd-party productions, so watch and read at your own discretion.
ReactiveX简介和教程— ReactiveX网站上有大量资源列表,可用于学习有关Reactive编程和各种语言实现的更多信息。 它们是第三方制作的,因此请您自行观看和阅读。
RxJS — The RxJS website is the place for canonical information about the ReactiveX library for JavaScript.
RxJS — RxJS网站是有关ReactiveX JavaScript库的规范信息的地方。
Which Operator do I use? — A helpful tool for choosing the best Observables operator for a desired action.
我要使用哪个运营商? —一个有用的工具,用于为期望的操作选择最佳的Observables运算符。
If you want to learn more about JavaScript Promises, which are a better asynchronous tool for some programming situations, check out the following posts:
如果您想了解有关JavaScript Promises(对于某些编程情况而言是更好的异步工具)的更多信息,请查看以下文章:
Asynchronous JavaScript: Introduction to JavaScript Promises
If you’d like to learn more about RxJS Observables, check out this post:
如果您想了解有关RxJS Observables的更多信息,请查看以下文章:
Ready for more messaging excitement? Try some Programmable SMS missions in TwilioQuest!
准备更多的消息激动了吗? 在TwilioQuest中尝试一些可编程的SMS任务!
I’m Maciej Treder, contact me via contact@maciejtreder.com, https://www.maciejtreder.com or @maciejtreder on GitHub, Twitter and LinkedIn.
我马切伊Treder,通过接触我contact@maciejtreder.com , https://www.maciejtreder.com或@maciejtreder在GitHub上, Twitter的和LinkedIn 。
This post is originally published on the Twilio Blog.
该帖子最初发布在Twilio博客上。
函数式编程 rxjs