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. odoo-nginx 配置之80端口

    1 upstream odoo { 2 server 127.0.0.1:8069 weight=1 fail_timeout=0; 3 } 4 5 upstream odoo-im { 6 serv ...

  2. 【Soul网关探秘】http数据同步-Web端处理变更通知

    个人知识库 引言 上一篇,梳理http 数据同步策略的变更通知机制,本篇开始探究配置变更通知到达后, soul-web 端的处理响应. 不同数据变更的通知机制应当是一致的,故本篇以 selector ...

  3. LOJ10129

    AHOI 2009 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为 nn 的数列,不妨设为 a1​,a2​,⋯,an​.有如下三种操作形式: 把数列中的一段数全部乘一个值: 把 ...

  4. php中一种单引号逃逸造成的注入

    demo如下: $post = $_POST; $sql=''; $array['name'] = $post['name']; $array['age'] = 18; $array['addr'] ...

  5. 剖析 CopyOnWriteArrayList

    原文链接:https://www.changxuan.top/?p=1252 CopyOnWriteArrayList 是 JUC 中唯一一个支持并发的 List. CopyOnWriteArrayL ...

  6. Phoenix踩坑填坑记录

    Phoenix踩坑填坑记录 Phoenix建表语句 如何添加二级索引 判断某表是否存在 判断索引是否存在 Date类型日期,条件判断 杂项 记录Phoenix开发过程中的填坑记录. 部分原文地址:ph ...

  7. Django (auth模块、User对象、用户认证、线上-用户认证)

    一.auth模块 django.contrib.auth中提供了许多方法,这里主要介绍其中的三个: authenticate()    提供了用户认证,即验证用户名以及密码是否正确,一般需要usern ...

  8. Django(图书管理系统)#转

    自己虽然实现了, 但是写的太LOW了,为了不误导大家,推荐一篇好的博客 https://www.cnblogs.com/alice-bj/p/9114084.html

  9. sudo 配置

    在ubuntu中由于禁用了root用户,默认情况下会把安装系统时建立的用户添加到sudoers中. 但在redhat和centos中并没有把任何root用户之外的用户默认的添加到sudoers之中.这 ...

  10. MySQL的安装、改密及远程连接

    一.下载MySQL压缩包后的安装步骤 将压缩包解压到指定的目录 编辑好配置文件 [mysql] #设置MySQL客户端默认字符集 default-character-set=utf8 [mysqld] ...