Javascript

HTTP/JSON/AJAX + Asynchronous Javascript

目录

HTTP/HTTPS

Json

 Ajax

 Promises

 ES8 - Async Await

 object spread operator

Finally()

For await of

allSettled()

Promise.any() 

Redux

Object.assign()

mapStateToProps

mapDispatchToProps

Redux Middleware

Redux Async Actions

HTTP/HTTPS

Http:Hypertext Transfer Protocol (HTTP) 

HTTP 方法(有时称为 HTTP 动词)指示 HTTP 请求对所查询服务器的期望操作。例如,最常见的两种 HTTP 方法是“GET”和“POST”。“GET”请求期望返回信息(通常以网站的形式),而“POST”请求通常表示客户端正在向 Web 服务器提交信息(例如表单信息,如提交的用户名和密码)。

Get:会显示在query string.Eg:www.yujing.com?num=1

https://mp.csdn.net/mp_blog/creation/editor?spm=1001.2014.3001.4503

后面这一段就是query string。他会出现在search bar中

Post:是通过body(请求正文) 传输的。

请求正文是包含请求所传输信息的“主体”的部分。HTTP 请求的正文包含正在提交到 Web 服务器的任何信息,例如用户名和密码,或输入到表单中的任何其他数据。

当然还有其它的verb :Get/post/put/delete

reference:What is HTTP 

response 什么了?比如data(html...)或者status code(404/200....) 

 

Https:s means   -----------more secure and Encryption

Json

 server can receive any types of data?

Nope. Just receive Json and Xml data.

Both JSON and XML can be used to receive data from a web server.

 reference:JSON vs XML

 这是将

Convert a JavaScript object into a string with JSON.stringify().

The JSON.parse() static method parses a JSON string, constructing the JavaScript value or object described by the string. 

JSON.parse()
JSON.stringify()

 Ajax

AJAX即“Asynchronous JavaScript and XML”,指的是一套综合了多项技术的浏览器端网页开发技术

Ajax stands for Asynchronous JavaScript and XML. It is used to make asynchronous communication with the server. Ajax is used to read data from the server and update the page or send data to the server without affecting the current client page. Ajax is a programming concept. 

 function run() {
  
        // Creating Our XMLHttpRequest object 
        var xhr = new XMLHttpRequest();
  
        // Making our connection  
        var url = 'https://jsonplaceholder.typicode.com/todos/1';
        xhr.open("GET", url, true);
  
        // function execute after request is successful 
        xhr.onreadystatechange = function () {
            if (this.readyState == 4 && this.status == 200) {
                console.log(this.responseText);
            }
        }
        // Sending our request 
        xhr.send();
    }
    run();

Output

"{
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}"

 Promises

The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.

Promise is in one of these states:

  • pending: initial state, neither fulfilled nor rejected.
  • fulfilled: meaning that the operation was completed successfully.(resolve)
  • rejected: meaning that the operation failed.

 reference:Promise - JavaScript | MDN

加一个例子:

Promise还可以做更多的事情,比如,有若干个异步任务,需要先做任务1,如果成功后再做任务2,任何任务失败则不再继续并执行错误处理函数。

要串行执行这样的异步任务,不用Promise需要写一层一层的嵌套代码。有了Promise,我们只需要简单地写:

job1.then(job2).then(job3).catch(handleError);

For example:

new Promise(function (resolve, reject) {
    log('start new Promise...');
    var timeOut = Math.random() * 2;
    log('set timeout to: ' + timeOut + ' seconds.');
    setTimeout(function () {
        if (timeOut < 1) {
            log('call resolve()...');
            resolve('200 OK');
        }
        else {
            log('call reject()...');
            reject('timeout in ' + timeOut + ' seconds.');
        }
    }, timeOut * 1000);
}).then(function (r) {
    log('Done: ' + r);
}).catch(function (reason) {
    log('Failed: ' + reason);
});

 output:

Log:

start new Promise...

set timeout to: 0.9840564421066844 seconds.

call resolve()...

Done: 200 OK

 可见Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了:

reference:Promise - 廖雪峰的官方网站 

Exercise:

// Solve the questions below:

// #1) Create a promise that resolves in 4 seconds and returns "success" string
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("success");
  }, 4000)
});

