1、ES6、ES7、ES8中关于异步函数的处理办法
JS中常用的实现异步的方法
- 利用setTimout实现异步
<script>
var t=true;
window.setTimeout(function(){
t=false;
},1000);
while(t){
}
alert('end');
</script>
// 结果 死循环 setTimeout不执行 也导致alert不执行
// js是单线程 所以会先执行while(t){}再alert
// 但是这个是死循环 所以不会执行alert
// 为什么不执行setTimeout 因为js的工作机制
// 当线程中没有执行任何同步代码的前提下 才会执行异步代码
// setTimeout是异步代码 所有setTimeout只能等js空闲才会执行
// 但是死循环是永远不会空闲的 所以setTimeout也永远不会执行
-
动态创建script实现异步
var head = document.getElementByTagName('head')[0]; var script = document.createElement('script'); script.src = 'index.js'; head.appendChild('script');
-
利用script提供的defer/async
<script src="xx.js" defer></script>
defer:当页面加载完毕以后才去执行这段代码。
<script src="xx.js" async></script>
-
回调函数实现异步
callback函数
-
Promise(ES6)
原理分析
new Promise(function(resolve,reject){
//也可以包含非异步操作,但这些代码要在异步执行之前执行完毕
//包含一个异步函数,比如定时器或者像Ajax等
if(异步完成){
resolve()
}else{
reject()
}
})
jquery封装Promise对象和ajax过程
var jqGetAjaxPromise = function(param){
return new Promise(function(resolve, reject){
$.ajax({
url: param.url,
type: 'get',
data: param.data || '',
success: function(data){
resolve(data);
},
error: function(error){
reject(error)
}
});
});
};
// 调用示例
var p2 = jqGetAjaxPromise({
url: 'cross-domain1.txt'
});
p2.then(function(data){
console.log(data);
return jqGetAjaxPromise({
url:'cross-domain2.txt'
});
}).then(function(data2){
console.log(data2);
}).catch(function(err){
console.log(err);
});
/**
在newPromise的时候 对象内部已经开始执行
Promise内部有一个defers队列存放事件
其实就是Promise之中始终存放着.then
异步事件的状态 改变会去触发它
**/
再说的明白一点就是,你的数据和数据操作的分离。因为本来Promise也不是一个新的功能,只是一种新的写法,只是将回调函数的嵌套改成了链式调用,清晰结构而已。其实并没有多么复杂的逻辑性。
链式调用
-
连续的链式调用
let p = new Promise((resolve, reject) => { setTimeout(resolve, 1000, 'success'); }); p.then( res => { console.log(res); return `${res} again`; } ) .then( res => console.log(res) ); // success // success again
-
前一个then()方法中的回调函数中又可能返回一个Promise实例,这时候后面一个then()方法中的回调函数会等前一个Promise实例的状态发生变化才会调用。
let p = new Promise((resolve, reject) => { setTimeout(resolve, 1000, 'success'); }); p.then( res => { console.log(res); return new Promise((resolve, reject) => { setTimeout(resolve, 1000, 'success'); }); } ) .then( res => console.log(res) ); // 相隔1000ms // success // success
常用方法
-
.then() / .catch()
返回值/捕捉Promise内部错误 -
Promise.all()
可以同时调用多个Promise实例,已数组的形式传入。规定必须多个Promise实例全部为resolve状态才执行 .then,只要其中有一个错误,就立即抛出
3、Promise.resolve()
将不是Promise的对象转为Promise,并且是resolve状态
4、Promise.finally()------------ES2018
不管 Promise 对象最后状态如何,都会执行的操作
小练习
1、判断输出以及相应的时间
let doSth = new Promise((resolve, reject) => {
console.log('hello');
resolve();
});
setTimeout(() => {
doSth.then(() => {
console.log('over');
})
}, 10000);
//马上console.log(hello),然后隔10s后输出over
2、判断输出顺序
setTimeout(function() {
console.log(1)
}, 0);
new Promise(function executor(resolve) {
console.log(2);
for( var i=0 ; i<10000 ; i++ ) {
i == 9999 && resolve();
}
console.log(3);
}).then(function() {
console.log(4);
});
console.log(5);
Promise执行输出2,调用resolve,再输出3,然后调用then将输出4置于事件循环末尾,然后输出5,到达末尾,输出4,下一个事件循环,输出刚开始的1,所以顺序是23541
-
async (ES7)
async和await是ES7新增的规范它们要一起出现才有效果 它是Generator的升级版。
async 函数的实现原理,就是将 Generator 函数和自动执行器,包装在一个函数里。var stop= function (time) { return new Promise(function (resolve, reject) { setTimeout(function () { resolve(); }, time); }) }; var start = async function () { // 在这里使用起来就像同步代码那样直观 console.log('start'); var result = await stop(3000); console.log('end'); }; start();
//先出start,3000ms之后出现end
只有当await定义的函数执行完了代码才会继续往下执行,同时await还有有返回值,他的返回值在上面这个例子中就是resolve,reject的值需要通过try {}catch(err){},捕获:
var start = async function () {
// 在这里使用起来就像同步代码那样直观
console.log('start');
try{
await stop(3000);
}catch(err){
console.log(err);
}
console.log('end');
};
start();
注意:await后面的应该跟一个Promise的对象或者fetch
- fetch (ES8)
这个方法是ES2017中新增的特性,这个特性出来后给人一种传统ajax已死的感觉,其实它的作用是替代浏览器原生的XMLHttpRequest异步请求,我们在日常的开发中,基本不会自己去写XMLHttpRequest,主要是太复杂了,都是使用已经封装好了的各种插,件常用的有jquery,npm包管理工具也提供了axios,request等模块。而有了fetch后我们就可以在不用这些插件的情况下快速简单的实现异步请求了:
1、
get请求:
var word = '123',
url = 'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd='+word+'&json=1&p=3';
fetch(url,{mode: "no-cors"}).then(function(response) {
return response;
}).then(function(data) {
console.log(data);
}).catch(function(e) {
console.log("Oops, error");
});
2、post请求:
var headers = new Headers();
headers.append("Content-Type", "application/json;");
fetch(url, {
method: 'post',
headers: headers,
body: JSON.stringify({
date: '2016-10-08',
time: '15:16:00'
})
});
3、jsonp
目前原生的fetch还不支持jsonp的请求方式,如果需要实现jsonp,需要安装npm包fetchJ-jsonp
fetchJsonp(url, {
timeout: 3000,
jsonpCallback: 'callback'
}).then(function(response) {
console.log(response.json());
}).catch(function(e) {
console.log(e)
});
网友评论