classCustomEntryOptionPlugin {
// This is the standard way of creating plugins.// It's either this, or a simple function, but we're using this approach// in order to be on par with how most of the plugins are created.apply(compiler) {
// Recall that hooks offer us the possibility to intervene in the// bundling process.// With the help of the `entryOption` hook, we're adding the logic// that will basically mean the start of the bundling process. As in,// the `entryObject` argument will hold the `entry` object from the// configuration file and we'll be using it to set up the creation of// module trees.
compiler.hooks.entryOption.tap('CustomEntryOptionPlugin', entryObject => {
// The `EntryOption` class will handle the creation of a module tree.constEntryOption = class {
constructor (options) {
this.options = options;
};
// Since this is still a plugin, we're abiding by the standard.apply(compiler) {
// The `start` hook marks the start of the bundling process.// It will be called **after** `hooks.entryOption` is called.
compiler.hooks.start('EntryOption', ({ createModuleTree }) => {
// Creating new tree of modules, based on the configuration of this plugin.// The `options` contain the name of the entry(which essentially is the name of the chunk)// and the file name.// The `EntryDependency` encapsulates these options and also provides way to// create modules(because it maps to a `NormalModuleFactory`, which produces `NormalModule`s).// After calling `createModuleTree`, the source code of the file will be found,// then a module instance will be created and then webpack will get its AST, which // will be further used in the bundling process.createModuleTree(newEntryDependency(this.options));
});
};
};
// For each item in the `entryObject` we're preparing// the creation of a module tree. Remember that each// module tree is independent of others.// The `entryObject` could be something like this: `{ a: './a.js' }`for (const name in entryObject) {
const fileName = entryObject[name];
// We're fundamentally saying: `ok webpack, when the bundling process starts,// be ready to create a module tree for this entry`.newEntryOption({ name, fileName }).apply(compiler);
};
});
}
};
// The way we're adding logic to the existing webpack hooks// is by using the `tap` method, which has this signature:// `tap(string, callback)`// where `string` is mainly for debugging purposes, indicating// the source where the custom logic has been added from.// The `callback`'s argument depend on the hook on which we're adding custom functionality.classUnderstandingModuleGraphPlugin {
apply(compiler) {
const className = this.constructor.name;
// Onto the `compilation` object: it is where most of the *state* of// the bundling process is kept. It contains information such as the module graph,// the chunk graph, the created chunks, the created modules, the generated assets// and much more.
compiler.hooks.compilation.tap(className, (compilation) => {
// The `finishModules` is called after *all* the modules(including// their dependencies and the dependencies' dependencies and so forth)// have been built.
compilation.hooks.finishModules.tap(className, (modules) => {
// `modules` is the set which contains all the built modules.// These are simple `NormalModule` instances. Once again, a `NormalModule`// is produced by the `NormalModuleFactory`.// console.log(modules);// Retrieving the **module map**(Map<Module, ModuleGraphModule>).// It contains all the information we need in order to traverse the graph.const {
moduleGraph: { _moduleMap: moduleMap },
} = compilation;
// Let's traverse the module graph in a DFS fashion.constdfs = () => {
// Recall that the root module of the `ModuleGraph` is the// *null module*.const root = null;
const visited = newMap();
consttraverse = (crtNode) => {
if (visited.get(crtNode)) {
return;
}
visited.set(crtNode, true);
console.log(
crtNode?.resource ? path.basename(crtNode?.resource) : 'ROOT'
);
// Getting the associated `ModuleGraphModule`, which only has some extra// properties besides a `NormalModule` that we can use to traverse the graph further.const correspondingGraphModule = moduleMap.get(crtNode);
// A `Connection`'s `originModule` is the where the arrow starts// and a `Connection`'s `module` is there the arrow ends.// So, the `module` of a `Connection` is a child node.// Here you can find more about the graph's connection: https://github.com/webpack/webpack/blob/main/lib/ModuleGraphConnection.js#L53.// `correspondingGraphModule.outgoingConnections` is either a Set or undefined(in case the node has no children).// We're using `new Set` because a module can be reference the same module through multiple connections.// For instance, an `import foo from 'file.js'` will result in 2 connections: one for a simple import// and one for the `foo` default specifier. This is an implementation detail which you shouldn't worry about.const children = newSet(
Array.from(
correspondingGraphModule.outgoingConnections || [],
(c) => c.module
)
);
for (const c of children) {
traverse(c);
}
};
// Starting the traversal.traverse(root);
};
dfs();
});
});
}
}
const path = require('path');
// We're printing this way in order to highlight the parent-child// relationships between `ChunkGroup`s.constprintWithLeftPadding = (message, paddingLength) => console.log(message.padStart(message.length + paddingLength));
classUnderstandingChunkGraphPlugin {
apply (compiler) {
const className = this.constructor.name;
compiler.hooks.compilation.tap(className, compilation => {
// The `afterChunks` hook is called after the `ChunkGraph` has been built.
compilation.hooks.afterChunks.tap(className, chunks => {
// `chunks` is a set of all created chunks. The chunks are added into// this set based on the order in which they are created.// console.log(chunks);// As we've said earlier in the article, the `compilation` object// contains the state of the bundling process. Here we can also find// all the `ChunkGroup`s(including the `Entrypoint` instances) that have been created.// console.log(compilation.chunkGroups);// An `EntryPoint` is a type of `ChunkGroup` which is created for each// item in the `entry` object. In our current example, there are 2.// So, in order to traverse the `ChunkGraph`, we will have to start// from the `EntryPoints`, which are stored in the `compilation` object.// More about the `entrypoints` map(<string, Entrypoint>): https://github.com/webpack/webpack/blob/main/lib/Compilation.js#L956-L957const { entrypoints } = compilation;
// More about the `chunkMap`(<Chunk, ChunkGraphChunk>): https://github.com/webpack/webpack/blob/main/lib/ChunkGraph.js#L226-L227const { chunkGraph: { _chunks: chunkMap } } = compilation;
constprintChunkGroupsInformation = (chunkGroup, paddingLength) => {
printWithLeftPadding(`Current ChunkGroup's name: ${chunkGroup.name};`, paddingLength);
printWithLeftPadding(`Is current ChunkGroup an EntryPoint? - ${chunkGroup.constructor.name === 'Entrypoint'}`, paddingLength);
// `chunkGroup.chunks` - a `ChunkGroup` can contain one or mode chunks.const allModulesInChunkGroup = chunkGroup.chunks
.flatMap(c => {
// Using the information stored in the `ChunkGraph`// in order to get the modules contained by a single chunk.const associatedGraphChunk = chunkMap.get(c);
// This includes the *entry modules* as well.// Using the spread operator because `.modules` is a Set in this case.return [...associatedGraphChunk.modules];
})
// The resource of a module is an absolute path and// we're only interested in the file name associated with// our module.
.map(module => path.basename(module.resource));
printWithLeftPadding(`The modules that belong to this chunk group: ${allModulesInChunkGroup.join(', ')}`, paddingLength);
console.log('\n');
// A `ChunkGroup` can have children `ChunkGroup`s.
[...chunkGroup._children].forEach(childChunkGroup =>printChunkGroupsInformation(childChunkGroup, paddingLength + 3));
};
// Traversing the `ChunkGraph` in a DFS manner.for (const [entryPointName, entryPoint] of entrypoints) {
printChunkGroupsInformation(entryPoint, 0);
}
});
});
}
};
这是您应该看到的输出:
Current ChunkGroup's name: foo;
Is current ChunkGroup an EntryPoint? - true
The modules that belong to this chunk group: a.js, b.js, a1.js, b1.js
Current ChunkGroup's name: bar;
Is current ChunkGroup an EntryPoint? - true
The modules that belong to this chunk group: c.js, common.js
Current ChunkGroup's name: c1;
Is current ChunkGroup an EntryPoint? - false
The modules that belong to this chunk group: c1.js
Current ChunkGroup's name: c2;
Is current ChunkGroup an EntryPoint? - false
The modules that belong to this chunk group: c2.js
body {
background: hsl(210deg, 30%, 12%);
color: hsl(0deg0%100%);
}
.wrapper {
display: flex;
gap: 8px;
}
.item {
height: 32px;
border: 2px solid hsl(210deg8%50%);
background: hsl(210deg15%20%);
}
.item.stretch {
/*
Because this item is empty, it
has a default hypothetical width
of 0px. This isn't realistic,
though; in a typical case,
there would be content in here!
And so we set a width of 300px
to simulate it containing stuff.
*/width: 300px;
flex-grow: 1;
border-radius: 16px;
}
.item.ball {
width: 32px;
/*
NOTE: We could prevent the circle
from squishing into an oval by
setting border-radius: 16px
instead. I'm using percentages
because it makes for a better
demo. But even with a pixel-based
radius, we still need
flex-shrink: 0 to prevent the
item from shrinking (give it a
shot and see the difference!).
*/border-radius: 50%;
}
<!DOCTYPE html><html><head><meta charset="UTF-8"/><title>Ribbons设计 - 实例</title><link rel="stylesheet" type="text/css" href="./ribbon.css" /></head><body><div class="ribbon"><!-- The left side --><div class="ribbon__side ribbon__side--l"></div><!-- The left triangle displayed below the content --><div class="ribbon__triangle ribbon__triangle--l"></div><!-- The right triangle displayed below the content --><div class="ribbon__triangle ribbon__triangle--r"></div><!-- The right side --><div class="ribbon__side ribbon__side--r"></div><!-- The content --><div class="ribbon__content"></div></div></body></html>
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function's scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.
这个定义记住关键一点,它是在运行时产生的,一定是在函数创建时刻才有闭包
function outer() {
let counter = 0;
function inner() {
counter++;
console.log(counter);
}
inner();
}
outer();
outer();
// 1 1
function outer() {
let counter = 0;
function inner() {
counter++;
console.log(counter);
}
return inner;
}
let fn = outer();
fn();
fn();
// 1 2
/*
* This class prints the given message on console.
*/publicclassMessageUtil {
private String message;
//Constructor//@param message to be printedpublicMessageUtil(String message){
this.message = message;
}
// prints the messagepublic String printMessage(){
System.out.println(message);
return message;
}
// add "Hi!" to the messagepublic String salutationMessage(){
message = "Hi!" + message;
System.out.println(message);
return message;
}
}
本文解释了JUnit中方法的执行过程,定义了方法调用的顺序。下面举例说明 JUnit 测试 API 方法的执行过程。
创建一个名为 ExecutionProcedureJunit.java 的 java 类文件
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
publicclassExecutionProcedureJunit {
//execute only once, in the starting @BeforeClasspublicstaticvoidbeforeClass() {
System.out.println("in before class");
}
//execute only once, in the end@AfterClasspublicstaticvoidafterClass() {
System.out.println("in after class");
}
//execute for each test, before executing test@Beforepublicvoidbefore() {
System.out.println("in before");
}
//execute for each test, after executing test@Afterpublicvoidafter() {
System.out.println("in after");
}
//test case 1@TestpublicvoidtestCase1() {
System.out.println("in test case 1");
}
//test case 2@TestpublicvoidtestCase2() {
System.out.println("in test case 2");
}
}
import org.junit.Test;
importstatic org.junit.Assert.*;
publicclassTestAssertions {
@TestpublicvoidtestAssertions() {
//test dataStringstr1=newString ("abc");
Stringstr2=newString ("abc");
Stringstr3=null;
Stringstr4="abc";
Stringstr5="abc";
intval1=5;
intval2=6;
String[] expectedArray = {"one", "two", "three"};
String[] resultArray = {"one", "two", "three"};
//Check that two objects are equal
assertEquals(str1, str2);
//Check that a condition is true
assertTrue (val1 < val2);
//Check that a condition is false
assertFalse(val1 > val2);
//Check that an object isn't null
assertNotNull(str1);
//Check that an object is null
assertNull(str3);
//Check if two object references point to the same object
assertSame(str4,str5);
//Check if two object references not point to the same object
assertNotSame(str1,str3);
//Check whether two arrays are equal to each other.
assertArrayEquals(expectedArray, resultArray);
}
}
The Test annotation tells JUnit that the public void method to which it is attached can be run as a test case.
2
@Before
Several tests need similar objects created before they can run. Annotating a public void method with @Before causes that method to be run before each Test method.
3
@After
If you allocate external resources in a Before method, you need to release them after the test runs. Annotating a public void method with @After causes that method to be run after the Test method.
4
@BeforeClass
Annotating a public static void method with @BeforeClass causes it to be run once before any of the test methods in the class.
5
@AfterClass
This will perform the method after all tests have finished. This can be used to perform clean-up activities.
6
@Ignore
The Ignore annotation is used to ignore the test and that test will not be executed.
创建一个名为 JunitAnnotation.java 的 java 类文件
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
publicclassJunitAnnotation {
//execute before class@BeforeClasspublicstaticvoidbeforeClass() {
System.out.println("in before class");
}
//execute after class@AfterClasspublicstaticvoidafterClass() {
System.out.println("in after class");
}
//execute before test@Beforepublicvoidbefore() {
System.out.println("in before");
}
//execute after test@Afterpublicvoidafter() {
System.out.println("in after");
}
//test case@Testpublicvoidtest() {
System.out.println("in test");
}
//test case ignore and will not execute@IgnorepublicvoidignoreTest() {
System.out.println("in ignore test");
}
}
publicclassEmployeeDetails {
private String name;
privatedouble monthlySalary;
privateint age;
/**
* @return the name
*/public String getName() {
return name;
}
/**
* @param name the name to set
*/publicvoidsetName(String name) {
this.name = name;
}
/**
* @return the monthlySalary
*/publicdoublegetMonthlySalary() {
return monthlySalary;
}
/**
* @param monthlySalary the monthlySalary to set
*/publicvoidsetMonthlySalary(double monthlySalary) {
this.monthlySalary = monthlySalary;
}
/**
* @return the age
*/publicintgetAge() {
return age;
}
/**
* @param age the age to set
*/publicvoidsetAge(int age) {
this.age = age;
}
}
import org.junit.Test;
importstatic org.junit.Assert.*;
publicclassTestJunit1 {
@TestpublicvoidtestAdd() {
//test dataintnum=5;
Stringtemp=null;
Stringstr="Junit is working fine";
//check for equality
assertEquals("Junit is working fine", str);
//check for false condition
assertFalse(num > 6);
//check for not null value
assertNotNull(temp);
}
}
import junit.framework.TestCase;
import org.junit.Before;
import org.junit.Test;
publicclassTestJunit2extendsTestCase {
protecteddouble fValue1;
protecteddouble fValue2;
@BeforepublicvoidsetUp() {
fValue1 = 2.0;
fValue2 = 3.0;
}
@TestpublicvoidtestAdd() {
//count the number of test cases
System.out.println("No of Test Case = "+ this.countTestCases());
//test getName Stringname=this.getName();
System.out.println("Test Case Name = "+ name);
//test setNamethis.setName("testNewAdd");
StringnewName=this.getName();
System.out.println("Updated Test Case Name = "+ newName);
}
//tearDown used to close the connection or clean up activitiespublicvoidtearDown( ) {
}
}
import org.junit.Test;
import junit.framework.AssertionFailedError;
import junit.framework.TestResult;
publicclassTestJunit3extendsTestResult {
// add the errorpublicsynchronizedvoidaddError(Test test, Throwable t) {
super.addError((junit.framework.Test) test, t);
}
// add the failurepublicsynchronizedvoidaddFailure(Test test, AssertionFailedError t) {
super.addFailure((junit.framework.Test) test, t);
}
@TestpublicvoidtestAdd() {
// add any test
}
// Marks that the test run should stop.publicsynchronizedvoidstop() {
//stop the test here
}
}
Counts the number of test cases that will be run by this test.
4
String getName()
Returns the name of the suite.
5
void run(TestResult result)
Runs the tests and collects their result in a TestResult.
6
void setName(String name)
Sets the name of the suite.
7
Test testAt(int index)
Returns the test at the given index.
8
int testCount()
Returns the number of tests in this suite.
9
static Test warning(String message)
Returns a test which will fail and log a warning message.
创建一个名为 JunitTestSuite.java 的 java 类文件
import junit.framework.*;
publicclassJunitTestSuite {
publicstaticvoidmain(String[] a) {
// add the test's in the suiteTestSuitesuite=newTestSuite(TestJunit1.class, TestJunit2.class, TestJunit3.class );
TestResultresult=newTestResult();
suite.run(result);
System.out.println("Number of test cases = " + result.runCount());
}
}
验证输出
No of Test Case = 1
Test Case Name = testAdd
Updated Test Case Name = testNewAdd
Number of test cases = 3
Error creating bean with name 'userCreditPublisher' defined in file
[C:\devnote\backend\devnote\user-center\target\classes\io\majing\usercenter\message\UserCreditPublisher.class]:
Unsatisfied dependency expressed through constructor parameter 0;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.amqp.core.AmqpTemplate' available:
expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
/*
* This class prints the given message on console.
*/publicclassMessageUtil {
private String message;
//Constructor//@param message to be printedpublicMessageUtil(String message){
this.message = message;
}
// prints the messagepublic String printMessage(){
System.out.println(message);
return message;
}
}
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>5.2.2.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.2.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.2.2.RELEASE</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.5</version></dependency><dependencies><!-- Test Dependencies--><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.5.2</version><scope>test</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><version>5.5.2</version><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.2.2.RELEASE</version><scope>test</scope></dependency></dependencies>
...
<!-- Important for Jupiter-engine --><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>3.0.0-M3</version></plugin></plugins></build></project>
package com.jbd.saop.around.dao;
import com.jbd.saop.around.ExecutionTime;
import org.springframework.stereotype.Repository;
//A very stupid demo repository@RepositorypublicclassUserRepository {
//Add a user@ExecutionTimepublic UserRepository add(String username)throws InterruptedException {
Thread.sleep(100);
if(username == null) {
thrownewRuntimeException("username is null", newNullPointerException());
}
System.out.println("New user added: " + username);
returnthis;
}
//Update an userpublic UserRepository update(String username, String email) {
System.out.println("Update email: " + email);
returnthis;
}
//Delete an user@ExecutionTimepublicbooleandelete(String username){
if (username == null) {
thrownewRuntimeException("username is null", newNullPointerException());
}
System.out.println("User deleted: " + username);
returntrue;
}
}
@ExecutionTime
package com.jbd.saop.around;
import java.lang.annotation.*;
/**
* Tracks the execution time.
*///Allowed to use only on methods@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic@interface ExecutionTime {
}
<dependencies>
...
<!-- Test Dependencies--><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.5.2</version><scope>test</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><version>5.5.2</version><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.2.2.RELEASE</version><scope>test</scope></dependency></dependencies>
...
<!-- Important for Jupiter-engine --><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>3.0.0-M3</version></plugin></plugins></build></project>
Before method: UserRepository.add(..)
New user added: sample_username
Time taken to execute: 124ms
Before method: UserRepository.add(..)
java.lang.RuntimeException: username is null
at com.jbd.saop.around.dao.UserRepository.add(UserRepository.java:14)
at com.jbd.saop.around.dao.UserRepository$$FastClassBySpringCGLIB$$dcb57c42.invoke()
...
Caused by: java.lang.NullPointerException
... 86 more
Time taken to execute: 120ms
如您所见,Spring AOP 中的 around 建议非常强大。您可以更好地控制匹配的方法执行,尤其是由于 ProceedingJoinPoint。永远记得在通知方法中调用proceed()并返回Object值。
<dependencies>
...
<!-- Test Dependencies--><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.5.2</version><scope>test</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><version>5.5.2</version><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.2.2.RELEASE</version><scope>test</scope></dependency></dependencies>
...
<!-- Important for Jupiter-engine --><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>3.0.0-M3</version></plugin></plugins></build></project>
After advice executed: UserRepository.add(..)
After Exception executed: UserRepository.add(..)
Exception details: java.lang.RuntimeException: username is null
User deleted: alexa
After advice executed: UserRepository.delete(..)
// index.js// In this example, the page shows an `input` tag and a button.// The user is supposed to type an animal name and when the button is pressed,// the chunk whose name corresponds to the animal name will be loaded.let fileName;
// Here the animal name is written by the user.document.querySelector('input').addEventListener('input', ev => {
fileName = ev.target.value;
});
// And here the chunk is loaded. Notice how the chunk depends on the animal name// written by the user.document.getElementById('demo').addEventListener('click', () => {
import(/* webpackChunkName: 'animal' */`./animals/${fileName}.js`)
.then(m => {
console.warn('CHUNK LOADED!', m);
m.default();
})
.catch(console.warn);
});
可能已经注意到,控制台告诉我们块已经加载,以及它包含的模块,即 cat 模块。例如,如果我们想使用 fish 模块,也会采取相同的步骤:
导入匹配的每个文件,都会发生同样的情况。
eager模式
让我们首先看看我们将在本节中使用的示例:
let fileName;
// Here the animal name is written by the user.document.querySelector('input').addEventListener('input', ev => {
fileName = ev.target.value;
});
// Here the chunk that depends on `fileName` is loaded.document.getElementById('demo').addEventListener('click', () => {
import(/* webpackChunkName: 'animal', webpackMode: 'eager' */`./animals/${fileName}.js`)
.then(m => {
console.warn('FILE LOADED!', m);
m.default();
})
.catch(console.warn);
});
/*
The same file structure is assumed:
├── animals
│ ├── cat.js
│ ├── dog.js
│ ├── fish.js
│ └── lion.js
└── index.js
*/let fileName;
// Here the user chooses the name of the module.document.querySelector('input').addEventListener('input', ev => {
fileName = ev.target.value;
});
// When clicked, the chunk will be loaded and the module that matches with the `fileName`// variable will be executed and retrieved.document.getElementById('demo').addEventListener('click', () => {
import(/* webpackChunkName: 'animal', webpackMode: 'lazy-once' */`./animals/${fileName}.js`)
.then(m => {
console.warn('FILE LOADED!', m);
m.default();
})
.catch(console.warn);
});
let fileName;
// Here the user types the name of the moduledocument.querySelector('input').addEventListener('input', ev => {
fileName = ev.target.value;
});
// Here that module is retrieved directly if possible, otherwise// an error will be thrown.document.getElementById('demo').addEventListener('click', () => {
import(/* webpackChunkName: 'animal', webpackMode: 'weak' */`./animals/${fileName}.js`)
.then(m => {
console.warn('FILE LOADED!', m);
m.default();
})
.catch(console.warn);
});
let fileName;
// Here the user chooses the name of the file.document.querySelector('input').addEventListener('input', ev => {
fileName = ev.target.value;
});
// Requesting the module that should already be available.document.getElementById('demo').addEventListener('click', () => {
import(/* webpackChunkName: 'animal', webpackMode: 'weak' */`./animals/${fileName}.js`)
.then(m => {
console.warn('FILE LOADED!', m);
m.default();
})
.catch(console.warn);
});
// Dynamically loading the `cat.js` module.document.getElementById('load-cat').addEventListener('click', () => {
import('./animals/cat.js').then(m => {
console.warn('CAT CHUNK LOADED');
});
});
<dependencies>
...
<!-- Test Dependencies--><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.5.2</version><scope>test</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><version>5.5.2</version><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.2.2.RELEASE</version><scope>test</scope></dependency></dependencies>
...
<!-- Important for Jupiter-engine --><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>3.0.0-M3</version></plugin></plugins></build></project>
@Configuration@AspectpublicclassUppercaseAspect {
@AfterReturning("c.jbd.saop.ar.aspect.DaoExpressions.findMethod()")publicvoiduppercaseUsername(JoinPoint joinPoint, User result){
//advice body
}
}
<dependencies>
...
<!-- Test Dependencies--><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.5.2</version><scope>test</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><version>5.5.2</version><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.2.2.RELEASE</version><scope>test</scope></dependency></dependencies>
...
<!-- Important for Jupiter-engine --><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>3.0.0-M3</version></plugin></plugins></build></project>
After method - UserRepository.find(..)
original result:User[username='JsTobigdata', email='hello@world.com']
final result: User[username='JSTOBIGDATA', email='hello@world.com']
"use strict";
var arrowfunction = functionarrowfunction() {
console.log("Added changes to the log message");
};
main1.js
"use strict";
var handler = functionhandler() {
console.log("Added one more file");
};
接下来,我们将执行下面给出的命令,使用 babeljs 将这两个文件编译成一个文件。
npx babel src --out-file out/all.js
all.js
"use strict";
var arrowfunction = functionarrowfunction() {
console.log("Added changes to the log message");
};
"use strict";
var handler = functionhandler() {
console.log("Added one more file");
};
let m = newMap(); //map example
m.set("0","A");
m.set("1","B");
console.log(m);
let set = newSet(); //set example
set.add('A');
set.add('B');
set.add('A');
set.add('B');
console.log(set);
let ws = newWeakSet(); //weakset examplelet x = {};
let y = {};
ws.add(x);
console.log(ws.has(x));
console.log(ws.has(y));
let wm = newWeakMap(); //weakmap examplelet a = {};
wm.set(a, "hello");
console.log(wm.get(a));
"use strict";
var m = newMap(); //map example
m.set("0", "A");
m.set("1", "B");
console.log(m);
var set = newSet(); //set example
set.add('A');
set.add('B');
set.add('A');
set.add('B');
console.log(set);
var ws = newWeakSet(); //weakset examplevar x = {};
var y = {};
ws.add(x);
console.log(ws.has(x));
console.log(ws.has(y));
var wm = newWeakMap(); //weakmap examplevar a = {};
wm.set(a, "hello");
console.log(wm.get(a));
@Aspect@ConfigurationpublicclassExampleAspect {
@Before("com.jbd.someapp.aspect.SystemArchitecture.inWebLayer()")publicvoidlogWebLayer(){
System.out.print("Log in web layer");
}
}
<dependencies>
...
<!-- Test Dependencies--><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.5.2</version><scope>test</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><version>5.5.2</version><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.2.2.RELEASE</version><scope>test</scope></dependency></dependencies>
...
<!-- Important for Jupiter-engine --><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>3.0.0-M3</version></plugin></plugins></build></project>
Call general analytics for:UserRepository c.jbd.saop.cjp.dao.UserRepository.add(String)
New user added: Alexa
Call special analytics for: UserRepository c.jbd.saop.cjp.dao.UserRepository.update(String,String)
Update email: alexa@aws.com
正如您在上面的示例中看到的,在调用更新方法之前调用了特殊的分析 API,对于调用通用分析的所有其他 DAO 方法。
import add from'./add';
import multiply from'./multiply'let a = add(10,20);
let b = multiply(40,10);
console.log("%c"+a,"font-size:30px;color:green;");
console.log("%c"+b,"font-size:30px;color:green;");
new Promise() 用于构造一个 Promise。 Promise 构造函数有一个参数,它是一个回调函数。回调函数有两个参数——resolve和reject;
这两个都是内部函数。您编写的异步代码,即 Ajax 调用、图像加载、计时函数将进入回调函数。
如果回调函数中执行的任务成功,则调用resolve函数;否则,将使用错误详细信息调用拒绝函数。
以下代码行显示了一个 Promise 结构调用
var _promise = newPromise (function(resolve, reject) {
var success = true;
if (success) {
resolve("success");
} else {
reject("failure");
}
});
_promise.then(function(value) {
//once function resolve gets called it comes over here with the value passed in resolveconsole.log(value); //success
}).catch(function(value) {
//once function reject gets called it comes over here with the value passed in rejectconsole.log(value); // failure.
});
ES6 Promise 示例
let timingpromise = newPromise((resolve, reject) => {
setTimeout(function() {
resolve("Promise is resolved!");
}, 1000);
});
timingpromise.then((msg) => {
console.log(msg);
});
"use strict";
var x = void0,
y = void0,
rem = void0;
x = 10;
y = 20;
console.log(x);
console.log(y);
x = 10;
y = 20;
rem = [30, 40, 50];
console.log(rem);
var z = 0;
var _ref = z ? { x: 10, y: 20 } : { x: 1, y: 2 };
x = _ref.x;
y = _ref.y;
console.log(x);
console.log(y);
"use strict";
var a = 5;
var b = 10;
console.log("Using Template literal : Value is " + (a + b) + ".");
console.log("Using normal way : Value is " + (a + b));
let handler = {
get: function (target, name) {
return name in target ? target[name] : "invalid key";
}
};
let o = {
name: 'Siya Kapoor',
addr: 'Mumbai'
}
let a = newProxy(o, handler);
console.log(a.name);
console.log(a.addr);
console.log(a.age);
我们在上面的示例中定义了目标和处理程序,并将其与代理一起使用。代理返回带有键值的对象。
Siya Kapoor
Mumbai
invalid key
现在让我们看看如何使用 babel 将上述代码转换为 ES5
npx babel proxy.js --out-file proxy_es5.js
'use strict';
var handler = {
get: functionget(target, name) {
return name in target ? target[name] : "invalid key";
}
};
var o = {
name: 'Siya Kapoor',
addr: 'Mumbai'
};
var a = newProxy(o, handler);
console.log(a.name);
console.log(a.addr);
console.log(a.age);