黑马程序员技术交流社区

标题: 总结javascript处理异步的方法 [打印本页]

作者: 逆风TO    时间: 2020-3-25 14:31
标题: 总结javascript处理异步的方法
javascript语言的执行环境是单线程(single thread),就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推。
这种模式的好处是实现起来比较简单,执行环境相对单纯;但是只要耗时比较多,假如有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。为了解决这个问题,Javascript语言将任务的执行模式分成两种:同步(Synchronous)和异步(Asynchronous)。
Javascript处理异步的方法有以下几种:
回调函数回调是一个函数被作为一个参数传递到另一个函数里,在那个函数执行完后再执行。回调函数是异步编程最基本的方法,其优点是简单、容易理解和部署;缺点是容易产生回调地狱。

[JavaScript] 纯文本查看 复制代码
ajax('XXX1', () => {
  // callback 函数体
  ajax('XXX2', () => {
    // callback 函数体
    ajax('XXX3', () => {
      // callback 函数体
    })
  })
})

这就是所谓的回调地狱,回调地狱带来的负面作用有以下几点:
事件监听这种方式,异步任务的执行不取决于代码的顺序,而取决于某个事件是否发生。
f1.on('done', f2);复制代码上面这行代码的意思是,当f1发生done事件,就执行f2。

[JavaScript] 纯文本查看 复制代码
element.onclick=function(){
   //处理函数
}

element.onclick=handler1;
element.onclick=handler2;
element.onclick=handler3;
// 只有handler3会被添加执行


该方法的第三个参数是一个布尔值:当为false时表示由里向外,true表示由外向里。
发布/订阅模式我们假定,存在一个"信号中心",某个任务执行完成,就向信号中心"发布"(publish)一个信号,其他任务可以向信号中心"订阅"(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做"发布/订阅模式"(publish-subscribe pattern)
首先,f2向信号中心jQuery订阅done信号。
jQuery.subscribe('done', f2);
然后,f1进行如下改写:
[JavaScript] 纯文本查看 复制代码
function f1() {
  setTimeout(function () {
    jQuery.publish('done');
  }, 1000);
}

f1执行完成后,向信号中心jQuery发布done信号,从而引发f2的执行。f2完成执行后,可以取消订阅(unsubscribe)
jQuery.unsubscribe('done', f2);复制代码这种方式的优点:可以通过查看“消息中心”,了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行。
promise以上都是ES6之前的异步处理方式。ES6之后出现了promise。它是异步编程的一种解决方案,比传统的解决方案(回调函数)——更合理和更强大。
Promise 对象有以下两个特点。
基本用法
[JavaScript] 纯文本查看 复制代码
const promise = new Promise((resolve, reject) => {
  if (/* 异步操作成功 */){
    resolve(success)
  } else {
    reject(error)
  }
})


Promise接收一个函数作为参数,函数里有resolve和reject两个参数:
[JavaScript] 纯文本查看 复制代码
promise.then((success) => {
  // 对应于上面的resolve(success)方法
}, (error) => {
  // 对应于上面的reject(error)方法
}


// 还可以写成这样 (推荐使用这种写法)
promise.then((success) => {
  // 对应于上面的resolve(success)方法
}).catch((error) => {
  // 对应于上面的reject(error)方法
})


then(onfulfilled,onrejected)方法中有两个参数,两个参数都是函数:

[JavaScript] 纯文本查看 复制代码
const promise = new Promise((resolve, reject) => {
  console.log(1)
  resolve()
  console.log(2)
})

promise.then(() => {
  console.log(3)
})

console.log(4)
// 1  2  4   3

Promise.finally()
Promise.finally()用于指定不管 Promise 对象最后状态如何,都会执行的操作。
[JavaScript] 纯文本查看 复制代码
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
Promise.all()Promise.all()用于处理多个异步处理,比如说一个页面上需要等多个 ajax 的数据回来才执行相关逻辑。
const p = Promise.all([p1, p2, p3]);复制代码p的状态由p1、p2、p3决定,分成两种情况。
Promse.race()Promse.race()就是赛跑的意思,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
[JavaScript] 纯文本查看 复制代码
const p = Promise.race([p1, p2, p3])

上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
async/awaitasync/await是JavaScript为了解决异步问题而提出的一种解决方案,许多人将其称为异步的终极解决方案。async 函数,就是 Generator 函数的语法糖。
相较于 Generator,Async 函数的改进在于下面四点:
async/await使用规则
[JavaScript] 纯文本查看 复制代码
async function test() {
   
}

let result = test()
console.log(result)  //即便代码里test函数什么都没返回,我们依然打出了Promise对象




[JavaScript] 纯文本查看 复制代码
function test() {
  let result = await Promise.resolve('success')
  console.log(result)
}

test()   //执行以后会报错

await 在等什么


文章转载自链接:https://juejin.im/post/5e7ab8325188255e3629a161















欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2