// #2) Run the above promise and make it console.log "success"
promise.then(console.log)
// or
promise.then(resp => console.log(resp))

// #3) Read about Promise.resolve() and Promise.reject(). How can you make
// the above promise shorter with Promise.resolve() and console loggin "success"
const promise = Promise.resolve(
  setTimeout(() => {
    console.log("success");
  }, 4000)
);

// #4) Catch this error and console log 'Ooops something went wrong'
Promise.reject('failed')
  .catch(console.log('Ooops something went wrong'))

// #5) Use Promise.all to fetch all of these people from Star Wars (SWAPI) at the same time.
// Console.log the output and make sure it has a catch block as well.
const urls = [
  'http://swapi.dev/api/people/1',
  'http://swapi.dev/api/people/2',
  'http://swapi.dev/api/people/3',
  'http://swapi.dev/api/people/4'
]

Promise.all(urls.map(url =>
    fetch(url).then(people => people.json())
))
  .then(array => {
    console.log('1', array[0])
    console.log('2', array[1])
    console.log('3', array[2])
    console.log('4', array[3])
  })
  .catch(err => console.log('ughhhh fix it!', err));

 ES8 - Async Await

  • async 表示这是一个async函数, await只能用在async函数里面,不能单独使用
  • async 返回的是一个Promise对象,await就是等待这个promise的返回结果后,再继续执行
  • await 等待的是一个Promise对象,后面必须跟一个Promise对象,但是不必写then(),直接就可以得到返回值

作者:李悦之
链接:https://www.jianshu.com/p/612bd4c9a7a8
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

他跟fetch的作用一样。但是比promise更容易理解,逻辑更清晰,更好调试 

fetch('https://jsonplaceholder.typicode.com/todos/1')
      .then(response => response.json())
      .then(json => console.log(json))

async function fetchUser() {
const resp = await fetch('https://jsonplaceholder.typicode.com/todos/1');
const data = await resp.json();
console.log(data)
}

这两个列子是一摸一样的结果。fetch data 过后得到的promise,然后还会输出结果 

const urls = [
  'http://swapi.dev/api/people/1',
  'http://swapi.dev/api/people/2',
  'http://swapi.dev/api/people/3',
  'http://swapi.dev/api/people/4'
]

Promise.all(urls.map(url =>
    fetch(url).then(people => people.json())
))
  .then(array => {
    console.log('1', array[0])
    console.log('2', array[1])
    console.log('3', array[2])
    console.log('4', array[3])
  })
  .catch(err => console.log('ughhhh fix it!', err));

 object spread operator

const animals = {
'lion':230,
'tiger':200,
'elephant':'100'
}
const {lion,...rest} = animals

Output:  

可以用在array,也可以用在object

Finally()

finally(onFinally)

finally(() => {
  // Code that will run after promise is settled (fulfilled or rejected)
})

Returns an equivalent Promise. If the handler throws an error or returns a rejected promise, the promise returned by finally() will be rejected with that value instead. 没有接受任何值

reference:Promise.prototype.finally() - JavaScript | MDN 

用在哪?

The finally() method can be useful if you want to do some processing or cleanup once the promise is settled, regardless of its outcome. (没用过,不知道现实生活中到底怎么用的)

Example.

let isLoading = true;

fetch(myRequest).then(function(response) {
    var contentType = response.headers.get("content-type");
    if(contentType && contentType.includes("application/json")) {
      return response.json();
    }
    throw new TypeError("Oops, we haven't got JSON!");
  })
  .then(function(json) { /* process your JSON further */ })
  .catch(function(error) { console.log(error); })
  .finally(function() { isLoading = false; });

For await of

The for await...of statement creates a loop iterating over async iterable objects as well as sync iterables

synax:

for await (variable of iterable)
  statement

Example

const urls = [
  "https://jsonplaceholder.typicode.com/users",
  "https://jsonplaceholder.typicode.com/posts",
  "https://jsonplaceholder.typicode.com/albums",
];

const getData = async function () {
  const [users, posts, albums] = await Promise.all(
    urls.map((url) => fetch(url).then((resp) => resp.json())),
  );
  console.log("users", users);
  console.log("posta", posts);
  console.log("albums", albums);
};

