Redux Middleware All in One

https://redux.js.org/advanced/middleware

https://redux.js.org/api/applymiddleware

redux-saga

https://redux-saga.js.org/


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的更多相关文章

  1. redux middleware 的理解

    前言 这几天看了redux middleware的运用与实现原理,写了一个百度搜索的demo,实现了类似redux-thunk和redux-logger中间件的功能. 项目地址:https://git ...

  2. 如何学习理解Redux Middleware

    Redux中的middleware其实就像是给你提供一个在action发出到实际reducer执行之前处理一些事情的机会.可以允许我们添加自己的逻辑在这段当中.它提供的是位于 action 被发起之后 ...

  3. koa/redux middleware系统解析

    middleware 对于现有的一些框架比如koa,express,redux,都需要对数据流进行一些处理,比如koa,express的请求数据处理,包括json.stringify,logger,或 ...

  4. redux middleware 源码分析

    原文链接 middleware 的由来 在业务中需要打印每一个 action 信息来调试,又或者希望 dispatch 或 reducer 拥有异步请求的功能.面对这些场景时,一个个修改 dispat ...

  5. koa/redux middleware 深入解析

    middleware 对于现有的一些框架比如koa,express,redux,都需要对数据流进行一些处理,比如koa,express的请求数据处理,包括json.stringify,logger,或 ...

  6. 再探Redux Middleware

    前言 在初步了解Redux中间件演变过程之后,继续研究Redux如何将中间件结合.上次将中间件与redux硬结合在一起确实有些难看,现在就一起看看Redux如何加持中间件. 中间件执行过程 希望借助图 ...

  7. 初识Redux Middleware

    前言 原先改变store是通过dispatch(action) = > reducer:那Redux的Middleware是什么呢?就是dispatch(action) = > reduc ...

  8. [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 ...

  9. [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 ...

随机推荐

  1. 计算机网络安全 —— C# 使用谷歌身份验证器(Google Authenticator)(五)

    一.Google Authenticator 基本概念  Google Authenticator是谷歌推出的一款动态口令工具,旨在解决大家Google账户遭到恶意攻击的问题,在手机端生成动态口令后, ...

  2. 计算机网络第7版 PDF+ 计算机网络释疑与习题解答第7版 PDF 计算机网络 课后答案

    网上全都是要钱的,要么就是第六版的,属实被恶心到了. 链接:https://pan.baidu.com/s/15jCOH6LXnQfB1RwGpNgBFg提取码:byMB

  3. LOJ2632

    题目描述 译自 BalticOI 2011 Day1 T3「Switch the Lamp On」有一种正方形的电路元件,在它的两组相对顶点中,有一组会用导线连接起来,另一组则不会.有  个这样的元件 ...

  4. REST以及RESTful

    java作为一门后端语言,其厉害之处在于web,大家比较熟知的各种网络应用,java都能做,那么在这个移动优先的时代,如何继续发挥java的强大呢.通常是让java作为一个app的服务端,为app客户 ...

  5. python -m http.server 搭建一个简易web下载服务器

    在打vulnhub靶场的时候遇到的一个问题 目录 一.进到需要发送的安装包目录 二.开启http服务 三.访问服务器 一.进到需要发送的安装包目录 比如设置一个专门发送,传输的文件的文件夹,cmd命令 ...

  6. python模块----configpaser (key:value型 配置文件解析器)

    configparser是用来读取配置文件的包,配置文件的格式类似:[section]+内容(键=值) 标准库网址:https://docs.python.org/3/library/configpa ...

  7. centos设系统置语言为中文

    [root@host /]# vim /etc/sysconfig/i18n #i18n 是 internationalization 的缩写形式,意即在 i 和 n 之间有 18 个字母,本意是指软 ...

  8. Kubernetes -- secret (敏感数据管理)

    https://www.kubernetes.org.cn/secret secret 主要解决密码.token.密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者Pod Spec中 Se ...

  9. Elasticsearch 之 Filter 与 Query 有啥不同?

    今天来了解下 Elasticsearch(以下简称 ES) 中的 Query 和 Filter. 在 ES 中,提供了 Query 和 Filter 两种搜索: Query Context:会对搜索进 ...

  10. 《进击吧!Blazor!》第一章 4.数据交互

    <进击吧!Blazor!>是本人与张善友老师合作的Blazor零基础入门系列视频,此系列能让一个从未接触过Blazor的程序员掌握开发Blazor应用的能力. 视频地址:https://s ...