强大的promise
这个玩意叫做普罗米修斯,希腊神话的盗火英雄
promise只用来包装异步函数,同步的会搞乱执行顺序,生产BUG
// 如何使用 function pro(){ return new Promise(function(resolve,reject){ setTimeout(function(){ var num = parInt(Math.random()*10); if(num>5){ resolve(num) // 这个可以写成 // return Promise.resolve(num) }else{ reject(num) // 这个可以写成 // return Promise.reject(num) } },5000) }) } // pro()这个返回的是一个pending的Promise对象 // Promise可以被then启动,参数有两个,跟new的时候对应也是两个 // new的时候第一个参数传递成功,then的时候第一个参数接受成功 // new的时候第二个参数传递失败,then的时候第二个参数接受失败 pro().then((res)=>{ ... },(error)=>{ ... })
这个api是有固定写法的,用来把回调的异步函数转成链式的异步函数
先看看传统的回调型异步函数
function ajax1(){ ajax({ sucess:function(res1){ //回调ajax2,或者直接把第二个ajax写在这里面 ajax2(res1) } }) } function ajax2(res1){ ajax({ sucess:function(res2){ ... } }) } ajax1()
Promise写法
function ajax1(){ return new Promise((resolve,reject)=>{ ajax({ sucess:function(res1){ //回调ajax2,或者直接把第二个ajax写在这里面 resolve(res1) } }) } } function ajax2(){ return new Promise((resolve,reject)=>{ ajax({ sucess:function(res2){ //回调ajax2,或者直接把第二个ajax写在这里面 resolve(res2) } }) } } ajax1().then((res1)=>{ return ajax2(res1) }).then((res2)=>{ ... })
promise.resolve
let res = Promise.resolve("123") res.then(res=>{ console.log(res) })
promise.reject
let res = Promise.reject("123") res.then(res=>{ console.log(res) })
Promise.all
这个使用在几个异步函数需要同时请求但是相互不关联的情况
常用来作为初始化加载使用
Promise.all([promise1, promise2, promise3]).then((values) => { console.log(values); },(error)=> { console.log(error) }); // 如果上面几个promise函数没有全部返回成功,就会指向error
看了上面的写法觉得也不过如此是吧,有没有改变,代码还变多了,我也是这么觉得的,直到看到Promise配合async使用
async
这个是Generator函数的语法糖
什么是语法糖,就是更简易的使用,二次封装
什么是Generator函数,这个是es6的api,还没被人知道就被他的语法糖async给抢了头条,所以不管,知道语法糖async怎么用就行
任何函数都可以在前面加上单词async
把函数升级成异步管理函数
async只能在该函数的作用域里使用,如果是函数里的函数就得再写一次async了
async要跟await配合使用,否则没有存在意义
await要连接一个promise函数,primise要是一个异步函数
这几个点不遵守肯定会有一些执行顺序等等的BUG
function ajax1(){ return new Promise((resolve,reject)=>{ ajax({ sucess:function(res1){ //回调ajax2,或者直接把第二个ajax写在这里面 resolve(res1) } }) } } function ajax2(opt){ return new Promise((resolve,reject)=>{ ajax({ sucess:function(res2){ //回调ajax2,或者直接把第二个ajax写在这里面 resolve(res2) } }) } } async function init(){ var res1 = await ajax1() var opt = res1 + 1; //模拟正常的方法什么的 var res2 = await ajax2(opt) } init()
上面的代码如果是同步代码我们是很好理解的,但是因为是异步的,就不好理解了,正常来说因为ajax1和ajax2是异步的,res1和res2只会拿到undefined,这种运行顺序根本巅峰了对异步的理解,你确定这样的代码执行下来没问题?
有没有问题可以自己试试
async错误处理
// 统一处理 async function init(){ try{ var aa = await A() var bb = await B() }catch(err) { console.log(err) } } // 单独处理 async function init(){ const [err, data] = await A().then(data => [null, data]).catch(err => [err, null]) const [err, data] = await B().then(data => [null, data]).catch(err => [err, null]) } // 上面的优化写法 // 抽离成公共方法 const awaitWrap = (promise) => { return promise .then(data => [null, data]) .catch(err => [err, null]) } async function init(){ const [err, data] = await awaitWrap(A()) const [err, data] = await awaitWrap(B()) }
如何理解async呢
我们可以认为await阻塞了线程,如果有了解过java,在java里有个yeild的方法,这个方法就是await的语法糖,这个API让异步变成了同步,让代码更加的好理解
做一个网络测速
网络测速的前提是服务器超大的带宽
原理是让前端递归去获取服务器的图片获得下载的网速,再把图片转base64递归上传获得上传的网速,我做了五个实验
第一个
var index = 10; function yi() { var start = new Date().getTime() var img = document.createElement("img"); var num = Math.random() img.src = './img/xxx.png?num=' + num; img.onload = function (res){ var end = new Date().getTime() console.log("递归----"+(end-start)) index--; if(index!=0){ yi() } } } yi()
第二个
var index = 10; var promiseArr = []; function getImg() { return new Promise(function (resolve, reject) { var start = new Date().getTime() var img = document.createElement("img"); var num = Math.random() img.src = './img/girs.png?num=' + num; img.onload = function (res){ var end = new Date().getTime() console.log("Promise.all----"+(end-start)) resolve(end-start); } }) } function er() { for(var i=0;i<10;i++){ promiseArr.push(getImg()) } Promise.all(promiseArr).then() } er()
第三个
function getImg() { return new Promise(function (resolve, reject) { var start = new Date().getTime() var img = document.createElement("img"); var num = Math.random() img.src = './img/girs.png?num=' + num; img.onload = function (res){ var end = new Date().getTime() console.log("10次await-----"+(end-start)) resolve(end-start); } }) } async function san() { var allTime = 0; allTime += await getImg(); allTime += await getImg(); allTime += await getImg(); allTime += await getImg(); allTime += await getImg(); allTime += await getImg(); allTime += await getImg(); allTime += await getImg(); allTime += await getImg(); allTime += await getImg(); } san()
第四个
function getImg() { return new Promise(function (resolve, reject) { var start = new Date().getTime() var img = document.createElement("img"); var num = Math.random() img.src = './img/girs.png?num=' + num; img.onload = function (res){ var end = new Date().getTime() console.log("for(x){await x}-----"+(end-start)) resolve(end-start); } }) } async function si() { var arr = [] for(var i=0;i<10;i++){ arr.push(getImg()) } for (const x of arr){ await x; } } si()
第五个
function getImg() { return new Promise(function (resolve, reject) { var start = new Date().getTime() var img = document.createElement("img"); var num = Math.random() img.src = './img/girs.png?num=' + num; img.onload = function (res){ var end = new Date().getTime() console.log("for await(x){x}+-----"+(end-start)) resolve(end-start); } }) } async function wu() { var arr = [] for (var i=0;i<10;i++){ arr.push(getImg()) } for await(const x of arr){ x; } } wu()
这五个代码的执行时间都不一样,为什么还得研究
封装一个promise版本的ajax
function ajax(url, method = 'get', param = {}) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); const paramString = getStringParam(param); if (method === 'get' && paramString) { url.indexOf('?') > -1 ? url += paramString : url += `?${paramString}` } xhr.open(method, url); xhr.onload = function () { const result = { status: xhr.status, statusText: xhr.statusText, headers: xhr.getAllResponseHeaders(), data: xhr.response || xhr.responseText } if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) { resolve(result); } else { reject(result); } } // 设置请求头 xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); // 跨域携带cookie xhr.withCredentials = true; // 错误处理 xhr.onerror = function () { reject(new TypeError('请求出错')); } xhr.timeout = function () { reject(new TypeError('请求超时')); } xhr.onabort = function () { reject(new TypeError('请求被终止')); } if (method === 'post') { xhr.send(paramString); } else { xhr.send(); } }) } function getStringParam(param) { let dataString = ''; for (const key in param) { dataString += `${key}=${param[key]}&` } return dataString; }