在这篇文章中,我们将为您详细介绍Angular客户端和后端python-socketio的内容,并且讨论关于angular如何和后端交互的相关问题。此外,我们还会涉及一些关于AndroidNDKSoc
在这篇文章中,我们将为您详细介绍Angular 客户端和后端 python - socket io的内容,并且讨论关于angular如何和后端交互的相关问题。此外,我们还会涉及一些关于Android NDK Socket(POSIX Socket Api)编程、Angular 12.0.5 HMR 不工作,不重新加载模块,不重新加载页面实时重新加载,Angular 11.0.6 重新加载整个页面 调查 Angular 构建系统使用的版本配置 webpack使用 Angular 12.0.5 / next.6 时 - 没有帮助、angular j j angular j angular angular service service service j、Angular 学习系列 - - angular.bind、angular.bootstrap、angular.copy的知识,以帮助您更全面地了解这个主题。
本文目录一览:- Angular 客户端和后端 python - socket io(angular如何和后端交互)
- Android NDK Socket(POSIX Socket Api)编程
- Angular 12.0.5 HMR 不工作,不重新加载模块,不重新加载页面实时重新加载,Angular 11.0.6 重新加载整个页面 调查 Angular 构建系统使用的版本配置 webpack使用 Angular 12.0.5 / next.6 时 - 没有帮助
- angular j j angular j angular angular service service service j
- Angular 学习系列 - - angular.bind、angular.bootstrap、angular.copy
Angular 客户端和后端 python - socket io(angular如何和后端交互)
如何解决Angular 客户端和后端 python - socket io
我在 python 中有我的服务器
from flask import Flask,render_template,jsonify
from flask_socketio import SocketIO,emit
app = Flask(__name__)
socketio = SocketIO(app,cors_allowed_origins="*")
import time
@socketio.on(''connect'')
def test_connect():
emit(''data'',{"tag" :"message"})
value_changed()
def value_changed():
emit(''data'',{"tag" :"message"})
time.sleep(3000)
while True:
value_changed()
if __name__ == ''__main__'':
socketio.run(app,host=''0.0.0.0'',port=3000)
我的客户端代码在 angular 11 中运行
import { Component,OnInit } from ''@angular/core'';
import {io} from ''socket.io-client'';
const socket = io(''http://127.0.0.1:3000'');
@Component({
selector: ''app-root'',templateUrl: ''./app.component.html'',styleUrls: [''./app.component.css'']
})
export class AppComponent implements OnInit {
ngOnInit() {
console.log("Data**..");
socket.on(''data'',(res) => {
console.log("Data 1",res)
})
}
}
angular 和后端服务器都已启动并且 当我加载浏览器时,我可以看到网络选项卡中发生的呼叫没有打印控制台日志
enter image description here
为什么控制台日志没有打印在控制台中。 我究竟做错了什么。 请帮忙!!
Android NDK Socket(POSIX Socket Api)编程
socket简介
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。
tcpsocket和udpsocket的具体实现
讲了这么久,终于要开始讲socket的具体实现了,iOS提供了Socket网络编程的接口CFSocket,不过这里使用BSD Socket。
tcp和udp的socket是有区别的,这里给出这两种的设计框架
基本TCP客户—服务器程序设计基本框架
基本UDP客户—服务器程序设计基本框架流程图
这里我们利用Linux C POSIX Socket API进行NDK Socket编程
AbstractEchoActivity
package com.apress.echo;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ScrollView;
import android.widget.TextView;
/**
* 客户端和服务端的抽象父类 共同有一个启动按钮,显示日志的TextView,端口设置EditText
*
*/
public abstract class AbstractEchoActivity extends Activity implements
OnClickListener {
protected static final int TCP = 1;
protected static final int UDP = 2;
protected EditText editPort;// Port number
protected Button btnStart;// server button
protected ScrollView scrollLog;//
protected TextView tvLog;// log view
private final int layoutID;
public AbstractEchoActivity(int layoutID) {
this.layoutID = layoutID;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(layoutID);
editPort = (EditText) findViewById(R.id.port_edit);
btnStart = (Button) findViewById(R.id.start_button);
scrollLog = (ScrollView) findViewById(R.id.scroll_view);
tvLog = (TextView) findViewById(R.id.log_view);
btnStart.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v == btnStart) {
onStartButtonClicked();
} else {
Log.v("onClick", "onClick no done.");
}
}
/**
* 获取端口
*
* @return
*/
protected Integer getPort() {
Integer port;
try {
port = Integer.valueOf(editPort.getText().toString());
} catch (Exception e) {
e.printStackTrace();
port = null;
}
return port;
}
protected void logMessage(final String message) {
runOnUiThread(new Runnable() {
@Override
public void run() {
logMessageDirect(message);
}
});
}
protected void logMessageDirect(final String message) {
tvLog.append(message);
tvLog.append("\n");
scrollLog.fullScroll(View.FOCUS_DOWN);
}
protected abstract void onStartButtonClicked();
/**
* 这个thread抽象出onBackground()方法作为线程的执行方法,在启动前先设置控件状态为不可用,同时清空日志。执行完毕后设置控件可用。
*
*/
protected abstract class AbstractEchoTask extends Thread {
private final Handler handler;
public AbstractEchoTask() {
handler = new Handler();
}
protected void onPreExecute() {
btnStart.setEnabled(false);
// 清空日志
tvLog.setText("");
}
/*
*
*/
@Override
public synchronized void start() {
// 这里start是由主线程来调用的。调用之前先设置控件状态。
onPreExecute();
super.start();
}
@Override
public void run() {
// run是在新线程中运行的
onBackground();
// 用handler来修改控件
handler.post(new Runnable() {
@Override
public void run() {
onPostExecute();
}
});
}
/**
* 线程的执行体
*/
protected abstract void onBackground();
/**
*
*/
protected void onPostExecute() {
btnStart.setEnabled(true);
}
}
static {
System.loadLibrary("Echo");
}
}
客户端 EchoClientActivity
package com.apress.echo;
import android.os.Bundle;
import android.widget.EditText;
public class EchoClientActivity extends AbstractEchoActivity {
private EditText editIp;
private EditText editMessage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
editIp = (EditText) findViewById(R.id.ip_edit);
editMessage = (EditText) findViewById(R.id.message_edit);
}
public EchoClientActivity() {
super(R.layout.activity_echo_client);
}
@Override
protected void onStartButtonClicked() {
String ip = editIp.getText().toString();
Integer port = getPort();
String message = editMessage.getText().toString();
if (0 != ip.length() && port != null && (0 != message.length())) {
new ClientTask(ip, port, message).start();
}
}
private native void nativeStartTcpClient(String ip, int port, String message)
throws Exception;
private class ClientTask extends AbstractEchoTask {
private final String ip;
private final int port;
private final String message;
public ClientTask(String ip, int port, String message) {
this.ip = ip;
this.port = port;
this.message = message;
}
@Override
protected void onBackground() {
logMessage("Starting client");
try {
nativeStartTcpClient(ip, port, message);
} catch (Exception e) {
logMessage(e.getMessage());
}
logMessage("Client terminated.");
}
}
}
服务端SocketServer
EchoServerActivity
package com.apress.echo;
public class EchoServerActivity extends AbstractEchoActivity {
public EchoServerActivity() {
super(R.layout.activity_echo_server);
}
@Override
protected void onStartButtonClicked() {
Integer port = getPort();
if (port != null) {
new ServerTask(port, TCP).start();
} else {
logMessage("port error");
}
}
/**
* 启动tcp服务
*
* @param port
* @throws Exception
*/
private native void nativeStartTcpServer(int port) throws Exception;
/**
* 启动udp服务
*
* @param port
* @throws Exception
*/
private native void nativeStartUdpServer(int port) throws Exception;
private class ServerTask extends AbstractEchoTask {
private final int port;
private final int protocol;
/**
* @param port端口
* @param protocol
* 使用的协议
*/
public ServerTask(int port, int protocol) {
this.port = port;
this.protocol = protocol;
}
@Override
protected void onBackground() {
logMessage("Starting server.");
logMessage("server ip:" + Commons.getIpAddress());
try {
if (protocol == TCP) {
nativeStartTcpServer(port);
} else if (protocol == UDP) {
nativeStartUdpServer(port);
} else {
logMessage("protocol error.");
}
} catch (Exception e) {
logMessage(e.getMessage());
}
logMessage("Server terminated.");
}
}
}
清单文件
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.apress.echo"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<!-- 服务端app -->
<!-- <activity -->
<!-- android:name=".EchoServerActivity" -->
<!-- android:label="@string/title_activity_echo_server" -->
<!-- android:launchMode="singleTop" > -->
<!-- <intent-filter> -->
<!-- <action android:name="android.intent.action.MAIN" /> -->
<!-- <category android:name="android.intent.category.LAUNCHER" /> -->
<!-- </intent-filter> -->
<!-- </activity> -->
<!-- 客户端app -->
<activity
android:name=".EchoClientActivity"
android:label="@string/title_activity_echo_client"
android:launchMode="singleTop" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
实现NDK编程
native接口文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_apress_echo_EchoServerActivity */
#ifndef _Included_com_apress_echo_EchoServerActivity
#define _Included_com_apress_echo_EchoServerActivity
#ifdef __cplusplus
extern "C" {
#endif
#undef com_apress_echo_EchoServerActivity_TCP
#define com_apress_echo_EchoServerActivity_TCP 1L
#undef com_apress_echo_EchoServerActivity_UDP
#define com_apress_echo_EchoServerActivity_UDP 2L
/*
* Class: com_apress_echo_EchoServerActivity
* Method: nativeStartTcpServer
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_com_apress_echo_EchoServerActivity_nativeStartTcpServer
(JNIEnv *, jobject, jint);
/*
* Class: com_apress_echo_EchoServerActivity
* Method: nativeStartUdpServer
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_com_apress_echo_EchoServerActivity_nativeStartUdpServer
(JNIEnv *, jobject, jint);
#ifdef __cplusplus
}
#endif
#endif
实现native Socket
SocketTool.cpp
#include <stdio.h>
#include <stdarg.h>
//errno
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
//sockaddr_un
#include <sys/un.h>
//htons,sockaddr_in
#include <netinet/in.h>
//inet_ntop
#include <arpa/inet.h>
//close,unlink
#include <unistd.h>
//offsetof
#include <stddef.h>
#ifndef __SOCKET_UTILS__
#define __SOCKET_UTILS_
//MAX log message length
#define MAX_LOG_MESSAGE_LENGTH 256
//MAX data buffer size
#define MAX_BUFFER_SIZE 80
//打印日志到java环境中
static void LogMessage(JNIEnv* env, jobject obj, const char* format, ...) {
//cache log method ID
static jmethodID methodID = NULL;
if (methodID == NULL) {
jclass clazz = env->GetObjectClass(obj);
methodID = env->GetMethodID(clazz, "logMessage",
"(Ljava/lang/String;)V");
env->DeleteLocalRef(clazz);
}
if (methodID != NULL) {
char buffer[MAX_BUFFER_SIZE];
//将可变参数输出到字符数组中
va_list ap;
va_start(ap, format);
vsnprintf(buffer, MAX_LOG_MESSAGE_LENGTH, format, ap);
va_end(ap);
//转换成java字符串
jstring message = env->NewStringUTF(buffer);
if (message != NULL) {
env->CallVoidMethod(obj, methodID, message);
env->DeleteLocalRef(message);
}
}
}
//通过异常类和异常信息抛出异常
static void ThrowException(JNIEnv* env, const char* className,
const char* message) {
jclass clazz = env->FindClass(className);
if (clazz != NULL) {
env->ThrowNew(clazz, message);
env->DeleteLocalRef(clazz);
}
}
//通过异常类和错误号抛出异常
static void ThrowErrnoException(JNIEnv* env, const char* className,
int errnum) {
char buffer[MAX_LOG_MESSAGE_LENGTH];
//通过错误号获得错误消息
if (-1 == strerror_r(errnum, buffer, MAX_LOG_MESSAGE_LENGTH)) {
strerror_r(errno, buffer, MAX_LOG_MESSAGE_LENGTH);
}
ThrowException(env, className, buffer);
}
//sock用到的一些公用方法
//创建一个socket:socket()
static int NewTcpSocket(JNIEnv* env, jobject obj) {
LogMessage(env, obj, "Constructing a new TCP socket...");
int tcpSocket = socket(PF_INET, SOCK_STREAM, 0);
if (-1 == tcpSocket) {
ThrowErrnoException(env, "java/io/IOException", errno);
}
return tcpSocket;
}
//绑定 bind()
static void BindSocketToPort(JNIEnv* env, jobject obj, int sd,
unsigned short port) {
struct sockaddr_in address;
//清空结构体
memset(&address, 0, sizeof(address));
address.sin_family = PF_INET;
//Bind to all address
address.sin_addr.s_addr = htonl(INADDR_ANY);
//Convert port to network byte order
address.sin_port = htons(port);
//Bind socket
LogMessage(env, obj, "Binding to port %hu.", port);
//sockaddr方便函数传递, sockaddr_in方便用户设定, 所以需要的时候在这2者之间进行转换
if (-1 == bind(sd, (struct sockaddr*) &address, sizeof(address))) {
ThrowErrnoException(env, "java/io/IOException", errno);
}
}
//返回当前socket绑定的端口
static unsigned short GetSocketPort(JNIEnv* env, jobject obj, int sd) {
unsigned short port = 0;
struct sockaddr_in address;
socklen_t addressLength = sizeof(address);
if (-1 == getsockname(sd, (struct sockaddr*) &address, &addressLength)) {
ThrowErrnoException(env, "java/io/IOException", errno);
} else {
port = ntohs(address.sin_port);
LogMessage(env, obj, "Binding to the random port %hu.", port);
}
return port;
}
//监听 listen()
static void ListenOnSocket(JNIEnv*env, jobject obj, int sd, int backlog) {
LogMessage(env, obj,
"Listening on socket with a baklog of %d pending connections.",
backlog);
//listen()用来等待参数s 的socket 连线. 参数backlog 指定同时能处理的最大连接要求,
//如果连接数目达此上限则client 端将收到ECONNREFUSED 的错误.
//Listen()并未开始接收连线, 只是设置socket 为listen 模式, 真正接收client 端连线的是accept().
//通常listen()会在socket(), bind()之后调用, 接着才调用accept().
if (-1 == listen(sd, backlog)) {
ThrowErrnoException(env, "java/io/IOException", errno);
}
}
//根据地址打印IP和端口
static void LogAddress(JNIEnv* env, jobject obj, const char* message,
const struct sockaddr_in* address) {
char ip[INET_ADDRSTRLEN];
if (NULL == inet_ntop(PF_INET, &(address->sin_addr), ip, INET_ADDRSTRLEN)) {
ThrowErrnoException(env, "java/io/IOException", errno);
} else {
unsigned short port = ntohs(address->sin_port);
LogMessage(env, obj, "%s %s:%hu", message, ip, port);
}
}
//accept()
static int AcceptOnSocket(JNIEnv* env, jobject obj, int sd) {
struct sockaddr_in address;
socklen_t addressLength = sizeof(address);
LogMessage(env, obj, "Waiting for a client connection...");
int clientSocket = accept(sd, (struct sockaddr*) &address, &addressLength);
if (-1 == clientSocket) {
ThrowErrnoException(env, "java/io/IOException", errno);
} else {
LogAddress(env, obj, "Client connection from ", &address);
}
return clientSocket;
}
//接收 recv()
static ssize_t ReceiveFromSocket(JNIEnv* env, jobject obj, int sd, char* buffer,
size_t bufferSize) {
LogMessage(env, obj, "Receiving from the socket... ");
ssize_t recvSize = recv(sd, buffer, bufferSize - 1, 0);
if (-1 == recvSize) {
ThrowErrnoException(env, "java/io/IOException", errno);
} else {
//字符串截断
buffer[recvSize] = NULL;
if (recvSize > 0) {
//接收成功,打印
LogMessage(env, obj, "Received %d bytes:%s", bufferSize, buffer);
} else {
LogMessage(env, obj, "Client disconnected.");
}
}
return recvSize;
}
//发送消息:send()
static ssize_t SendToSocket(JNIEnv *env, jobject obj, int sd,
const char* buffer, size_t bufferSize) {
LogMessage(env, obj, "Sending to the socket... ");
ssize_t sentSize = send(sd, buffer, bufferSize, 0);
if (-1 == sentSize) {
ThrowErrnoException(env, "java/io/IOException", errno);
} else {
if (sentSize > 0) {
LogMessage(env, obj, "Send %d bytes: %s", sentSize, buffer);
} else {
LogMessage(env, obj, "Client disconnected.");
}
}
return sentSize;
}
//链接到服务器 connect()
static void ConnectToAddress(JNIEnv*env, jobject obj, int sd, const char*ip,
unsigned short port) {
LogMessage(env, obj, "Connecting to %s:%hu...", ip, port);
struct sockaddr_in address;
memset(&address, 0, sizeof(address));
address.sin_family = PF_INET;
//转换ip
if (0 == inet_aton(ip, &(address.sin_addr))) {
ThrowErrnoException(env, "java/io/IOException", errno);
} else {
address.sin_port = htons(port);
}
if (-1 == connect(sd, (const sockaddr*) &address, sizeof(address))) {
ThrowErrnoException(env, "java/io/IOException", errno);
} else {
LogMessage(env, obj, "Connected.");
}
}
//----------------udp
//创建udp socket
static int NewUdpSocket(JNIEnv* env, jobject obj) {
LogMessage(env, obj, "Constructing a new UDP socket...");
int udpSocket = socket(PF_INET, SOCK_DGRAM, 0);
if (-1 == udpSocket) {
ThrowErrnoException(env, "java/io/IOException", errno);
}
return udpSocket;
}
#endif __SOCKET_UTILS_
实现Native 接口
#include <jni.h>
#include "com_apress_echo_EchoServerActivity.h"
#include "com_apress_echo_EchoClientActivity.h"
#include "SocketTool.cpp"
//服务端:启动监听
//流程:socket()->listen()->accept()->recv()->send()_close()
void JNICALL Java_com_apress_echo_EchoServerActivity_nativeStartTcpServer(
JNIEnv *env, jobject obj, jint port) {
int serverSocket = NewTcpSocket(env, obj);
if (NULL == env->ExceptionOccurred()) {
//绑定
BindSocketToPort(env, obj, serverSocket, (unsigned short) port);
if (NULL != env->ExceptionOccurred()) {
goto exit;
}
//如果端口是0,打印出当前随机分配的端口
if (0 == port) {
GetSocketPort(env, obj, serverSocket);
if (NULL != env->ExceptionOccurred()) {
goto exit;
}
}
//监听 链接4
ListenOnSocket(env, obj, serverSocket, 4);
if (NULL != env->ExceptionOccurred()) {
goto exit;
}
//
int clientSocket = AcceptOnSocket(env, obj, serverSocket);
if (NULL != env->ExceptionOccurred()) {
goto exit;
}
char buffer[MAX_BUFFER_SIZE];
ssize_t recvSize;
ssize_t sentSize;
while (1) {
//接收
recvSize = ReceiveFromSocket(env, obj, clientSocket, buffer,
MAX_BUFFER_SIZE);
if ((0 == recvSize) || (NULL != env->ExceptionOccurred())) {
break;
}
//发送
sentSize = SendToSocket(env, obj, clientSocket, buffer,
(size_t) recvSize);
if ((0 == sentSize) || (NULL != env->ExceptionOccurred())) {
break;
}
}
//close the client socket
close(clientSocket);
}
exit: if (serverSocket > 0) {
close(serverSocket);
}
}
//客户端:连接
void JNICALL Java_com_apress_echo_EchoClientActivity_nativeStartTcpClient(
JNIEnv *env, jobject obj, jstring ip, jint port, jstring message) {
int clientSocket = NewTcpSocket(env, obj);
if (NULL == env->ExceptionOccurred()) {
const char* ipAddress = env->GetStringUTFChars(ip, NULL);
if (NULL == ipAddress) {
goto exit;
}
ConnectToAddress(env, obj, clientSocket, ipAddress,
(unsigned short) port);
//释放ip
env->ReleaseStringUTFChars(ip, ipAddress);
//connect exception check
if (NULL != env->ExceptionOccurred()) {
goto exit;
}
const char* messageText = env->GetStringUTFChars(message, NULL);
if (NULL == messageText) {
goto exit;
}
//这里的size不用release??
jsize messageSize = env->GetStringUTFLength(message);
SendToSocket(env, obj, clientSocket, messageText, messageSize);
//
env->ReleaseStringUTFChars(message, messageText);
if (NULL != env->ExceptionOccurred()) {
goto exit;
}
char buffer[MAX_BUFFER_SIZE];
ReceiveFromSocket(env, obj, clientSocket, buffer, MAX_BUFFER_SIZE);
}
exit: if (clientSocket > -1) {
close(clientSocket);
}
}
//启动udp服务端
void JNICALL Java_com_apress_echo_EchoServerActivity_nativeStartUdpServer(
JNIEnv *, jobject, jint) {
}
Angular 12.0.5 HMR 不工作,不重新加载模块,不重新加载页面实时重新加载,Angular 11.0.6 重新加载整个页面 调查 Angular 构建系统使用的版本配置 webpack使用 Angular 12.0.5 / next.6 时 - 没有帮助
如何解决Angular 12.0.5 HMR 不工作,不重新加载模块,不重新加载页面实时重新加载,Angular 11.0.6 重新加载整个页面 调查 Angular 构建系统使用的版本配置 webpack使用 Angular 12.0.5 / next.6 时 - 没有帮助
Angular HMR 不替换/重新加载组件
- 实时重载适用于 11.0.6 和 12.1.0-next.6。
- Angular 12.0.5 根本不会重新加载。
任何人都可以使用它并且可以提供一个有效的示例应用程序?
给定:一个简单的入门应用
(来自故事书 https://github.com/chromaui/intro-storybook-angular-template)
使用 Angular 11.0.6
然后 HMR 开箱即用并不能按预期工作,但完全重新加载可以(即启用 [WDS] 实时重新加载。)
更新到 Angular 12.0.5 时
然后 HMR 不会重新加载任何东西。 (根本没有实时重新加载)
12.0.5 行为:更新角度组件时不重新加载。
控制台错误(chrome):
dev-server.js:60 Uncaught Error: [HMR] Hot Module Replacement is disabled.
at Object.5033 (dev-server.js:60)
at __webpack_require__ (bootstrap:19)
at __webpack_exec__ (polyfills.js:12907)
at polyfills.js:12908
at webpackJsonpCallback (jsonp chunk loading:35)
at polyfills.js:1
编辑组件 (HTML) 后,控制台“卡住”“[WDS] 应用热更新...”
更新到 Angular 12.1.0-next.6 时"
结果与 v11 相同(然后 HMR 开箱即用,但完全重新加载可以(即启用 [WDS] 实时重新加载。)
webpack-dev-server 是原因(可能与 webpack 5.3 一起)
经过一番挖掘,我意识到这与 webpack-dev-server 有关。
- https://github.com/webpack/webpack-dev-server/issues/2758
一个解决方案似乎是将 webpack 目标设置为 web(而不是浏览器)进行开发。或者使用测试版的 webpack-dev-server(即 4.0.0-beta.x)
"target: ''web'',
调查 Angular 构建系统使用的版本
在“node_modules/@angular-devkit/build-webpack/package.json”中使用了 webpack-dev-server。
对于 "@angular-devkit/build-angular": "~12.0.5",webpack-dev-server 版本为 3.11.2
"peerDependencies": { "webpack": "^5.30.0","webpack-dev-server": "^3.11.2" },
将 Angular 更新为 v-next 时 对于 "@angular-devkit/build-angular": "^12.1.0-next.6",webpack-dev-server 版本较低,为 3.1.4,与 ''build-angular'' v11 相同。 (可能是因为他们意识到实时重新加载的问题)
"peerDependencies": { "webpack": "^5.30.0","webpack-dev-server": "^3.1.4" },
使用 Angular 11 时 对于“@angular-devkit/build-angular”:“~0.1100.6”
"peerDependencies": { "webpack": "^4.6.0",
配置 webpack(使用 Angular 12.0.5 / next.6 时) - 没有帮助
根据以下资源配置,使用@angular-builders/custom-webpack
没有帮助。帮助! =D
- https://github.com/just-jeb/angular-builders/tree/master/packages/custom-webpack#Custom-webpack-dev-server
- https://github.com/just-jeb/angular-builders/blob/master/packages/custom-webpack/examples/full-cycle-app/extra-webpack.config.ts
//package.json
"devDependencies": {
"@angular-builders/custom-webpack": "^12.1.0",
//angular.json
//replace "builder" in "build" and "serve"
//add customWebpackConfig with path to a new config file
//"builder": "@angular-devkit/build-angular:browser"
"architect": {
"build": {
"builder": "@angular-builders/custom-webpack:browser","options": {
"customWebpackConfig": {
"path": "extra-webpack.config.ts","replaceDuplicatePlugins": true
},//...
//replace "builder": "@angular-devkit/build-angular:dev-server","serve": {
"builder": "@angular-builders/custom-webpack:dev-server",
//extra-webpack.config.ts
import { Configuration } from "webpack";
export default {
target:"web",// target: process.env.NODE_ENV === "development" ? "web" : "browserslist",} as Configuration;
解决方法
我们有一些与您介绍的类似的东西。您是否删除了 package_lock、node_modules 并进行了全新安装?
在 Angular 11.2.4 和新的 Angular 12.1.4 项目中,使用 HRM 进行设置没有问题。 尝试使用 "@angular-builders/custom-webpack": "12.1.0","@angular-devkit/build-angular": "^12.1.4" 它应该可以工作
angular j j angular j angular angular service service service j
我有一个控制器,我在其中进行以下调用:
mapService.getMapByUuid(mapUUID,isEditor).then(function(datas){ fillMapDatas(datas); }); function fillMapDatas(datas){ if($scope.elements === undefined){ $scope.elements = []; } //Here while debugging my unit test,'datas' contain the promise javascript object instead //of my real reponse. debugger; var allOfThem = _.union($scope.elements,datas.elements); ...
以下是我的服务:
(function () { 'use strict'; var serviceId = 'mapService'; angular.module('onmap.map-module.services').factory(serviceId,[ '$resource','appContext','restHello','restMap',serviceFunc]); function serviceFunc($resource,appContext,restHello,restMap) { var Maps = $resource(appContext+restMap,{uuid: '@uuid',editor: '@editor'}); return{ getMapByUuid: function (uuid,modeEditor) { var maps = Maps.get({'uuid' : uuid,'editor': modeEditor}); return maps.$promise; } }; } })();
最后,这是我的单位测试:
describe('Map controller',function() { var $scope,$rootScope,$httpBackend,$timeout,createController,MapService,$resource; beforeEach(module('onmapApp')); beforeEach(inject(function($injector) { $httpBackend = $injector.get('$httpBackend'); $rootScope = $injector.get('$rootScope'); $scope = $rootScope.$new(); var $controller = $injector.get('$controller'); createController = function() { return $controller('maps.ctrl',{ '$scope': $scope }); }; })); afterEach(function() { $httpBackend.verifyNoOutstandingExpectation(); $httpBackend.verifyNoOutstandingRequest(); }); var response = {"elements":[1,2,3]}; it('should allow user to get a map',function() { var controller = createController(); $httpBackend.expect('GET','/onmap/rest/map/MY-UUID?editor=true') .respond({ "success": response }); // hope to call /onmap/rest/map/MY-UUID?editor=true url and hope to have response as the fillMapDatas parameter $scope.getMapByUUID('MY-UUID',true); $httpBackend.flush(); }); });
我真正想要做的是将我的响应对象({“elements:…})作为fillMapDatas函数的datas参数,我不明白如何模拟所有的服务(服务,承诺,然后)
提前感谢您的帮助
var mapService,$q,$rootScope; beforeEach(inject(function (_mapService_,_$httpBackend_,_$q_,_$rootScope_) { mapService = mapService; $httpBackend = _$httpBackend_; $q = _$q_; $rootScope = _$rootScope_; // expect the actual request $httpBackend.expect('GET','/onmap/rest/map/uuid?editor=true'); // react on that request $httpBackend.whenGET('/onmap/rest/map/uuid?editor=true').respond({ success: { elements: [1,3] } }); }));
您可以看到,您不需要使用$ inject,因为您可以直接注入所需的服务。如果您想在整个测试中使用正确的服务名称,您可以使用前缀和后缀“_”注入它们,注入()足够聪明地识别出您的意思。我们还为每个it()规范设置$ httpBackend mock。并且我们设置$ q和$ rootScope进行后续处理。
以下是您如何测试您的服务方法返回承诺:
it('should return a promise',function () { expect(mapService.getMapUuid('uuid',true).then).tobedefined(); });
由于承诺总是有一个.then()方法,我们可以检查这个属性,看看它是否是一个承诺(当然,其他对象也可以使用这个方法)。
接下来,您可以用适当的价值测试您得到的解决方案的承诺。您可以设置您明确解析的延迟。
it('should resolve with [something]',function () { var data; // set up a deferred var deferred = $q.defer(); // get promise reference var promise = deferred.promise; // set up promise resolve callback promise.then(function (response) { data = response.success; }); mapService.getMapUuid('uuid',true).then(function(response) { // resolve our deferred with the response when it returns deferred.resolve(response); }); // force `$digest` to resolve/reject deferreds $rootScope.$digest(); // make your actual test expect(data).toEqual([something]); });
希望这可以帮助!
Angular 学习系列 - - angular.bind、angular.bootstrap、angular.copy
angular.bind
返回一个调用 self 的函数 fn(self 代表 fn 里的 this). 可以给 fn 提供参数 args(*). 这个功能也被称为局部操作,以区别功能。
格式:angular.bind(self,fn,args);
self:object 对象; fn 的上下文对象,在 fn 中可以用 this 调用
fn:function; 绑定的方法
args:传入 fn 的参数
使用代码:
var obj = { name: "Any" };var fn = function (Adj) {
console.log(this.name + "is a boy!!! And he is " + Adj + " !!!");
};var f = angular.bind(obj, fn, "handsome");
f();//Any is a boy!!! And he is handsome!!!var t = angular.bind(obj, fn);
t("ugly");// Any is a boy!!! And he is ugly!!!
bind 顾名思义绑定的意思,那么假如我们要把 A 绑到 B 上,那么必须又有绑定的东西和被绑定的东西。这里需要的就一个对象和一个函数。那么怎么绑?本兽的理解是把对象 “绑” 到函数的 this 上去执行,这时候 fn 的 this 就等于 obj 了,至于第三个参数,可有可无,看需求,如果函数需要传入参数,那么我们可以把 angular.bind 的第三个参数放上去,这就是传入 fn 函数的参数了。
案例中第一种写法是定义绑定的时候就把 fn 所需的参数传进去了,调用的时候直接用,而案例中第二种写法是先绑定,在调用执行的时候再给 fn 传参,效果是一样的...
angular.bootstrap
使用这个功能来手动启动 angular 应用。基于 ngScenario 的端对端测试不能使用 bootstrap 手动启动,需要使用 ngApp.
Angular 会检测应用在浏览器是否已启动并且只允许第一次的启动,随后的每次启动都将会导致浏览器控制台报错.
这可以防止应用出现多个 Angular 实例尝试在 Dom 上运行的一些奇异结果.
格式:angular.bootstrap(element,[modules]);
element:Dom 元素,angular 应用启动的根节点
modules:数组,angular 的应用程序模块
使用代码:
<div id="ngApp"> <div ng-controller="testCtrl as ctrl"> {{ctrl.value}} </div>
</div>
(function () {
angular.module("Demo", [])
.controller("testCtrl", testCtrl); function testCtrl() { this.value = "Hello World";
}
angular.bootstrap(document.getElementById("ngApp"), ["Demo"]);
}());
一般来说,我们写 ng 程序,都会在页面 Dom 元素上写 ngApp 指令用来启动 Angular 程序,但是也可能出现一些特殊情况需要我们在启动之前干些什么或者需要我们手动启动应用程序,这时候 angular.bootstrap 就派的上用场了。
angular.copy
针对对象或数字创建一个深层的拷贝。
格式:angular.copy(source, [destination]);
source:被拷贝的对象
destination:接收的对象 [注意:参数类型是对象或数组]
使用代码:
var objA, objD = []; //objA:undefined objD:[]var objB = { text: "Hello World" };var objC = {text:"Hai",value:"Test"};
objA = angular.copy(objB); // objA:{ text:"Hello World"} objB:{ text:"Hello World"}angular.copy(objC, objD);// objC:{text: "Hai", value: "Test"} objD:[text: "Hai", value: "Test"]
本兽对 Angular API 逐个的学习并且进行翻译,然后写能运行成功的代码,并把学习过程进行整理记录及分享...
关于Angular 客户端和后端 python - socket io和angular如何和后端交互的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于Android NDK Socket(POSIX Socket Api)编程、Angular 12.0.5 HMR 不工作,不重新加载模块,不重新加载页面实时重新加载,Angular 11.0.6 重新加载整个页面 调查 Angular 构建系统使用的版本配置 webpack使用 Angular 12.0.5 / next.6 时 - 没有帮助、angular j j angular j angular angular service service service j、Angular 学习系列 - - angular.bind、angular.bootstrap、angular.copy的相关知识,请在本站寻找。
本文标签: