JavaScript异步编程 学习笔记

文章内容输出来源:拉勾大前端高薪训练营

单线程 JavaScript 异步方案:

1、采用单线程模式工作的原因

主要是跟他的设计初衷有关,最早它就是运行在浏览器端的脚本语言,目的为了实现页面上的交互,而实现页面交互的核心就是dom操作,这就决定了它必须使用单线程模型,否则就会出现多线程同步问题。

JS 执行环境中负责执行代码的线程只有一个。

  • 优点:安全简单
  • 缺点:无法同时处理大量耗时任务,耗时任务会阻塞主程序的执行。
    如果遇到一个特别耗时的任务,后面的任务都必须排队等待这个业务的结束,导致整个程序的执行被拖延,出现假死的情况。

为了解决js 耗时任务阻塞执行的问题,JavaScript 将任务的执行模式分为两种:同步模式(Synchronous)和 异步模式(Asynchronous)

2、同步模式 和 异步模式

同步模式:按照代码的顺序,排队等待执行
异步模式:不会等待这个任务的结束才开始下一个任务,对于耗时操作,开启之后,就立即往后执行下一个任务,后续逻辑一般会通过回调函数的方式定义,在内部耗时任务完成后就自动执行回调函数。

这种模式很重要,因为 单线程的 JavaScript 语言就无法同时处理大量耗时任务。

  • 难点:代码的执行顺序混乱,所以需要理解和习惯,多看、多练、多思考

\color{#FF0000}{注意:我们说的同步和异步模式,不是指我们写代码的方式, 而是运行环境提供的api 是以同步或异步模式的方式工作。}
js是单线程,但是浏览器不是单线程,通过js调用的某些内部api不是单线程的。

例如:倒计时器
它内部就有一个单独的线程去负责倒数,时间到了之后将回调放入消息队列
我们说的单线程是执行我们代码的是单线程,但是内部api会用单独的线程执行这些等待的操作

同步API和异步API的区别

同步api 的特点:代码执行完才继续往下走。例如: console.log
异步api的特点:下达任务开启的指令之后就继续往下走,代码不等待任务结束,例如:setTimeout

3、回调函数

  • 是所有异步编程方案的根基
  • 可以理解为一件你想要做的事情
  • 调用者定义,执行者执行

4、Promise:一种更优的异步编程统一方案

详细说明:Promise:一种更优的异步编程统一方案 学习笔记

promise 就是一个对象,表示一个异步任务最终结束过后是成功还是失败,就像是内部对外界做的一个承诺,明确结果之后不能更改。

  • 目的:为了避免回调地狱的问题,为异步编程题提供一种更合理,更强大的统一解决方案
  • 注意:即便 promise 中没有任何的异步操作,then方法中指定的回调函数,仍然会进入到回调队列中排队,也就是必须要等到同步代码执行完了,这里才会执行。
const promise = new Promise(function( resolve, reject){
  //这里兑现“承诺”
  resolve(100);  //承诺达成
  //reject(new Error('promise rejected'));  //承诺失败
});
promise.then(function(value){
  console.log(value);
}, function(value){
  console.log(value);
})
console.log('end');
//结果:end、100

5、Generator 异步方案

Generator 函数是ES2015 提供 的生成器函数。

  • 它就是在普通的函数的基础之上多了一个*,调用一个生成器函数并不会立即去执行这个函数,而是得到一个生成器对象,指导我们手动调用这个对象的next方法,这个函数的函数体才会开始执行。
  • 在函数内部可以随时使用 yield 关键词 向外返回一个值,可以在 next 方法返回对象中的value拿到这个返回的值,这个返回的对象中还有一个 done 属性,用来表示这个生成器是否全部执行完了
  • yield 关键词 不会像 return 语句一样 立即结束 函数的执行,只是 暂停 生成器函数的执行,直到外部再次调用生成器对象的next 方法时,它就会继续从yield 位置往 下执行。
  • 调用 next 时 如果传递参数,参数会作为 yield 的返回值,可以在 yield 的左边接收到这个值
  • 调用生成器对象的 throw 方法,可以对生成器函数内部抛出异常,继续执行会得到异常,可以通过 try catch 得到这个异常
//Generator 配合 Promise 的异步方案
function ajax(url){
  return new Promise(function(resolve, reject){
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.responseType = 'json';
    xhr.onload = function (){  //请求完成 也就是 readyStatus = 4 才会执行
      if(this.status == 200){
        resolve(this.response);
      }else{
        reject(new Error(this.statusText));
      }
    }
    xhr.send();
  })
}
function * main (){
  try {
  // users.json : [  {   "name": "张三",  "age": 13  },{ "name": "里斯", "age": 20}]
    const users = yield ajax('/api/users.json'); 
    console.log(users);
  // urls.json : [  "/api/urls.json", "/api/users.json"]
    const urls = yield ajax('/api/urlss.json');
    console.log(urls);
  } catch (error) {
    console.log(error);
  } 
}
// const res = g.next();
// res.value.then( data => {
//   const res2 = g.next(data);
//   console.log(res2);
//   if(res2.done) return
//   res2.value.then( data => {
//     const res3 = g.next(data);
//     console.log(res3);
//   })
// })
function co(generator){
  const g = generator();
  // 递归
  function handleResult(result){
    if(result.done) return; //生成器函数结束
    result.value.then( data => {
      handleResult(g.next(data))
    }, error => {
      g.throw(error)
    })
  }
  handleResult(g.next());
}
co(main)

执行结果


6、Async、Await 语法糖

它是 语言层面的异步编程标准,提供扁平化的异步编程体验。
它就是生成器函数更方便的语法糖。语法上 跟 Generator 函数类似,只需要把生成器函数 修改成 async 的普通函数,yield 替换成 await。

  • async 返回一个 promise 对象,更加利于整体代码的控制
  • async 中的 await 只能出现在 async 中,不能在外部单独使用
//Generator 配合 Promise 的异步方案
function ajax(url){
  return new Promise(function(resolve, reject){
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.responseType = 'json';
    xhr.onload = function (){  //请求完成 也就是 readyStatus = 4 才会执行
      if(this.status == 200){
        resolve(this.response);
      }else{
        reject(new Error(this.statusText));
      }
    }
    xhr.send();
  })
}
async function main (){
  try {
    const users = await ajax('/api/users.json');
    console.log(users);

    const urls = await ajax('/api/urlss.json');
    console.log(urls);
  } catch (error) {
    console.log(error);
  } 
}
main()

执行结果同上

你可能感兴趣的:(JavaScript异步编程 学习笔记)