const getData2 = async function(){
  const arrayofPromise = urls.map((url)=>fetch(url));
  for await (let request of arrayofPromise){
    const data = await request.json()
    console.log(data)
  }
}

allSettled()

The Promise.allSettled() static method takes an iterable of promises as input and returns a single Promise. This returned promise fulfills when all of the input's promises settle (including when an empty iterable is passed), with an array of objects that describe the outcome of each promise.

他只回复一个promise,就是把所有的情况一起回复,不会遇到reject就不回复resolve部分了

Promise.any() 

Promise.any() 可用于以并行和竞争方式执行独立的异步操作,以获取任何第一个完成的 promise 的值。

Promise.any() 原理解析及使用指南 - 掘金

Redux

action ->reducer ->store->make changes

他就是个state management

直接上例子。

 actions.js

import { CHANGE_SEARCH_FIELD } from './constants.js';
export const setSearchField = (text) => ({
    type: CHANGE_SEARCH_FIELD,
    payload: text
})

 action 是用来干嘛的呢?就是声明一下,我是谁,我想传送什么类型的数据。

感觉跟这个功能很像

const [search,setSearch] = useState("")

 type就跟它的名字一样。payload就是 我要传送什么数据(put that information)。

 constants.js

创建它的常量

export const CHANGE_SEARCH_FIELD = 'CHANGE_SEARCH_FIELD';

reducers.js

import { CHANGE_SEARCH_FIELD } from './constants.js';
const initailState = {
    searchField: ''
}
export const searchRobots = (state=initailState, action={}) => {
    switch(action.type) {
        case CHANGE_SEARCH_FIELD:
            return Object.assign({}, state, {searchField: action.payload});
        default:
            return state;
    }
}

reducers作用是一个函数,具有返回值,用来接收对象,并且更新对象

这个reducers是从array.reduce这个函数得来的。它接受上一个结果(state)和当前项(action 对象),根据这些参数计算出一个新 state,并返回该新 state。

比如说

const numbers = [2, 5, 8]

const addNumbers = (previousResult, currentItem) => {
  console.log({ previousResult, currentItem })
  return previousResult + currentItem
}

const initialValue = 0

const total = numbers.reduce(addNumbers, initialValue)
// {previousResult: 0, currentItem: 2}
// {previousResult: 2, currentItem: 5}
// {previousResult: 7, currentItem: 8}

console.log(total)
// 15

它本身不需要跟踪任何东西。它接受 previousResult 和 currentItem 参数,用它们做一些事情,并返回一个新的结果值。

补充

Object.assign()

是一个 JavaScript 方法,用于将一个或多个源对象的所有可枚举属性复制到目标对象中。它会返回目标对象。

通俗来说,就是可以将多个对象合并成一个对象,其中后面的对象属性会覆盖前面的对象属性。这个方法通常用于 React 和 Redux 中。

例如,我们有以下两个对象:


const obj1 = { name: 'Alice', age: 20 };
const obj2 = { name: 'Bob', gender: 'male' };

我们可以使用 Object.assign() 方法将这两个对象合并成一个对象:


const newObj = Object.assign({}, obj1, obj2);

这样,newObj 的值为:

{
  name: 'Bob',
  age: 20,
  gender: 'male'
}

在这个例子中,我们传入了三个对象:空对象、obj1 和 obj2。空对象作为目标对象,obj1 和 obj2 是源对象。Object.assign() 方法会将 obj1 和 obj2 的属性复制到目标对象中。

需要注意的是,Object.assign() 方法会将源对象的属性复制到目标对象中,如果目标对象已经有同名的属性,那么源对象的属性会覆盖目标对象的属性。

store

index.js

const store = createStore(rootReducers)

它就跟个存储库一样,可以都是把状态什么的都存在这里。store顾名思义

The current Redux application state lives in an object called the store .

The store is created by passing in a reducer, and has a method called getState that returns the current state value

并且会pass down the store as a prop

The <Provider> component makes the Redux store available to any nested components that need to access the Redux store.

root.render(
<Provider store={store}>
  <App/>
</Provider>
);

那么我们都设置好了,如何将这个东西放到react 里面呢?

