美文网首页
js 异步系列(1) -发展

js 异步系列(1) -发展

作者: Super曲江龙Kimi | 来源:发表于2019-08-18 10:03 被阅读0次

ajax

最早为了实现局部请求无刷新,有了ajax的概念。在原生js是时代,请求数据都需要自己手写一个ajax。现在还有很多面试题会让手写一个ajax

// 先实例化一个XMLHttpRequest对象
const xhr = new XMLHttpRequest()

// xhr 具有一个 open 方法,相当于填写配置先初始化。这时候没有发出请求
// method: 请求方式 —— get / post
// url:请求的地址
// async:是否异步请求,默认为 true(异步)
xhr.open(method, url, async)

// send 方法发送请求,并接受一个可选参数
// 当请求方式为 post 时,可以将请求体的参数传入
// 当请求方式为 get 时,可以不传或传入 null
xhr.send(data)

// xhr上有一个readyStatus值。他会随着请求的阶段不同而变化:
// xhr.readyStatus==0 尚未调用 open 方法
// xhr.readyStatus==1 已调用 open 但还未发送请求(未调用 send)
// xhr.readyStatus==2 已发送请求(已调用 send)
// xhr.readyStatus==3 已接收到请求返回的数据
// xhr.readyStatus==4 请求已完成

// 当readyStatus变化时都会执行onreadystatechange 回调。
// responseText: 请求返回的数据内容
// status: 响应的HTTP状态,如 200 304 404 等
xhr.onreadystatechange = () => {
    if (xhr.readyStatus === 4) {
        if (xhr.status >= 200 && 
            xhr.status < 300 || 
            xhr.status == 304) {
            console.log('请求成功', xhr.responseText)
        }
    }
}

// 设置超时时间为1000毫秒
xhr.timeout = 1000

jquery

后来在jquery盛行的时代。将ajax封装成了一个函数。可以直接调用

$.ajax({  
  type : "POST",
  url:'http://aaaa.com',
  async:true,
  dataType:'json',
  data:{a:'aa'},
  success :function(msg){
      //请求成功函数
  },
  error:function(err){
      //请求失败函数
  }
});

jquery1.5之后

var ajax = $.ajax('data.json')
ajax.done(function () {
        console.log('success 1')
    })
    .fail(function () {
        console.log('error')
    })
    .done(function () {
         console.log('success 2')
    })

console.log(ajax) // 返回一个 deferred 对象

区别:
之前返回的是一个XHR对象,这个对象不可能有done或者fail的方法的
1.5开始返回一个deferred对象,这个对象就带有done和fail的方法,并且是等着请求返回之后再去调用

promise前身

// 改造前
var wait = function() {
    var task = function () {
        console.log('ok')
    }
    setTimeout(task, 2000)
}
wait()
// 改造后  
function waitHandle() {
    var dtd = $.Deferred()  
    var wait = function(dtd) {
        var task = function() {
            console.log('ok');
            dtd.resolve()
            // dtd.reject() 
        }
        setTimeout(task, 2000)
        return dtd.promise() // 返回promise对象,使用时不可以修改状态。promise的前身
    }
    
    return wait(dtd);
}   
waitHandle().then();    

1.5改造之后最大的好处就是可以通过then的方法来链式调用。不再会有回调地狱。而且状态一旦改变,也不能再变成其他状态了。和之后的promise一样。

promise

es6中将之前社区中的方案正式纳入标准,制定了promise/A+规范。也就可以直接的使用promise

