美文网首页
2020-10-28promise(二)

2020-10-28promise(二)

作者: 夏天的风2020 | 来源:发表于2020-10-28 13:33 被阅读0次

异步操作前置知识
jS是单线程的
就是同一时间只能处理一个任务。就类似生活中的去超市排队结账,正常情况下,以为收银员只能为一位顾客结账,其他顾客需要在后面排队等候。

为什么js是单线程的?作为浏览器脚本语言,javascript的主要用途是与用户互动,以及操作DOM,
这决定了它只能是单线程,否则会带很复杂的同步问题。比如,假定javascript同时有两个线程,
一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?

单线程就意味着,所有任务都需要排队,前一个任务结束,才能执行后一个任务。如果前一个任务耗
时很长,那么后一个任务就不得不一直等待,于是乎,js设计师们就把所有的任务分成两类,同步和异步。

同步:只有前一个任务执行完毕,才能执行后一个任务。
异步:当同步任务执行到某个WebAPI时,就会触发异步操作,此时浏览器就会单独开线程去处理这些
    异步任务

同步

    const a = 2
    const b = 3
    console.log(a+ b)

异步

  setTimeout(()=>{
    console.log(a+ b)
  },1000)

请思考下面的输出结果是什么?

   console.log(1)
    setTimeout(()=>{ //异步任务,放入任务队列中
    console.log(2)
    },0)
   console.log(3)

 //输出结果 1,3,2

下图说明了同步任务和异步任务的执行过程


task.9fef93a6.png

Ajax原理
Ajax即'Asyncchronous Javascript And XML'(即异步javascript和XML),是指一种创建交互式,快速动态
网页应用的网页开发技术,无需重新加载整个网页的情况下,能够更新部分网页的技术。
通过在后台与服务器进行少量数据交换,Ajax可以使网页异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。

    //创建XMLHttpRequest对象
      const  url =  'http://www.baidu.com'
      let xmlhttp 
      if(window.XMLHttpRequest){ //code for IE7+,Firefox,Chrom,Opera,Safari
        xmlhttp = new XMLHttpRequest()
      }else{
        xmlhttp = new ActiveXObject('Microsoft.XMLHTTP')
      }
      //发送请求
      xmlhttp.open('GET',url,true)
      xmlhttp.send() 
      //服务端相应
      xmlhttp.onreadystatechaneg = function(){
        if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
          let obj = JSON.parse(xmlhttp.responseText)
        }
      }

Callback Hell

JavaScipt 中的许多操作都是异步的,我们把上面的Ajax封装成一个函数:

function ajax(url, callback) {
    let xmlhttp
    if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari
        xmlhttp = new XMLHttpRequest()
    } else { // code for IE6, IE5
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP")
    }
    // 发送请求
    xmlhttp.open("GET", url, true)
    xmlhttp.send()
    // 服务端响应
    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
            //    console.log(xmlhttp.responseText)
            let obj = JSON.parse(xmlhttp.responseText)
            callback(obj)
        }
    }
}

a.json:

{
    "a": "我是A"
}

b.json:

{
    "b": "我是B"
}

c.json:

{
    "c": "我是C"
}

我们可以像这样使用:

// 加载并执行脚本
ajax('/static/a.json')

函数是异步调用的,因为操作不是立即完成的,而是之后才会完成。

ajax('/static/a.json')
// 下面的代码不会等到ajax执行完才执行
// ...

这个过程大家并不陌生,可是如果在回调之后再回调呢?

ajax('static/a.json', res => {
    console.log(res)
    ajax('static/b.json', res => {
        console.log(res)
        ajax('static/c.json', res => {
            console.log(res)
        })
    })
})

如果嵌套变多,代码层次就会变深,维护难度也随之增加。
这就被称为 “回调地狱” 或者“回调深渊”。

基本语法

Promise 就是为了解决“回调地狱”问题的,它可以将异步操作的处理变得很优雅。
回调地狱,代码难以维护, 常常第一个的函数的输出是第二个函数的输入这种现象promise可以支持多个并发的请求,获取并发请求中的数据这个promise可以解决异步的问题,
本身不能说promise是异步的。

创建Promise实例。

const promise = new Promise(function(resolve, reject) {
    // ... some code
    if ( /* 异步操作成功 */ ) {
        resolve(value)
    } else {
        reject(error)
    }
})

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。

  1. 处理结果正常的话,调用resolve(处理结果值),将Promise对象的状态从“未完成”变为 “成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果, 作为参数传递出去
    2.处理结果错误的话,调用reject(Error对象),将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。

promise.then(function(value) {
    // success
}, function(error) {
    // failure
})

then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。

下面是一个Promise对象的简单例子。

function timeout(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, ms, 'done');
  });
}

timeout(100).then((value) => {
  console.log(value);
});

上面代码中,timeout方法返回一个Promise实例,表示一段时间以后才会发生的结果。过了指定的时间(ms参数)以后,Promise实例的状态变为resolved,就会触发then方法绑定的回调函数。