The connect() function connects a React component to a Redux store.

// parameter state comes from index.js provider store state(rootReducers)
const mapStateToProps = (state) => {
  return {
    searchField: state.searchRobots.searchField,
  }
}

// dispatch the DOM changes to call an action. note mapStateToProps returns object, mapDispatchToProps returns function
// the function returns an object then uses connect to change the data from redecers.
const mapDispatchToProps = (dispatch) => {
  return {
    onSearchChange: (event) => dispatch(setSearchField(event.target.value)),
  }
}
// action done from mapDispatchToProps will channge state from mapStateToProps
export default connect(mapStateToProps, mapDispatchToProps)(App)

mapStateToProps

If a mapStateToProps function is specified, the new wrapper component will subscribe to Redux store updates. This means that any time the store is updated, mapStateToProps will be called. 

mapDispatchToProps

Conventionally called mapDispatchToProps, this second parameter to connect() may either be an object, a function, or not supplied.

dispatch to the reducer

这个解释的比较清楚。

Redux 入门教程(三):React-Redux 的用法 - 阮一峰的网络日志

总结

整体流程

connect方法可以用来生成容器组件,mapStateToProps()将当前状态当包装成一个容器(props),每当redux store 更新的时候 的时候,就会调用这个。mapDispatchToProps()它定义了哪些用户的操作应该当作 Action。

图如下

以计算器为例子

Redux Middleware

index.js 里面

const logger = createLogger() 

const store = createStore(rootReducers, applyMiddleware(thunkMiddleware, logger))

Redux Middleware(中间件)是 Redux 中的一个概念,用于扩展 Redux 的功能。它是一个函数,它可以拦截 Redux 的 Action(动作)并在 Action 到达 Reducer(数据处理器)之前做一些操作,比如日志记录、异步请求、错误处理等等。

通俗来说,Middleware 可以在 Redux 数据流中的某个特定点添加额外的功能,如在 Action 被发起时添加日志记录、在 Action 到达 Reducer 之前进行请求、在 Action 处理过程中进行错误处理等等,增强了 Redux 的灵活性和可扩展性。

例如,我们可以使用 Middleware 为每个发起的 Action 添加日志记录:


const loggerMiddleware = store => next => action => {
  console.log('dispatching', action)
  let result = next(action)
  console.log('next state', store.getState())
  return result
}

const store = createStore(
  rootReducer,
  applyMiddleware(loggerMiddleware)
)

这个 Middleware 拦截了每一个发起的 Action,并在 Action 被发起时添加日志记录。它在 Action 到达 Reducer 之前执行,打印出 Action 的内容和当前状态。(previous state,action,new state )然后让 Action 继续传递到下一个 Middleware 或者 Reducer。

需要注意的是,Middleware 必须以特定的形式定义,并且需要添加到 Redux 的 createStore 函数中作为第二个参数,例如上面的 applyMiddleware(loggerMiddleware)。这样,当 Action 被发起时,它会经过这个 Middleware,然后再到达 Reducer 处理。

举个生活中的例子

假设你正在制作一份沙拉,你需要切一些蔬菜。但是你发现你的刀太钝了,不能很好地切割蔬菜。那么你会怎么做?你会找到一个磨刀石来磨刀,这样你的刀就能更好地切割蔬菜了。

在这个例子中,你的刀就像 Redux 中的 action,而磨刀石就像 Redux 中的 middleware。middleware 可以处理 action,修改它们的值或者将它们转换成其他形式,这样它们能够更好地被 reducer 处理。

类似于磨刀石,middleware 可以帮助你让你的 action 更加“尖锐”,以至于你的 reducer 可以更好地处理它们。在 Redux 中,middleware 可以用于处理异步操作、日志记录、错误处理等等。

Redux Async Actions

可以使用middleware 进行异步请求。fetch data

action.js

export const requestRobots = () => (dispatch) => {
  dispatch({ type: REQUEST_ROBOTS_PENDING })
  apiCall('https://jsonplaceholder.typicode.com/users')
    .then(data => dispatch({ type: REQUEST_ROBOTS_SUCCESS, payload: data }))
    .catch(error => dispatch({ type: REQUEST_ROBOTS_FAILED, payload: error }))
}

 export const requestRobots = () => (dispatch) => {}

