Andrei Fidelman
const jsDeveloper = !!!(+[] - +[]);
main()
increment()
sum()
console.log()
const sum = (a, b) => a + b;
const increment = a => sum(a, 1);
const printIncrement = a => {
const incremented = increment(a);
console.log(`Incremented: ${incremented}`);
};
printIncrement(10);
main()
printIncrement()
increment()
sum()
console.log()
const foo = $.getSync('foo.com');
console.log('Hello World');
console.log(foo);
main()
$.getSync()
console.log('Hello World')
console.log(foo)
fetch('foo.com', { method: 'GET' })
.then(foo => console.log(foo));
console.log('Hello World');
main()
fetch(callback)
console.log('Hello World')
callback
fetch('foo.com', { method: 'GET' })
.then(foo => console.log(foo));
console.log('Hello World');
main()
fetch(callback)
console.log('Hello World')
fetch(callback)
foo
"Hello world"
callback
callback
function wait(time) {
return new Promise(function(resolve) {
setTimeout(resolve, time);
});
}
wait(3000)
.then(function() {
console.log('Hello');
});
fetch('/article/promise/user.json', { method: 'GET' })
.then(response => {
console.log(response);
const user = JSON.parse(response);
return user;
})
.then(user => {
console.log(user);
return fetch(`https://api.github.com/users/${user.name}`, { method: 'GET' });
})
.then(githubUser => {
console.log(githubUser);
githubUser = JSON.parse(githubUser);
let img = new Image();
img.src = githubUser.avatar_url;
img.className = "promise-avatar-example";
document.body.appendChild(img);
});
const generator = generateSequence();
generator.next(); // { value: 1, done: false }
generator.next(); // { value: 2, done: false }
generator.next(); // { value: 3, done: true }
generator.next(); // { value: undefined, done: true }
function* showUserAvatar() {
const userInfo = yield fetch('/article/generator/user.json');
const githubUserInfo = yield fetch(`https://api.github.com/users/${userInfo.name}`);
...
yield new Promise(resolve => setTimeout(resolve, 3000));
}
execute(showUserAvatar);
function execute(generatorSequence, yieldValue) {
const generator = generatorSequence();
const next = generator.next(yieldValue);
if (!next.done) {
next.value.then(
result => execute(generator, result),
err => generator.throw(err)
);
} else {
alert(next.value);
}
}
const f = async () => 1; // Promise
f().then(alert); // 1;
const promise = new Promise((resolve, reject) => {
setTimeout(() => resolve('done'), 1000);
});
const f = async () => {
const result = await promise; // wait till the promise resolves
alert(result); // "done!"
};
async function showUserAvatar() {
const userInfo = await fetch('/article/generator/user.json');
const githubUserInfo = await fetch(`https://api.github.com/users/${userInfo.name}`);
...
await new Promise(resolve => setTimeout(resolve, 3000));
}
showUserAvatar();
export default store => next => action => {
if (action.type !== 'GET_PRODUCTS_FETCH') next(action);
fetch(action.url, { method: 'GET' })
.then((response) => {
next({
...action,
payload: response.payload
});
});
}
export default async store => next => action => {
if (action.type !== 'GET_PRODUCTS_FETCH') next(action);
const response = await fetch(action.url, { method: 'GET' });
next({
...action,
payload: response.payload
});
}
// action creator
export default (url) => {
return (dispatch) => {
dispatch({ type: 'GET_PRODUCTS_FETCH' });
fetch(url, { method: 'GET' })
.then((response) => {
dispatch({
type: 'GET_PRODUCTS_SUCCESS',
payload: response.payload
});
});
};
}
// action creator
export default (url) => {
return async (dispatch) => {
dispatch({ type: 'GET_PRODUCTS_FETCH' });
const response = await fetch(url, { method: 'GET' });
dispatch({
type: 'GET_PRODUCTS_SUCCESS',
payload: response.payload
});
};
}
// store.js
const store = createStore(
reducer,
applyMiddleware(thunk.withExtraArgument(api))
)
// action.js
export default (url) => {
return async (dispatch, getState, api) => {
dispatch({ type: 'GET_PRODUCTS_FETCH' });
const response = await fetch(url, { method: 'GET' });
dispatch({
type: 'GET_PRODUCTS_SUCCESS',
payload: response.payload
});
};
}
// store.js
import { createStore, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'
import rootSaga from './sagas'
const sagaMiddleware = createSagaMiddleware()
const store = createStore(
reducer,
applyMiddleware(sagaMiddleware)
)
sagaMiddleware.run(rootSaga)
// sagas/index.js
import { all } from 'redux-saga/effects'
export default function* rootSaga() {
yield all([
watchIncrementAsync()
])
}
// sagas/increment.js
import { delay } from 'redux-saga'
import { put, takeEvery } from 'redux-saga/effects'
// worker
function* incrementAsync() {
yield delay(1000)
yield put({ type: 'INCREMENT' })
}
// watcher
export default function* watchIncrementAsync() {
yield takeEvery('INCREMENT_ASYNC', incrementAsync)
}
// sagas/increment.js
import { takeEvery } from 'redux-saga/effects'
// watcher
export default function* watchIncrementAsync() {
yield takeEvery('INCREMENT_ASYNC', incrementAsync)
}
// sagas/increment.js
import { takeLatest } from 'redux-saga/effects'
// watcher
export default function* watchIncrementAsync() {
yield takeLatest('INCREMENT_ASYNC', incrementAsync)
}
// sagas/increment.js
import { takeEvery } from 'redux-saga/effects'
import Api from './path/to/api'
function* watchFetchProducts() {
yield takeEvery('PRODUCTS_REQUESTED', fetchProducts)
}
function* fetchProducts() {
const products = yield Api.fetch('/products')
console.log(products)
}
// __test__/increment.js
const iterator = fetchProducts()
assert.deepEqual(iterator.next().value, ??)
// sagas/increment.js
import { takeEvery, call } from 'redux-saga/effects'
import Api from './path/to/api'
function* watchFetchProducts() {
yield takeEvery('PRODUCTS_REQUESTED', fetchProducts)
}
function* fetchProducts() {
const products = yield call(Api.fetch, '/products')
console.log(products)
}
// __test__/increment.js
assert.deepEqual(
iterator.next().value,
call(Api.fetch, '/products'),
"fetchProducts should yield an Effect call(Api.fetch, './products')"
)
// action.js
export const login = (url, data) => {
return async (dispatch) => {
dispatch({ type: 'LOGIN_FETCH' });
const response = await fetch(url, {method: 'post', data});
if (response.success) {
dispatch({
type: 'LOGIN_FETCH_SUCCESS',
token: response.token
});
} else {
dispatch({
type: 'LOGIN_FETCH_FAIL',
errorMessage: response.errorMessage
});
}
}
}
export const logout = (url, data) => {
return async (dispatch) => {
dispatch({ type: 'LOGOUT_FETCH' });
const response = await fetch(url, {method: 'post', data});
if (response.success) {
dispatch({
type: 'LOGOUT_FETCH_SUCCESS'
});
} else {
dispatch({
type: 'LOGOUT_FETCH_FAIL',
response.errorMessage
});
}
}
}
// saga.js
import { take, call, put, cancelled } from 'redux-saga/effects'
import Api from '...'
function* authorize(user, password) {
try {
const token = yield call(Api.authorize, user, password)
yield put({type: 'LOGIN_SUCCESS', token})
yield call(Api.storeItem, {token})
return token
} catch(error) {
yield put({type: 'LOGIN_ERROR', error})
} finally {
if (yield cancelled()) {
// ... put special cancellation handling code here
}
}
}
export default function* loginFlow() {
while (true) {
const {user, password} = yield take('LOGIN_REQUEST')
const task = yield fork(authorize, user, password)
const action = yield take(['LOGOUT', 'LOGIN_ERROR'])
if (action.type === 'LOGOUT') yield cancel(task)
yield call(Api.clearItem, 'token')
}
}
By Andrei Fidelman
JS Dev Talks about async Redux ~ 25 mins VIDEO: https://www.youtube.com/watch?v=ipDHLtjoH_A