异步编程的理解

回调函数

函数也是一种数据类型,既可以做参数,又可以充当返回值

传统的函数

直接通过return 返回结果

function add (x,y){
    return x+y
}
add(10,20)

异步函数

函数封装了异步的操作

异步操作:

setTimeout

setInterval

ajax

node中的文件操作

一般异步API都伴随一个回调函数

function add (x,y){
    setTimeout(() => {
       var ret = x + y 
    },1000)
}
add(10,20)
//思考:把函数的结果ret弄出来

错误思路

1.return (错误,实现不了)

2.使用全局变量存储(变量在全局,封装没意义了)

function add (x,y){
    setTimeout(() => {
       var ret = x + y 
      // return ret 错,此处的return只能返回给延时器里的函数
    },1000)
    //return ret  错 拿不到延时器里的ret
}
add(10,20)

var ret
function add (x,y){
    setTimeout(() => {
       ret = x + y 
    },1000)
}
add(10,20)
setTimeout(() =>{
    console.log(ret)
},1000)

正确思路 : 把回调函数做参数

目的1 : 获取函数内部的异步操作结果

function add (x,y,callback){
    setTimeout( () => {
        var ret = x + y
        callback(ret)
    },1000)
}
add(10,20,ret => {
    console.log(ret)
})

目的2 : 在异步操作完成后再调用函数

function fn (callback){
    setInterval( () => {
        callback()
    },1000 )
}
fn( () => {
    //定时器结束后,执行的回调函数
    console.log('定时器结束后,要做的任务')
} )

回调地狱

多层异步嵌套

  1. 异步(不嵌套)无法控制顺序( 缺点 : 异步的执行顺序不固定)
fs.readFile('a.txt', 'utf8',(err,data) =>{
    if(err){
        throw err
    }
    console.log(data)
})
fs.readFile('b.txt', 'utf8',(err,data) =>{
    if(err){
        throw err
    }
    console.log(data)
})
fs.readFile('c.txt', 'utf8',(err,data) =>{
    if(err){
        throw err
    }
    console.log(data)
})
  1. 通过回调嵌套方式 控制顺序

    会出现新的问题 : 回调地狱

fs.readFile('a.txt', 'utf8',(err,data) =>{
    if(err){
        throw err
    }
    console.log(data)
        fs.readFile('b.txt', 'utf8',(err,data) =>{
        if(err){
            throw err
        }
        console.log(data)
                fs.readFile('c.txt', 'utf8',(err,data) =>{
            if(err){
                throw err
            }
            console.log(data)
        })
    })
})

Promise

为什么用Promise

使用Promise来解决 异步编程回调(传统的异步编程是 回调函数+事件)

什么是Promise

同步的方式编写代码处理异步操作的一种 解决方案

  • 特点 :

    • 对象的状态不受外界影响

      只有异步操作的结果,可以决定当前是哪一种状态,任何操作都无法改变这个状态

      • pending : 初始值 ,表示进行中
      • fulfilled : 表示操作成功
      • rejected : 表示操作失败
  • 一旦状态改变,就不会再变

    • pending ---> fulfilled
    • pending ---> rejected
    • ,只要这两种情况发生,就称为resolved(已定型)
  • 优点

    • 把异步操作以同步操作的流程表达出来,避免层层嵌套的回调函数
    • Promise对象提供了接口,操作更容易
  • 缺点

    • 无法取消Promise(一旦创建后就会立即执行,中途无法取消)
    • 如果不设置回调,Promise内部抛出的错误,不会反应到外部
    • 当处于pending状态时,无法得知当前是哪一阶段

Promise基本使用

使用步骤

  • 使用 new Promise(callback) 或者快捷方式 Promise.resolve() Promise.reject()
  • callback中指定要处理的异步操作
    • 处理成功 ,调用 resolve
    • 处理失败 ,调用 reject
// resolve : 把Promise对象的状态 从 pending--> resolved,并把异步操作成功的结果传递出去
// reject : 把Promise对象的状态 从 pending--> rejected,并返回异步操作报出的错误信息
const promise = new Promise( (resolve,reject) => {
        if(/*异步操作成功判断*/){
            resolve(data)
        }else{
            reject(err)
        }
})
//如果promise实例的状态发生改变,就会触发then方法绑定的回调
promise.then(data => {
   	 console.log(data) //111
   	 },err => {
    	console.log(err) //222
    })

promise的执行顺序

promise本身是同步的, 而promise内部有异步方法

//异步 --- 宏任务(下次循环执行的)
setTimeout( () => {
    console.log('setTimeout')
},1000 )
const promise = new Promise( (resolve,reject) => {
    console.log('promise')
    resolve()
})
//异步 ---- 微任务 (本次循环执行的)
promise.then( () => {
    console.log('promise1')
})
console.log('outer')
//promise
//outer
//promise1
//setTimeout
补充 : 宏任务和微任务

