Redux Middleware All in One
Redux Middleware All in One
https://redux.js.org/advanced/middleware
https://redux.js.org/api/applymiddleware
redux-saga
import {
delay,
put,
select,
call,
takeLatest,
takeEvery,
fork,
getContext,
take,
cancel
} from 'redux-saga/effects';
import { channel } from 'redux-saga';
import escape from 'lodash/escape';
import {
challengeDataSelector,
challengeMetaSelector,
challengeTestsSelector,
initConsole,
updateConsole,
initLogs,
updateLogs,
logsToConsole,
updateTests,
isBuildEnabledSelector,
disableBuildOnError,
types
} from './';
import {
buildChallenge,
canBuildChallenge,
getTestRunner,
challengeHasPreview,
updatePreview,
isJavaScriptChallenge,
isLoopProtected
} from '../utils/build';
// How long before bailing out of a preview.
const previewTimeout = 2500;
let previewTask;
export function* executeCancellableChallengeSaga() {
if (previewTask) {
yield cancel(previewTask);
}
const task = yield fork(executeChallengeSaga);
previewTask = yield fork(previewChallengeSaga, { flushLogs: false });
yield take(types.cancelTests);
yield cancel(task);
}
export function* executeCancellablePreviewSaga() {
previewTask = yield fork(previewChallengeSaga);
}
export function* executeChallengeSaga() {
const isBuildEnabled = yield select(isBuildEnabledSelector);
if (!isBuildEnabled) {
return;
}
const consoleProxy = yield channel();
try {
yield put(initLogs());
yield put(initConsole('// running tests'));
// reset tests to initial state
const tests = (yield select(challengeTestsSelector)).map(
({ text, testString }) => ({ text, testString })
);
yield put(updateTests(tests));
yield fork(takeEveryLog, consoleProxy);
const proxyLogger = args => consoleProxy.put(args);
const challengeData = yield select(challengeDataSelector);
const challengeMeta = yield select(challengeMetaSelector);
const protect = isLoopProtected(challengeMeta);
const buildData = yield buildChallengeData(challengeData, {
preview: false,
protect
});
const document = yield getContext('document');
const testRunner = yield call(
getTestRunner,
buildData,
{ proxyLogger },
document
);
const testResults = yield executeTests(testRunner, tests);
yield put(updateTests(testResults));
yield put(updateConsole('// tests completed'));
yield put(logsToConsole('// console output'));
} catch (e) {
yield put(updateConsole(e));
} finally {
consoleProxy.close();
}
}
function* takeEveryLog(channel) {
// TODO: move all stringifying and escaping into the reducer so there is a
// single place responsible for formatting the logs.
yield takeEvery(channel, function*(args) {
yield put(updateLogs(escape(args)));
});
}
function* takeEveryConsole(channel) {
// TODO: move all stringifying and escaping into the reducer so there is a
// single place responsible for formatting the console output.
yield takeEvery(channel, function*(args) {
yield put(updateConsole(escape(args)));
});
}
function* buildChallengeData(challengeData, options) {
try {
return yield call(buildChallenge, challengeData, options);
} catch (e) {
yield put(disableBuildOnError());
throw e;
}
}
function* executeTests(testRunner, tests, testTimeout = 5000) {
const testResults = [];
for (let i = 0; i < tests.length; i++) {
const { text, testString } = tests[i];
const newTest = { text, testString };
// only the last test outputs console.logs to avoid log duplication.
const firstTest = i === 1;
try {
const { pass, err } = yield call(
testRunner,
testString,
testTimeout,
firstTest
);
if (pass) {
newTest.pass = true;
} else {
throw err;
}
} catch (err) {
newTest.message = text;
if (err === 'timeout') {
newTest.err = 'Test timed out';
newTest.message = `${newTest.message} (${newTest.err})`;
} else {
const { message, stack } = err;
newTest.err = message + '\n' + stack;
newTest.stack = stack;
}
yield put(updateConsole(newTest.message));
} finally {
testResults.push(newTest);
}
}
return testResults;
}
// updates preview frame and the fcc console.
function* previewChallengeSaga({ flushLogs = true } = {}) {
yield delay(700);
const isBuildEnabled = yield select(isBuildEnabledSelector);
if (!isBuildEnabled) {
return;
}
const logProxy = yield channel();
const proxyLogger = args => logProxy.put(args);
try {
if (flushLogs) {
yield put(initLogs());
yield put(initConsole(''));
}
yield fork(takeEveryConsole, logProxy);
const challengeData = yield select(challengeDataSelector);
if (canBuildChallenge(challengeData)) {
const challengeMeta = yield select(challengeMetaSelector);
const protect = isLoopProtected(challengeMeta);
const buildData = yield buildChallengeData(challengeData, {
preview: true,
protect
});
// evaluate the user code in the preview frame or in the worker
if (challengeHasPreview(challengeData)) {
const document = yield getContext('document');
yield call(updatePreview, buildData, document, proxyLogger);
} else if (isJavaScriptChallenge(challengeData)) {
const runUserCode = getTestRunner(buildData, { proxyLogger });
// without a testString the testRunner just evaluates the user's code
yield call(runUserCode, null, previewTimeout);
}
}
} catch (err) {
if (err === 'timeout') {
// eslint-disable-next-line no-ex-assign
err = `The code you have written is taking longer than the ${previewTimeout}ms our challenges allow. You may have created an infinite loop or need to write a more efficient algorithm`;
}
console.log(err);
yield put(updateConsole(escape(err)));
}
}
export function createExecuteChallengeSaga(types) {
return [
takeLatest(types.executeChallenge, executeCancellableChallengeSaga),
takeLatest(
[
types.updateFile,
types.previewMounted,
types.challengeMounted,
types.resetChallenge
],
executeCancellablePreviewSaga
)
];
}
webpack:///./src/templates/Challenges/redux/execute-challenge-saga.js
refs
https://www.freecodecamp.org/learn/coding-interview-prep/data-structures
https://zzk.cnblogs.com/my/s/blogpost-p?Keywords=redux-saga
xgqfrms 2012-2020
www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!
Redux Middleware All in One的更多相关文章
- redux middleware 的理解
前言 这几天看了redux middleware的运用与实现原理,写了一个百度搜索的demo,实现了类似redux-thunk和redux-logger中间件的功能. 项目地址:https://git ...
- 如何学习理解Redux Middleware
Redux中的middleware其实就像是给你提供一个在action发出到实际reducer执行之前处理一些事情的机会.可以允许我们添加自己的逻辑在这段当中.它提供的是位于 action 被发起之后 ...
- koa/redux middleware系统解析
middleware 对于现有的一些框架比如koa,express,redux,都需要对数据流进行一些处理,比如koa,express的请求数据处理,包括json.stringify,logger,或 ...
- redux middleware 源码分析
原文链接 middleware 的由来 在业务中需要打印每一个 action 信息来调试,又或者希望 dispatch 或 reducer 拥有异步请求的功能.面对这些场景时,一个个修改 dispat ...
- koa/redux middleware 深入解析
middleware 对于现有的一些框架比如koa,express,redux,都需要对数据流进行一些处理,比如koa,express的请求数据处理,包括json.stringify,logger,或 ...
- 再探Redux Middleware
前言 在初步了解Redux中间件演变过程之后,继续研究Redux如何将中间件结合.上次将中间件与redux硬结合在一起确实有些难看,现在就一起看看Redux如何加持中间件. 中间件执行过程 希望借助图 ...
- 初识Redux Middleware
前言 原先改变store是通过dispatch(action) = > reducer:那Redux的Middleware是什么呢?就是dispatch(action) = > reduc ...
- [React + Functional Programming ADT] Create Redux Middleware to Dispatch Actions with the Async ADT
We would like the ability to group a series of actions to be dispatched with single dispatching func ...
- [React + Functional Programming ADT] Create Redux Middleware to Dispatch Multiple Actions
We only have a few dispatching functions that need to be known by our React Application. Each one ac ...
随机推荐
- Golang调用windows下的dll动态库中的函数 Golang 编译成 DLL 文件
Golang调用windows下的dll动态库中的函数 package main import ( "fmt" "syscall" "time&quo ...
- 如何设计一个亿级网关(API Gateway)?
1.背景 1.1 什么是API网关 API网关可以看做系统与外界联通的入口,我们可以在网关进行处理一些非业务逻辑的逻辑,比如权限验证,监控,缓存,请求路由等等. 1.2 为什么需要API网关 RPC协 ...
- AutoMapper源码解析
研究AutoMapper源码前,我们先来看一下AutoMapper的作用 官网解释:AutoMapper是一个简单的小程序库,旨在解决看似复杂的问题-摆脱将一个对象映射到另一个对象的代码 解释 首先一 ...
- Jmeter(三十七) - 从入门到精通进阶篇 - 输出HTML格式的性能测试报告(详解教程)
1.简介 相对于Loadrunner,Jmeter其实也是可以有测试报告产出的,虽然一般都不用(没有Loadrunner的报告那么强大是一方面),但是有小伙伴们私下问,那宏哥还是顺手写一下吧,今天我们 ...
- JavaScript——DOM操作
DOM-(Document Object Model)即文档对象模型. JavaScript可以动态地修改DOM,从而来修改HTML的内容. 查找HTML元素 通过 id 找到 HTML 元素 通过标 ...
- 关于Spring Boot的博客集合
掘金: 关于Spring Boot的博客集合 CSDN: Spring Boot教程 掘金: SpringBoot2 简书: Spring Boot 核心技术 天码营 Spring Data JPA: ...
- Linux忽略大小写的查找技巧(转)
1.vim 中的查找 Linux 下 vim搜索文件内容时加上 \c 参数可以忽略搜索字符的大小写. 比如用vim 搜索文件中的 China 时 可用 :/china\c 2. find 查找 Lin ...
- Linux系统对文件及目录的权限管理(chmod、chown)
本文命令: 4 5 6 ls -l chmod chown 1.身份介绍 在linux系统中,对文件或目录来说访问者的身份有三种: ①.属主用户,拥有者(owner)文件的创建者 ②.属组用户,和文件 ...
- (31)grep命令详解:查找文件内容
1.grep命令用于不需要列出文件的全部内容,而是从文件中找到包含指定信息的那些行. grep命令能够在一个或多个文件中,搜索某一特定的字符模式(也就是正则表达式),此模式可以是单一的字符.字符串.单 ...
- Python3列表、元组及之间的区别和转换
文章目录 1. 列表(list) 1.1 列表创建.切片.删除.检索 1.2 列表常用函数 2. 元组(tuple) 3. 列表与元组区别及转换 1. 列表(list) 1.1 列表创建.切片.删除. ...