异步就是比较耗时的操作,CPU缓存的速度是最快的,然后是内存,然后是硬盘,所以从硬盘上读取文件是非常慢的,js认为从硬盘上读取文件是一个异步操作;另外一种是网络请求,这种也是异步的;操作dom节点也是非常耗时的,但却是同步操作,因为作为异步来处理比较麻烦。
promise就是一个承诺,在js中就是承诺过段时间会返回一个结果,而这个过段时间就指的是异步操作。
promise本质上是一个有限状态机,状态机指的是根据特定的条件按照一定的顺序进行转换,而且过程不可逆。每个promise实例都有三种状态:pending、resolve、reject。在状态机中,需要某些条件才能将自己的状态触发。
状态只有两种:从初始状态到成功:pending->resolve;从初始状态到失败:pending->reject。promise实例状态机状态的变化会触发promise原型上的then或catch方法的执行
DOM规范是运行在浏览器上的规范,比如navigator,只在dom上有,在node上没有;而ECMAScript规范,不仅在浏览器中可以使用,也可以在node.js中使用。
如何构建一个promise
构建一个promise实例需要给promise构造函数传入一个有两个形参的函数,第一个形参运行后会让promise实例处于resolve状态,所以一般用resove表示成功状态;第二个形参运行后会让promise实例处于reject状态,所以一般用reject表示失败状态。new出来的promise实例,有两个方法(then,catch,then捕获成功的操作,catch捕获失败的操作。),并且可以链式调用。在使用的时候,要将then放在catch的上面,这是因为then里的错误也可以在catch中捕获到,如代码所示:
let promiseInstance = new Promise((resolve,reject) =>{
setTimeOut(() => {
resolve('this is resolve.')
})
})
promiseInstance
.then((value)=>{console.log(value)}).catch((err)=>{console.error(err)})
promise是处理异步的,而网络请求是异步最常见的场景,所以可以用promise封装一个网络请求的方法,所以很多时候promise的实例是作为函数的返回值是,调用函数后可以对返回值的Promise对象进行相应的操作
function ajaxPromise(){
return new Promise((resolve,reject) => {
let xhr = new XMLHttpRequest();
xhr.open('get',queryUrl,true);
xhr.send(null);
xhr.onReadyStatechange = () => {
if(xhr.readyState === 4){
if(xhr.status === 200){
resolve(xhr.responseText);
}else{
reject(xhr.responseText)
}
}
}
})
}
ajaxPromise('http://api.github.com/')
.then((value) => {
console.log(value);
})
.catch((err) => {
console.error(err)
})
then与catch的使用
状态机的状态是不可逆的,所以执行了resolve方法,就算再执行reject方法,也不会有效果了。
promise的api
promise实例上的方法
promise.prototype.then()
promise.prototype.catch()
promise构造函数上的方法
promise.all(Array) 返回一个promise,等待参数中所有的promise都处于resolve状态后会触发返回的promise实例的resolve状态
promise.race(Array) 返回一个promise,参数中第一个执行完成的状态决定出发哪个函数
promise.resolve() 立刻返回一个resolve状态的实例
promise.reject() 立刻返回一个reject状态的实例
let promise1 = new Promise((resolve,reject)=>{
setTimeout(resolve,1000,'success1')
})
let promise2 = new Promise((resolve,reject)=>{
setTimeout(resolve,1000,'success12')
})
let promise3 = new Promise((resolve,reject)=>{
setTimeout(resolve,1000,'success3')
})
Promise.all([promise1, promise2, promise3]).then((value)=>{
console.log(value)
}).catch((err)=>{
console.error(err)
})
tips:setTimeOut的第三个参数,是第一个函数参数执行的时候,要传入的参数
promise.then的执行时机
promise.resolve是处理异步问题的,所以会先把同步的代码执行完,再执行promise.resolve返回实例的then或catch的代码
而Promise构造函数是同步的,then方法是异步的。setTimeOut的执行时机是最晚的
promise并不是处理异步最好的方法,比如回调金字塔的问题并没有解决,只是看起来更清晰了。解决异步最好的方法是async
generator
有点像一个函数内部有多个函数,是一个状态机,yield生成
function* genFunc(){
yield 'hello';
yield 'generator';
yield '!'
return 'end'//generator不建议使用return
}
generator返回的不是返回值,也不是一个生成的内容,而是一个迭代器,迭代器是一个可遍历的对象,迭代器有个next方法。通过for-of循环遍历迭代器
连续运行的generator
function* genFunc(initValue){
let first = yield new Promise((resolve,reject)=>{
setTimeOut(resolve,1000,'1'+initValue)
})
let second = yield new Promise((resolve,reject)=>{
setTimeOut(resolve,1000,'2-'+first)
})
let third = yield new Promise((resolve,reject)=>{
setTimeOut(resolve,1000,'3-'+second)
})
let genHandler = genFunc(1)
genHandler.next().value.
then((value) => {
genHandler.next(value).value.
then((value) => {
then((value) => {
console.log(value);
})
})
})
}
co库与async函数
import co from 'co'
上述代码中依然有回调金字塔,可以用co库解决
co(genFunc(1)).then((value) => {console.log(value)})//2-11
async相当于是generator+promise+co,是es7的新语法,目前没有浏览器实现,所以需要用webpack+babel编译一下才可以运行。
如何同步异步请求,即两次请求,异步执行,如何在两次请求都执行完成的情况下执行后续程序
function request(content){
setTimeout(()=>{
document.body.append(content)
},Math.floor(Math.random()*1000)) //时间控制为不确定
}
request('hello')
request('world')
//如何在两次request完成后执行代码。可以使用promise.all,只要两个异步有一个完成就可以,可以使用promise.race
docuement.body.append('finished')
如何处理回调嵌套回调
//珠峰课堂是先去服务端拿取token,然后再去拿课程
fetch('https://ketang.zhufengpeixun.cn/token')
.then(response => {
response.json().then(tokenJson =>{
const token = tokenJson
fetch('https:ketang.zhufengpeixun.cn/course')
.then( response =>{
response.json().then(tokenJson =>{
}
})
})
})
promise定义:用于异步计算,代表一个当前、未来或永远不可用的值
//promise中的代码段被直接执行了
const promise = new Promise((resolve,reject){
document.body.append('hello')
})
const a = () =>{
document.body.append('world')
}
a();
//执行结果是hello world
//用promise表示一个未来的值
function resolve_example(){
const promise = new Promise((resolve,reject)=>{
document.body.append('start.....');
setTimeout(()=>{//promise代表了一个未来值
resolve('done')
},2000)
})
return promise;
}
const promise = resolve_example();
//得到一个未来完成的值,此处data是异步返回的部分
promise.then(data => {
document.body.append(data)
})
promise有三种状态,当被new出来的时候属于pending状态,使用resolve则是fulfill状态,使用reject则是fail状态
Executor是构造Promise的唯一参数,在promise构造的时候会被马上执行