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 ...
随机推荐
- C指针的这些使用技巧,掌握后立刻提升一个Level
这是道哥的第016篇原创 关注+星标公众号,不错过最新文章 目录 一.前言 二.八个示例 1. 开胃菜:修改主调函数中的数据 2. 在被调用函数中,分配系统资源 2.1 错误用法 2.2 正确用法 3 ...
- Go Concurrency Patterns: Pipelines and cancellation
https://blog.golang.org/pipelines Go Concurrency Patterns: Pipelines and cancellation Sameer Ajmani1 ...
- 扒一扒ELF文件
ELF文件(Executable Linkable Format)是一种文件存储格式.Linux下的目标文件和可执行文件都按照该格式进行存储,有必要做个总结. 目录 1. 链接举例 2. ELF文件类 ...
- loj10014数列分段二
10014. 「一本通 1.2 练习 1」数列分段 II 题目描述 对于给定的一个长度为 n 的正整数数列 A ,现要将其分成 m 段,并要求每段连续,且每段和的最大值最小. 例如,将数列 4,2,4 ...
- LOJ10202樱花——数论
题目描述 原题来自:HackerRank Equations 求不定方程: 1/x+1/y=1/n! 的正整数解 (x,y) 的数目. 输入格式 一个整数 n . 输出格式 一个整数,表示有多少对 ( ...
- 从零搭建一个IdentityServer——初识OpenIDConnect
上一篇文章实现了IdentityServer4与Asp.net core Identity的集成,可以使用通过identity注册功能添加的用户,以Password的方式获取Access token, ...
- N皇后解法以及位运算优化
N皇后解法以及位运算优化 观察棋盘,要求皇后之间不能处在同行同列同一条斜线,求使得每行都有一个皇后的放置方法共有多少种. 每尝试放置一个皇后,都可以把该位置所在的行.列标号用一个数组标记,含义表示该行 ...
- 2019 徐州网络赛 M Longest subsequence t
对于答案来说,一定是 前 i-1 个字符和 t的前 i 个一样,然后第 i 个字符比 t的 大 \(i\in [1,m]\) 前缀为t,然后长度比t长 对于第一种情况,枚举这个 i ,然后找最小的 p ...
- Codeforces Round #641 (Div. 2)
只写了A~D A - Orac and Factors 题意:f(n)就是n的第二小因数,问执行k次 n=f(n)+n 后的结果. 题解:如果一直找第二小的因子的话,1e9肯定得t.看下边样例解释就会 ...
- 【uva 1442】Cav(算法效率)
题意:有一个由N个片段构成宽度的洞穴,已知洞顶 si 和洞底 pi 的高度,要求储存尽量多的燃料. 解法:O(n),分别从1到N和从N到1扫一遍,调整每个片段合法的最大高度,求出答案. 1 #incl ...