async react 使用

2018-01-19 10:29:50 oKeYue 阅读数 2533


本教程总共6篇,每日更新一篇,请关注我们!你可以进入历史消息查看以往文章,也敬请期待我们的新文章!


1、React项目配置1(如何管理项目公共js方法)---2018.01.11


2、React项目配置2(自己封装Ajax)---2018.01.12


3、React项目配置3(如何管理项目API接口)---2018.01.15


4、React项目配置4(如何在开发时跨域获取api请求)---2018.01.16


5、React项目配置5(引入MockJs,实现假接口开发)---2018.01.17


6、React项目配置6(前后端分离如何控制用户权限)---2018.01.18


7、React项目配置6(ES7的Async/Await的使用)---2018.01.19(新增)


开发环境:Windows 8,node v8.9.1,npm 5.5.1,WebStorm 2017.2.2


我们今天讲下ES7的Async/Await的使用!

1、首先需要改造下AJAX请求

    我们新建 xmlNative.js文件,把公共部分抽取出来!

const xmlNative = (opt, type) => {
opt = opt || {};
   opt.method = opt.method.toUpperCase() || 'POST';
   opt.url = opt.url || '';
   opt.async = opt.async || true;
   opt.data = opt.data || null;
   opt.success = opt.success || function () {
};
   let xmlHttp = new XMLHttpRequest();
   if (opt.method.toUpperCase() === 'POST') {
xmlHttp.open(opt.method, opt.url, opt.async);
       xmlHttp.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
       xmlHttp.send(JSON.stringify(opt.data));
   } else if (opt.method.toUpperCase() === 'GET') {
let params = [];
       for (let key in opt.data) {
params.push(key + '=' + opt.data[key]);
       }
let postData = params.join('&');
       xmlHttp.open(opt.method, opt.url + '?' + postData, opt.async);
       xmlHttp.send(null);
   }
if (type === 1) {
return new Promise((resolve, reject) => {
xmlHttp.onreadystatechange = () => {
if (xmlHttp.readyState === 4) {
if (xmlHttp.status === 200) {
let responseText = JSON.parse(xmlHttp.responseText);
                       if (responseText.code === 0) {
resolve(responseText.data)
} else {
reject(responseText.message)
}
} else {
reject(JSON.parse(xmlHttp.responseText), xmlHttp.status)
}
}
};
       })
} else {
xmlHttp.onreadystatechange = () => {
if (xmlHttp.readyState === 4) {
if (xmlHttp.status === 200) {
opt.success(JSON.parse(xmlHttp.responseText), xmlHttp.status)
} else {
opt.error(JSON.parse(xmlHttp.responseText), xmlHttp.status)
}
}
};
   }

};
export default xmlNative



2.修改之前的 apiRequest.js

import xmlNative from './xmlNative'
import apiManager from './apiManager'

const ajax = (url, method, data, successCB, errorCB) => {
let dataJson = {
version: "1.0.0",
       data: data
};
   return xmlNative({
method: method,
       url: url,
       data: dataJson,
       success: (data, status) => {
if (data.code === 0) {
successCB && successCB(data, status)
} else {
errorCB ? errorCB(data, status) : console.log(data, status)
}
},
       error: (data, status) => console.log(status, status)
});
};
const apiRequest = {
get: (apiName, data, successCB, errorCB) => ajax(apiManager[apiName], "get", data,
       data => successCB && successCB(data.data, data.systemDate),
       errorCB),
   post: (apiName, data, successCB, errorCB) => ajax(apiManager[apiName], "post", data,
       data => successCB && successCB(data.data, data.systemDate),
       errorCB)
};
export default apiRequest;

3.新建apiRequestAsync.js

import xmlNative from './xmlNative'
import apiManager from './apiManager'

const ajax = (url, method, data) => {
let dataJson = {
version: "1.0.0",
       data: data
};
   return xmlNative({
method: method,
       url: url,
       data: dataJson
}, 1);
};
const apiRequestAsync = {
get: (apiName, data) => ajax(apiManager[apiName], "get", data),
   post: (apiName, data) => ajax(apiManager[apiName], "post", data)
};
export default apiRequestAsync;

到这里就封装完了,我讲解下一些地方,如果没讲到的地方,大家不懂的可以留言问我!