这里代表的意思是当调用requestRobots的时候会返回一个函数

reducers.js


const initialStateRobots = {
  robots: [],
  isPending: true
}

export const requestRobots = (state=initialStateRobots, action={}) => {
  switch (action.type) {
    case REQUEST_ROBOTS_PENDING:
      return Object.assign({}, state, {isPending: true})
    case REQUEST_ROBOTS_SUCCESS:
      return Object.assign({}, state, {robots: action.payload, isPending: false})
    case REQUEST_ROBOTS_FAILED:
      return Object.assign({}, state, {error: action.payload})
    default:
      return state
  }
}

index.js 

const logger = createLogger() 

const rootReducers = combineReducers({requestRobots, searchRobots})

const store = createStore(rootReducers, applyMiddleware(thunkMiddleware, logger))

middleware -> store

App.js

const mapStateToProps = (state) => {
  return {
    searchField: state.searchRobots.searchField,
    robots: state.requestRobots.robots,
    isPending: state.requestRobots.isPending
  }
}

// dispatch the DOM changes to call an action. note mapStateToProps returns object, mapDispatchToProps returns function
// the function returns an object then uses connect to change the data from redecers.
const mapDispatchToProps = (dispatch) => {
  return {
    onSearchChange: (event) => dispatch(setSearchField(event.target.value)),
    onRequestRobots: () => dispatch(requestRobots())
  }
}

connect 一下

以下是一个例子,使用 Redux Middleware 来实现异步请求:


import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
import axios from 'axios';

const initialState = {
  loading: false,
  data: null,
  error: null,
};

// 定义 Action 类型
const FETCH_DATA_REQUEST = 'FETCH_DATA_REQUEST';
const FETCH_DATA_SUCCESS = 'FETCH_DATA_SUCCESS';
const FETCH_DATA_FAILURE = 'FETCH_DATA_FAILURE';

// 定义 Action 创建函数
const fetchDataRequest = () => ({
  type: FETCH_DATA_REQUEST,
});

const fetchDataSuccess = (data) => ({
  type: FETCH_DATA_SUCCESS,
  payload: data,
});

const fetchDataFailure = (error) => ({
  type: FETCH_DATA_FAILURE,
  payload: error,
});

// 定义 Reducer (pure function)
const reducer = (state = initialState, action) => {
  switch (action.type) {
    case FETCH_DATA_REQUEST:
      return {
        ...state,
        loading: true,
        error: null,
      };
    case FETCH_DATA_SUCCESS:
      return {
        ...state,
        loading: false,
        data: action.payload,
      };
    case FETCH_DATA_FAILURE:
      return {
        ...state,
        loading: false,
        error: action.payload,
      };
    default:
      return state;
  }
};

// 定义 Middleware
const fetchDataMiddleware = ({ dispatch }) => (next) => async (action) => {
  if (action.type === 'FETCH_DATA') {
    dispatch(fetchDataRequest());
    try {
      const response = await axios.get(action.url);
      dispatch(fetchDataSuccess(response.data));
    } catch (error) {
      dispatch(fetchDataFailure(error.message));
    }
  }
  return next(action);
};

// 创建 Store
const store = createStore(reducer, applyMiddleware(thunkMiddleware, fetchDataMiddleware));

// 发起 Action
store.dispatch({
  type: 'FETCH_DATA',
  url: 'https://jsonplaceholder.typicode.com/todos/1',
});

上面的例子中,我们使用了 Redux Middleware 实现了异步请求。我们定义了三个 Action 类型和对应的 Action 创建函数,用于发起异步请求并更新数据的状态。我们还定义了一个 Reducer,根据不同的 Action 类型更新数据的状态。最后,我们定义了一个 fetchDataMiddleware,用来处理异步请求。这个 Middleware 会拦截 type 为 FETCH_DATA 的 Action,发起异步请求,并根据请求结果派发对应的 Action。

需要注意的是,上面的例子中,我们使用了 redux-thunk 这个库来处理异步请求。redux-thunk 是一个常用的 Middleware 库,它允许我们在 Action 中返回一个函数,这个函数可以在其中进行异步请求并派发对应的 Action。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值