const getJSON = function(url) {
  const promise = new Promise(function(resolve, reject){
    const handler = function() {
      if (this.readyState !== 4) {
        return;
      }
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
    const client = new XMLHttpRequest();
    client.open("GET", url);
    client.onreadystatechange = handler;
    client.responseType = "json";
    client.setRequestHeader("Accept", "application/json");
    client.send();

  });

  return promise;
};

getJSON("/posts.json").then(function(json) {
  console.log('Contents: ' + json);
}, function(error) {
  console.error('出错了', error);
});

generator

promise的出现只是回调函数的改进,使用then方法以后,异步任务的两段执行看得更清楚了,会造成代码冗余。一堆的then。如下

var readFile = require('fs-readfile-promise');

readFile(fileA)
.then(function (data) {
  console.log(data.toString());
})
.then(function () {
  return readFile(fileB);
})
.then(function (data) {
  console.log(data.toString());
})
.catch(function (err) {
  console.log(err);
});

于是有了更好的解决方案---generator

var fetch = require('node-fetch');

function* gen(){
  var url = 'https://api.github.com/users/github';
  var result = yield fetch(url);
  console.log(result.bio);
}

var g = gen();
var result = g.next();

result.value.then(function(data){
  return data.json();
}).then(function(data){
  g.next(data);
});

Generator 函数可以暂停执行和恢复执行,这是它能封装异步任务的根本原因。虽然 Generator 函数将异步操作表示得很简洁,但是流程管理却不方便,需要执行器`控制他什么时候执行第一步,什么时候执行第二步。并且传递参数。

于是有了co这种流程管理库。

简单的流程管理如下。会一直执行下去。

function* gen() {
  // ...
}

var g = gen();
var res = g.next();

while(!res.done){
  console.log(res.value);
  res = g.next();
}

async await --终极方案

async function getStockPriceByName(name) {
  const symbol = await getStockSymbol(name);
  const stockPrice = await getStockPrice(symbol);
  return stockPrice;
}

getStockPriceByName('goog').then(function (result) {
  console.log(result);
});

好处
(1)内置执行器。
Generator 函数的执行必须靠执行器,所以才有了co模块,而async函数自带执行器。也就是说,async函数的执行,与普通函数一模一样,只要一行。

getStockPriceByName();

上面的代码调用了getStockPriceByName函数,然后它就会自动执行,输出最后结果。这完全不像 Generator 函数,需要调用next方法,或者用co模块,才能真正执行,得到最后结果。

(2)更好的语义。
async和await,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。

(3)更广的适用性。
co模块约定,yield命令后面只能是 Thunk 函数或 Promise 对象,而async函数的await命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。

(4)返回值是 Promise。
async函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then方法指定下一步的操作。

进一步说,async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。

在nodejs中已经使用async 、 await做为异步操作的解决方案

相关文章

  • js 异步系列(1) -发展

    ajax 最早为了实现局部请求无刷新,有了ajax的概念。在原生js是时代,请求数据都需要自己手写一个ajax。现...

  • js异步发展简史

    什么是异步? 所谓异步,简单来说就是异步任务(不会马上就完成的任务);但是js不会等待你这个任务完成,而是直接执行...

  • JS异步发展历程

    最近在看nodejs相关的内容,正好有提到几个异步调用的例子,于是想借着这个机会整理一下JS的异步发展历程,做下整...

  • JS中的同步异步

    目录 1. 在JS中,什么是同步异步? 2. JS中常见的异步代码 1. 在JS中,什么是同步异步? 通俗解释一下...

  • web前端面试3

    1 JS异步解决方案的发展历程以及优缺点 1,回调函数(无法捕获错误(使用try catch) 不能return)...

  • AJAX

    AJAX 定义Asynchronous JavaScript and XML(异步JS和XML)一系列web技术的...

  • 你不知道的JS(中卷)第七章

    第七章 回调 回调是js异步的基本单元。随着js越来越成熟,对于异步编程的发展,回调已经不够用了。回调表达异步流的...

  • JS异步那些事 一 (基础知识)

    JS异步那些事 一 (基础知识)JS异步那些事 二 (分布式事件)JS异步那些事 三 (Promise)JS异步那...

  • JS异步那些事 三 (Promise)

    JS异步那些事 一 (基础知识)JS异步那些事 二 (分布式事件)JS异步那些事 三 (Promise)JS异步那...

  • JS异步那些事 四(HTML 5 Web Workers)

    JS异步那些事 一 (基础知识)JS异步那些事 二 (分布式事件)JS异步那些事 三 (Promise)JS异步那...

网友评论

      本文标题:js 异步系列(1) -发展

      本文链接:https://www.haomeiwen.com/subject/vizlsctx.html