if (type === 1) {
return new Promise((resolve, reject) => {
xmlHttp.onreadystatechange = () => {
if (xmlHttp.readyState === 4) {
if (xmlHttp.status === 200) {
let responseText = JSON.parse(xmlHttp.responseText);
                   if (responseText.code === 0) {
resolve(responseText.data)
} else {
reject(responseText.message)
}
} else {
reject(JSON.parse(xmlHttp.responseText), xmlHttp.status)
}
}
};
   })

这个type完全是自定义的,type===1的时候,返回一个Promise,因为await等待的就是一个 Promise!

4.我们来测试一下

先看看原来的请求是否还正常

一切正常!

5.为什么要用 es7 async await

它主要是为了解决如下场景:

比如需求是我的请求的某个参数是需要上一个请求的结果:

类是于这样:

这样请求下去,会进入到回调地域里!

所有用es7 async await来解决这个问题

6、那怎么写呢?

其实也很简单,之前我们已经封装好了,我们来写下试试!

这里需要安装一个依赖,

npm i -S babel-polyfill

引入

import "babel-polyfill";
import apiRequestAsync from '../../../public/js/apiRequestAsync';

书写 es7 async await

async handleTodoList() {
let todoList = await apiRequestAsync.post('todoList');
   this.setState({list: todoList.list});
   let todoList1 = await apiRequestAsync.post('todoList');
   console.log(todoList1);
   let todoList2 = await apiRequestAsync.post('todoList');
   console.log(todoList2);
}



OK,看下浏览器效果

它渲染了 todolist,也打印出了todoList1及todoList2。

本文完 

禁止擅自转载,如需转载请在公众号中留言联系我们!

感谢童鞋们支持!

如果你有什么问题,可以在下方留言给我们!



2018-12-13 12:11:58 well2049 阅读数 6359

async/await 是个非常好用的处理的异步的es8新功能。

在react中使用也是特别方便的,如果你是通过create-react-app 创建的项目就不要担心浏览器的支持。直接使用即可。

直接上代码演示,我的axios是经过封装过后Promise。使用原生的也是一样效果,axios原生返回的也是Promise ,所以可以直接 通过let result = awiat Promise 中resolve 和 reject 的结果

requestUserData = async() => {       
        let roleId = this.state.selectedItem.roleId;
        this.params.conditionId = roleId;
        
        let noAuthUserResult = await axios.ajax({
            url: api.sys_auth_user_selectForPageNoAuthUser,
            data: this.params
        })
        let authUserResult = await axios.ajax({
            url: api.sys_auth_user_selectForPageAuthUser,
            data: this.params
        })
        if (!noAuthUserResult.status && !authUserResult.status){
            let targetKeys=[];
            let noAuthUserResultList = noAuthUserResult.data.recordList.map((item) => {
                item.key = item.userId;
                return item;
            });
            let authUserResultList = authUserResult.data.recordList.map((item) => {
                item.key = item.userId;
                targetKeys.push(item.userId);
                return item;
            });

            this.setState({
                leftData: [...noAuthUserResultList, ...authUserResultList],
                targetKeys: targetKeys,
                isVisibleTransfer: true
            })
        }else{
            Modal.info({
                title: "请求数据失败",
                content: ""
            })
        }        
    } 
2019-05-10 13:53:13 zhuming3834 阅读数 1157

之前在vue中使用axios《vue 开发axios的封装async/await》。这里其实就是把之前vue中封装的axios 移植过来的。基本没变。这里不再多说了。

封装

// 网络请求 可以使用 async/await

// 引入 axios
import axios from 'axios'

// 测试地址
// axios.defaults.baseURL = '';    
// 线上地址
// axios.defaults.baseURL = '';  
// demo地址
// axios.defaults.baseURL = '';  
axios.defaults.timeout = 10000;  // 超时时间  10s

var http = {

  /** get 请求
   * @param  {接口地址} url
   * @param  {请求参数} params
   */
  get: function(url,params){
    params = params || {}
    return new Promise((resolve,reject) => {
      axios.get(url,{
        params:params
      })
      .then((res) => {
        resolve( res.data);
      })
      .catch((error) => {
        reject( error );
      });
    })
  },
  /** post 请求
   * @param  {接口地址} url
   * @param  {请求参数} params
   */
  post: function(url,params){
    params = params || {};
    return new Promise((resolve,reject) => {
      axios.post(url,params)
      .then((res) => {
        resolve( res.data );
      })
      .catch((error) => {
        reject( error );
      });
    })
  }
}

export default http


使用

import React from 'react';
import { Link } from 'react-router-dom';
import http from '../assets/js/http'

class Home extends React.Component {

    // 获取IP
    async getMyIP(){
        let baseUrl = "https://api.apiopen.top/EmailSearch";
        let params = {
            number: '1012002'
        }
        var data = await http.get(baseUrl,params);
    }
    render() {
        return (
            <div className='home'>
                <Link to="/detail">Home</Link>
                我是首页
            </div>
        );
    }
    componentDidMount() {
        this.getMyIP();
    }
}

export default Home;
2019-05-12 09:10:46 weixin_33933118 阅读数 101

前言

async/await 语法用看起来像写同步代码的方式来优雅地处理异步操作,但是我们也要明白一点,异步操作本来带有复杂性,像写同步代码的方式并不能降低本质上的复杂性,所以在处理上我们要更加谨慎, 稍有不慎就可能写出不是预期执行的代码,从而影响执行效率。下面将简单地描述一下一些日常常用场景,加深对 async/await 认识

最普遍的异步操作就是请求,我们也可以用 setTimeOut 来简单模拟异步请求。

场景1. 一个请求接着一个请求

相信这个场景是最常遇到,后一个请求依赖前一个请求,下面以爬取一个网页内的图片为例子进行描述,使用了 superagent 请求模块, cheerio 页面分析模块,图片的地址需要分析网页内容得出,所以必须按顺序进行请求。


const request = require('superagent')
const cheerio = require('cheerio')
// 简单封装下请求,其他的类似

function getHTML(url) {
// 一些操作,比如设置一下请求头信息
return superagent.get(url).set('referer', referer).set('user-agent', userAgent)
}
// 下面就请求一张图片
async function imageCrawler(url) {
    let res = await getHTML(url)
    let html = res.text
    let $ = cheerio.load(html)
    let $img = $(selector)[0]
    let href = $img.attribs.src
    res = await getImage(href)
    retrun res.body
}
async function handler(url) {
    let img = await imageCrawler(url)
    console.log(img) // buffer 格式的数据
    // 处理图片
}
handler(url)
复制代码

上面就是一个简单的获取图片数据的场景,图片数据是加载进内存中,如果只是简单的存储数据,可以用流的形式进行存储,以防止消耗太多内存。

其中 await getHTML 是必须的,如果省略了 await 程序就不能按预期得到结果。执行流程会先执行 await 后面的表达式,其实际返回的是一个处于 pending 状态的 promise,等到这个 promise 处于已决议状态后才会执行 await 后面的操作,其中的代码执行会跳出 async 函数,继续执行函数外面的其他代码,所以并不会阻塞后续代码的执行。

场景2.并发请求

有的时候我们并不需要等待一个请求回来才发出另一个请求,这样效率是很低的,所以这个时候就需要并发执行请求任务。下面以一个查询为例,先获取一个人的学校地址和家庭住址,再由这些信息获取详细的个人信息,学校地址和家庭住址是没有依赖关系的,后面的获取个人信息依赖于两者


async function infoCrawler(url, name) {
    let [schoolAdr, homeAdr] = await Promise.all([getSchoolAdr(name), getHomeAdr(name)])
    let info = await getInfo(url + `?schoolAdr=${schoolAdr}&homeAdr=${homeAdr}`)
    return info
}
复制代码

上面使用的 Promise.all 里面的异步请求都会并发执行,并等到数据都准备后返回相应的按数据顺序返回的数组,这里最后处理获取信息的时间,由并发请求中最慢的请求决定,例如 getSchoolAdr 迟迟不返回数据,那么后续操作只能等待,就算 getHomeAdr 已经提前返回了,当然以上场景必须是这么做,但是有的时候我们并不需要这么做。

上面第一个场景中,我们只获取到一张图片,但是可能一个网页中不止一张图片,如果我们要把这些图片存储起来,其实是没有必要等待图片都并发请求回来后再处理,哪张图片早回来就存储哪张就行了


let imageUrls = ['href1', 'href2', 'href3']
async function saveImages(imageUrls) {
    await Promise.all(imageUrls.map(async imageUrl => {
    let img = await getImage(imageUrl)
    return await saveImage(img)
}))
    console.log('done')
}
// 如果我们连存储是否全部完成也不关心,也可以这么写
let imageUrls = ['href1', 'href2', 'href3']
// saveImages() 连 async 都省了
function saveImages(imageUrls) {
    imageUrls.forEach(async imageUrl => {
    let img = await getImage(imageUrl)
    saveImage(img)
    })
}
复制代码

可能有人会疑问 forEach 不是不能用于异步吗,这个说法我也在刚接触这个语法的时候就听说过,很明显 forEach 是可以处理异步的,只是是并发处理,map 也是并发处理,这个怎么用主要看你的实际场景,还要看你是否对结果感兴趣

场景3.错误处理

一个请求发出,可以会遇到各种问题,我们是无法保证一定成功的,报错是常有的事,所以处理错误有时很有必要, async/await 处理错误也非常直观, 使用 try/catch 直接捕获就可以了


async function imageCrawler(url) {
    try {
        let img = await getImage(url)
        return img
    } catch (error) {
        console.log(error)
    }
}
// imageCrawler 返回的是一个 promise 可以这样处理
async function imageCrawler(url) {
    let img = await getImage(url)
    return img
}
imageCrawler(url).catch(err => {
    console.log(err)
})
复制代码

可能有人会有疑问,是不是要在每个请求中都 try/catch 一下,这个其实你在最外层 catch 一下就可以了,一些基于中间件的设计就喜欢在最外层捕获错误


async function ctx(next) {
    try {
        await next()
    } catch (error) {
        console.log(error)
    }
}
复制代码

场景4. 超时处理

一个请求发出,我们是无法确定什么时候返回的,也总不能一直傻傻的等,设置超时处理有时是很有必要的


function timeOut(delay) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
        reject(new Error('不用等了,别傻了'))
        }, delay)
    })
}