macro-task(宏任务):包括整体代码script,setTimeout,setInterval
micro-task(微任务):Promise,process.nextTick
先执行宏任务(下一次循环执行) , 再执行微任务 (本次循环执行)
在这里插入图片描述

Promise的API

.then

语法:Promise.prototype.then(onFulfilled, onRejected)

onFullfilled : promise调用resolve()后触发该回调

onRejected : promise调用reject()后触发该回调

作用 : 为Promise实例添加状态改变时的回调函数

返回值 : 返回新的promise实例

//把异步操作封装起来
function timeout(txt) {
    return new Promise( (resolve,rejecte) => {
        setTimeout ( () =>  resolve(txt) ,1000 )
    } )
}
timeout('111')
    .then( data => {
		console.log(data) //111
    	return timeout('222')
   	 })
    .then (data => {
        console.log(data) //在111输出后延迟1秒 后输出 222
    	return timeout('333')
    })
    .then (data => {
        console.log(data) //延迟2秒后 输出333
    	return ....//可以继续嵌套
    })
.catch

语法:Promise.prototype.catch(onRejected)

onRejected :发生错误时触发的回调

//封装ajax
const p = new Promise( (resolve,reject) => {
    $.ajax({
        url:'xxx',
        data:'xxx',
        success:resolve,
        error : reject
    })
})
p.then(res => {}).catch(err => {})
.all

语法:Promise.all(iterable)

作用 : 将多个Promise实例,包装成一个新的 v实例

多个Promise实例是同时开始,并行执行的,而不是顺序执行的

多个异步 都 完成才执行then

function timeouts(timer){
    return new Promise( (resolve,reject) => {
        setTimeout( () => {resolve(timer)},1000)
    })
}
let startTime = Date.now()
Promise.all( [
    timeouts(1),
    timeouts(500),
    timeouts(1000),
    timeouts(1500),
]).then( res => {
    console.log(Date.now() - startTime + 'ms')
  	console.log(res)
})

//1501ms
//[ 1, 500, 1000, 1500 ]
.race

语法 : Promise.race(iterable)

作用 : 也是将多个Promise实例 ,包装成一个新的Promise实例

只要有一个异步完成,就调用then,通俗的讲,就是谁跑的快,就返回谁,

function timeouts(timer){
    return new Promise( (resolve,reject) => {
        setTimeout( () => {resolve(timer)},1000)
    })
}
let startTime = Date.now()
Promise.race( [
    timeouts(2000),
    timeouts(500),
    timeouts(1000),
    timeouts(1500),
]).then( res => {
    console.log(Date.now() - startTime + 'ms')
  	console.log(res)
})
//507ms
//500
.resolve

语法 : Promise.resolve()

作用 : 将参数 转成一个promise对象, resolve状态

Promise.resolve('success').then( res => {
    console.log(res) //success
})

//等同于
new Promise( (resolve,reject) => {
    resolve('success')
}).then( res => {
    console.log(res) //success
})
.reject

语法 : Promise.reject()

作用 : 将参数 转成一个promise对象, reject状态

 Promise.reject('aaa').then( res =>{
     console.log(res)).catch(err => {
         console.log(err) //aaa
     })

Async/await

promise协同工作

Async

async : 异步

作用 : 函数总是返回一个promise对象,如果代码中有 return <非promise>语句,JavaScript会自动把 返回的值 包装成promise的resolved值

注意 : 要放在函数的前面 async function f(){}

async function f(){
    return 1
}
f().then(alert) //1

async function f() {
    return Promise.resolve(1)
}
f().then(alert) // 1

Await

await : 等待

作用 : 等待一个异步操作的结果(promise实例)

注意 : 必须和async配合使用 await 异步操作

async function f(){
    let p = await new Promise( (resolve,reject) => {
        setTimeout(resolve,3000)
    })
    console.log(p)
}

注意点

  • asyncawait 必须成对出现
async function fn(){
    let res = await /*异步操作*/
    console.log(res) //异步操作的结果
}
  • async 一定要加到await最近的函数上面
function fn(){
    async function f(){
        let res = await /*异步操作*/
    	console.log(res) //异步操作的结果
	}
}
  • 使用 try....catch处理异常
async function f(){
    try{
        let res = await /*异步操作*/
   	 	console.log(res) //异步操作的结果
        }catch(error){
            console.log('异步操作失败')
        }
}

async/await 和 promise.then/.catch

  • 使用 async/await 来代替 .then/.catch,更方便
  • 特例, 当在async外部处理异步时,只能使用 .then/.catch
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值