Promise 新建后就会立即执行。

let promise = new Promise(function(resolve, reject) {
  console.log('Promise');
  resolve();
});

promise.then(function() {
  console.log('resolved.');
});

console.log('Hi!');

// Promise
// Hi!
// resolved

上面代码中,Promise 新建后立即执行,所以首先输出的是Promise。
然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,
所以resolved最后输出。

一个栗子:

    var promise = new Promise(function (resolve, reject) {
        console.log("good");
        var a = 10;
        var b = a + 25;
        if ( b === 35 ) {
            // 一旦异步执行成功,我们就调用内置的 resolve函数,将pending状态转化为resolved,并且传入我们希望传出的执行成功后的结果。
            // 注意: 这里一旦状态转变,那么后面就一定会调用then方法中的第一个参数的函数,然后将我们传入给resolve的参数传给then方法中的第一个方法作为参数,我们就可以在then的第一个方法中使用了。
            resolve(b);
        } else {
            reject("异步执行失败");
        }
    });
    promise.then(function (value) {
        console.log("异步执行成功,输出执行结果:" + value);
    }, function (error) {
        console.log("异步执行失败,输出执行结果:" + error);
    });

promise应用的一个栗子:

getUserInfo () {
    return new Promise((resolve, reject) => {
      getInfo().then(rsp => {
        this.loading = false
        if (rsp.ret === 0) 
          resolve(res) //异步执行成功,调用内置的resolve函数,将pending状态转化成resolved,并且传入我们希望传出的执行成功后的结果
                      // 注意: 这里一旦状态转变,那么后面就一定会调用then方法中的第一个参数的函数,然后将我们传入给resolve的参数传给then方法中的第一个方法作为参数,我们就可以在then的第一个方法中使用了。
          return
        }
        reject(rsp)  //异步执行失败,调用内置的reject函数,将pending状态转化成fulfilled,并且传入我们希望传出的执行成功后的结果
                    // 这里一旦状态转变,那么后面就一定会调用then方法中的第2个参数的函数,然后将我们传入给reject的参数传给then方法中的第2个方法作为参数,我们就可以在then的第2个方法中使用了。
      })
    })
  }

  //调用
   getUserInfo().then(function (val) {
        console.log("异步执行成功,输出执行结果:" + val);
    }, function (error) {
        console.log("异步执行失败,输出执行结果:" + error);
    });


TIP

实际上 Promise 用起来还是比较简单的,是不是可以动手试一试去封装自己业务中应用到的异步操作了(之前用回调写的)?

在这里必须说明下 Promise 内部是有状态的(pending、fulfilled、rejected),Promise 对象根据状态来确定执行哪个方法。Promise 在实例化的时候状态是默认 pending 的,当异步操作是完成的,状态会被修改为 fulfilled,如果异步操作遇到异常,状态会被修改为 rejected,可以通过下图来看下状态的走向


promise.04ed9cc2.png

注意
状态转化是单向的,不可逆转,已经确定的状态(fulfilled/rejected)无法转回初始状态(pending),而且只能是从 pending 到 fulfilled 或者 rejected

相关文章

  • 2020-10-28promise(二)

    异步操作前置知识jS是单线程的就是同一时间只能处理一个任务。就类似生活中的去超市排队结账,正常情况下,以为收银员只...

  • 2020-10-28promise(三)

    概述 Promise对象: 代表了未来某个将要发生的事件(通常是一个异步操作)。 ES6中的promise对象, ...

  • 2020-10-28promise(四)

    ES6 Promise 先拉出来遛遛 复杂的概念先不讲,我们先简单粗暴地把Promise用一下,有个直观感受。那么...

  • 二(二)

    发什么神经 突然就很想花钱 一边心疼 一边毫不在乎的花 啧 莫名其妙

  • 二,二

    2017.9.11教师节后的周一,第一次走进教室,刚站到讲台两个小可爱送给我两束花,原谅我那时候人还没有认全没有记...

  • 二〇二〇

    本来这篇小结打算年初写的,但是想想后边还有复试就先放一放,结果复试结束后过了两个月才想起要写这篇小结... 时过境...

  • 二金二木二火二土

    今天看完了极简中国史,这本书看了半个多月,因为是八十年前写的书,不是白话文,所以看的特别累。不过从近代前辈的角度去...

  • 说二『似二非二的二』

    说实话原以为他最多似二,生活小节或许专门学着似二,中枢神经应该不至于非二,没想到最近越来越疯狂地绞尽脑汁地朝着二的...

  • 二胎(二)

    今天宝宝三十周了,还有十周你就要出来了,也许会提前,妈妈和家人都很期待。 到了孕晚期,睡觉是个问题,左睡右睡都不对...

  • 二小姐(二)

    我去了李家,那环境好,夫人老爷小姐都很和蔼,我正坐在由木头和瓷做的椅子上,正等待着女管家来接我,我人生地不熟...

网友评论

      本文标题:2020-10-28promise(二)

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