JavaScript 异步编程

163 阅读4分钟

image.png

1.同步模式

任务依次执行,当前任务执行完,才能执行下一个任务

2.异步模式

特点

  • 不会等待这个任务的结束才开始下一个任务
  • 开启过后就立即往后执行下一个任务(对耗时操作)
  • 后续逻辑一般通过回调函数的方式定义

其他:如果没有这种模式的话,单线程的JS语言就无法同时处理大量耗时任务

console.log('global begin')
setTimeout(function timer1 () {
	console.log('timer1 invoke')
}, 1800)
setTimeout(function timer2 () {
	console.log('timer2 invoke')
    setTimeout(function inner () {
    console.log('inner invoke')
    }, 1000)
}, 1000)
console.log('global end')
//global begin
//global end
//timer2 invoke
//timer1 invoke
//inner invoke

896.PNG 总体过程:

  • JS线程某一时刻发起异步调用,然后执行本轮其他任务
  • 此时异步线程单独执行异步任务,执行完任务过后,将任务的回调放入消息队列
  • js主线程完成所有的任务过后,会依次执行消息队列中的任务

补充:

1.事件循环的作用:

  • 监听调用栈和消息队列
  • 一旦调用栈中所有的任务都结束,就会从消息队列中取出第一个回调函数
  • 然后压入调用栈

2.同步和异步不是指写代码的方式,而是运行环境提供的API是以同步或异步模式的方式工作

3.回调函数

function foo (callback) {
  setTimeout(function () {
    callback()
  }, 3000)
}

foo(function () {
  console.log('这就是一个回调函数')
  console.log('调用者定义这个函数,执行者执行这个函数')
  console.log('其实就是调用者告诉执行者异步任务结束后应该做什么')
})


// 回调地狱,只是示例,不能运行

$.get('/url1', function (data1) {
  $.get('/url2', data1, function (data2) {
    $.get('/url3', data2, function (data3) {
      $.get('/url4', data3, function (data4) {
        $.get('/url5', data4, function (data5) {
          $.get('/url6', data5, function (data6) {
            $.get('/url7', data6, function (data7) {
              // 略微夸张了一点点
            })
          })
        })
      })
    })
  })
})

4.Promise

1.promise的基本流程

896666.PNG

2.基本代码
//1.创建promise对象(pending状态),
const p=new Promise((resolve,reject)=>{
	//2.在执行器函数中启动异步任务
    setTimeout(()=>{
		const time=Data.now()
        //3.根据结果做不同的处理
        //3.1如果成功,调用resolve(),指定成功的value,状态变为resolved
        if(time%2===1){
            resolve('成功的值'+time)
        }else{
			//3.1如果失败,调用reject(),指定失败的reason,变为rejected状态
            reject('失败的值'+time)
        }
    },2000)
})
//通过promise指定成功或失败的回调函数来获取成功的value或失败的reason
p.then(
    value=>{ //成功的回调函数onResolved,得到成功的value
        console.log('成功的value',value)
    },
    reason=>{ //失败的回调函数onRejected,得到失败的reason
		console.log('失败的reason',reason)
    }
)
3.API
  1. Promise 构造函数: Promise (excutor) {} excutor 函数: 同步执行 (resolve, reject) => {} resolve 函数: 内部定义成功时我们调用的函数 value => {} reject 函数: 内部定义失败时我们调用的函数 reason => {} 说明: excutor 会在 Promise 内部立即同步回调,异步操作在执行器中执行

  2. Promise.prototype.then 方法: (onResolved, onRejected) => {}

    onResolved 函数: 成功的回调函数 (value) => {}

    onRejected 函数: 失败的回调函数 (reason) => {}

    说明: 指定用于得到成功 value 的成功回调和用于得到失败 reason 的失败回调 返回一个新的 promise 对象

  3. Promise.prototype.catch 方法: (onRejected) => {}

    onRejected 函数: 失败的回调函数 (reason) => {}

  4. Promise.resolve 方法: (value) => {}

    value: 成功的数据或 promise 对象

    说明: 返回一个成功/失败的 promise 对象

  5. Promise.reject 方法: (reason) => {}

    reason: 失败的原因

    说明: 返回一个失败的 promise 对象

  6. Promise.all 方法: (promises) => {}

    promises: 包含 n 个 promise 的数组

    说明: 返回一个新的 promise, 只有所有的 promise 都成功才成功, 只要有一个失败了就直接失败

  7. Promise.race 方法: (promises) => {}

    promises: 包含 n 个 promise 的数组

    说明: 返回一个新的 promise, 第一个完成的 promise 的结果状态就是最终的 结果状态

5.Generator

1.函数名称前面加一个星号表示它是一个生成器

2.调用生成器函数会产生一个生成器对象,生成器对象一开始处于暂定执行的状态,它与迭代器相似,生成器对象也实现了Iterator接口,因此具有next()方法,调用它可以让生成器开始或者恢复执行

3.next的返回值类似于迭代器,有一个done属性和value属性。函数体为空的生成器函数中间不会停留,调用一次next()就让生成器达到done:true

4.value属性是生成器函数的返回值,默认为undefined,可以通过生成器函数的返回值指定

5.yield关键字可以让生成器停止和开始执行。生成器函数在遇到yield关键字之前都会正常执行,遇到之后,会停止,函数作用域的状态会被保留。只有通过next()来恢复执行

6.throw()方法会在暂停的时候将一个提供的错误注入生成器对象,提前终止生成器

// 生成器函数回顾

function * foo () {
  console.log('start')

  try {
    const res = yield 'foo'
    console.log(res)
  } catch (e) {
    console.log(e)
  }
}

const generator = foo()

const result = generator.next()
console.log(result)


// generator.next('bar')

generator.throw(new Error('Generator error'))

6.Async

  • 使用 async / await, 搭配 promise, 可以通过编写形似同步的代码来处理异步流程
  • await 操作符用于等待一个 Promise 对象, 它只能在异步函数 async function 内部使用
  • 使用 async function 可以定义一个 异步函数