async function imageCrawler(url,delay) {
    try {
        let img = await Promise.race([getImage(url), timeOut(delay)])
        return img
    } catch (error) {
        console.log(error)
    }
}
复制代码

这里使用 Promise.race 处理超时,要注意的是,如果超时了,请求还是没有终止的,只是不再进行后续处理。当然也不用担心,后续处理会报错而导致重新处理出错信息, 因为 promise 的状态一经改变是不会再改变的

场景5. 并发限制

在并发请求的场景中,如果需要大量并发,必须要进行并发限制,不然会被网站屏蔽或者造成进程崩溃


async function getImages(urls, limit) {
    let running = 0
    let r
    let p = new Promise((resolve, reject) => {
    r = resolve
    })
    function run() {
        if (running < limit && urls.length > 0) {
            running++
            let url = urls.shift();
            (async () => {
                let img = await getImage(url)
                running--
                console.log(img)
                if (urls.length === 0 && running === 0) {
                    console.log('done')
                    return r('done')
                } else {
                    run()
                }
            })()
            run()  // 立即到并发上限
        }
    }
    run()
    return await p
}
复制代码

总结

以上列举了一些日常场景处理的代码片段,在遇到比较复杂场景时,可以结合以上的场景进行组合使用,如果场景过于复杂,最好的办法是使用相关的异步代码控制库。如果想更好地了解 async/await 可以先去了解 promise 和 generator, async/await 基本上是 generator 函数的语法糖,下面简单的描述了一下内部的原理。


function delay(time) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(time)
        }, time)
    })
}
function *createTime() {
    let time1 = yield delay(1000)
    let time2 = yield delay(2000)
    let time3 = yield delay(3000)
    console.log(time1, time2, time3)
}
let iterator = createTime()
console.log(iterator.next())
console.log(iterator.next(1000))
console.log(iterator.next(2000))
console.log(iterator.next(3000))
// 输出

{ value: Promise { <pending> }, done: false } 

{ value: Promise { <pending> }, done: false }

 { value: Promise { <pending> }, done: false } 

1000 2000 3000 

{ value: undefined, done: true }

复制代码

可以看出每个 value 都是 Promise,并且通过手动传入参数到 next 就可以设置生成器内部的值,这里是手动传入,我只要写一个递归函数让其自动添进去就可以了


function run(createTime) {
    let iterator = createTime()
    let result = iterator.next()
    function autoRun() {
        if (!result.done) {
            Promise.resolve(result.value).then(time => {
            result = iterator.next(time)
            autoRun()
        }).catch(err => {
            result = iterator.throw(err)
            autoRun()
            })
        }
    }
    autoRun()
}
run(createTime)
复制代码

promise.resove 保证返回的是一个 promise 对象 可迭代对象除了有 next 方法还有 throw 方法用于往生成器内部传入错误,只要生成内部能捕获该对象,生成器就可以继承运行,类似下面的代码


function delay(time) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (time == 2000) {
            reject('2000错误')
        }
            resolve(time)
        }, time)
    })
}
function *createTime() {
    let time1 = yield delay(1000)
    let time2
    try {
        time2 = yield delay(2000)
    } catch (error) {
        time2 = error
    }
    let time3 = yield delay(3000)
    console.log(time1, time2, time3)
}
复制代码

可以看出生成器函数其实和 async/await 语法长得很像,只要改一下 async/await 代码片段就是生成器函数了


async function createTime() {
    let time1 = await delay(1000)
    let time2
    try {
        time2 = await delay(2000)
    } catch (error) {
        time2 = error
    }
    let time3 = await delay(3000)
    console.log(time1, time2, time3)
}

function transform(async) {
  let str = async.toString()
  str = str.replace(/async\s+(function)\s+/, '$1 *').replace(/await/g, 'yield')
  return str
}
复制代码

转载于:https://juejin.im/post/5cd7d3e86fb9a032447f16b4

2018-05-03 10:33:41 Juniorselk 阅读数 5540

在React经常会有需要通过异步请求返回的数据,然后再setState到state中的操作。但是经常会因为异步的问题,导致数据显示有误,这里我通过async解决这个问题,下面是代码。

async componentDidMount() {
const data = await get(`url`)
    this.setState({
      data: data
    })
  }
}
get是通过fetch封装的请求。

ReactNative await和async

阅读数 1983