回调地狱(callback)和promise以及将setTimeout封装成promise

Callback与Promise,将setTimeout封装成Promise

  • 为什么回调地狱(Callback hell)会发生?
  • Promise披着怎样的面纱?

首先Promise的出现,是为了将困在Callback hell中的芸芸众生解救出来,相信回调地狱是JavaScript开发人员最头疼的问题之一吧!尤其在接手前人的代码时,打开看到满满的Callback嵌套,是不是很想递出辞职信;那么Promise是如何解救痛苦中的芸芸众生的呢!

目录

1.回调函数的顺序与回调地狱

2.定时器

3.网络请求

4.Promise

5.sleep函数

回调函数的顺序与回调地狱

我们那火影举例(相信在座的大部分都看过):如果你是卡卡西的话,当敌人太多时就要开写轮眼、写轮眼打开后,快嗝屁之前要使用千鸟、千鸟用完之后必须注意影分身;

下面用伪代码表示就是:

卡卡西.addEventListener('敌人太多', function(){
    
    
  卡卡西.addEventListener('快嗝屁了',function(){
    
    
    写轮眼();
    卡卡西.addEventListener('写轮眼开完了',function(){
    
    
      跑路();
    })
  })
})

以上的举例就是常见的回调地狱了(Callback hell),这也是很多人在办公室处理的事情太多的时候,常常会做到,不知道自己在做什么的原因。

为了不过度嵌套太多的注册事件、回调函数,后来开发者想到了各种的pattern,最后promise被纳入了ES6的标准里;

定时器

定时器是JavaScript中一个很常见的方法,而它的语法和前面的注册事件相当相似

var timeoutID = scope.setTimeout(code[, delay]);

第一个参数正是上面说到的回调函数(Callback),第二个参数则是微秒数;

举一个例子:

假设你的室友是一个很喜欢同时操作很多个session的肥宅,有一天这位肥宅和你说:“诶,十分钟后帮我开一下电脑,我要连回去,拜托!”

setTimeout(() => 开电脑, 10*60*1000)

内置的定时器会在十分钟之后去触发这个事件;

注意:clearSetTimeout(timerId)可以把定时器事件停止

通常这个肥宅不会这么轻易的就放过你,他还会对你说:“打开后两分钟帮我连上Steam,然后帮我下个游戏。”

setTimeout(()=>{
    
    
 打开电脑();
 you.addEventListener('opened',()=>{
    
    
  setTimeout(()=>{
    
    
    连上steam();
  },2*60*1000)
 })
},10*60*1000)

网络请求

在JavaScript中我们不希望一个操作太久,就好比一个顾客点餐如果花了十分钟,这段时间内服务员就无法去服务其他的客人。所以许多长时间的操作,如IO、network请求,一般会使用异步的处理方式。

网络请求主要分为两种:XMLHTTPRequest(有名的ajax就是针对此封装的),以及后来的fetch。而XHR主要为请求的事件注册load事件来监听响应(response)。最简单的做法就是addEventListener

function reqListener () {
    
    
  console.log(this.responseText);
}
var oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
oReq.open("GET", "http://www.example.org/example.txt");
oReq.send();

后来的fetch标准则是用到了then方法的链式调用。

fetch('http://example.com/movies.json')
  .then(function(response) {
    
    
    return response.json();
  })
  .then(function(myJson) {
    
    
    console.log(myJson);
  });

这个then是由promise的原型所提供的,fetch则是promise的实体;

Promise

在这里插入图片描述

Promise(承诺),承诺有可能信守承诺(resolve)、承诺失败(reject)。在Promise的结果出现前,会进入一个不知道是成功还是失败的状态(Pending)。

Promise ->pending->(resolve/reject)

幸运的是Promise的API非常的友好,可以通过then和catch这两个方法,把回调函数放进去,针对两个最终结构进行处理;

function success(){
    
    
  // do something when success 
}
function fail(){
    
    
  // do something when fail
}
(Statement will pending)
  .then(success)
  .catch(fail)

最后不管是then还是catch,都会把Callback给Promise化。

fetch('https://your-domain/api.json')
  .then(res=>res.json()) /* 这也是异步 */
  .then(j=>console.log(j.id)) /* json() resolve 之后 */
  .catch(()=>alert('fail'))

sleep函数(封装setTimeout)

传统的setTimeout

setTimeout( ()=>{
    
    } , 1000)

我们希望这个能暂停一段时间并做一些相关的操作,但是又不想写太过嵌套的回调函数

/* 最终希望的函数 sleep */
sleep(5).then(()=>console.log('5秒过去'))

进一步修改

function sleep(sec){
    
    
 setTimeout(()=>{
    
    },sec*1000)
}

初步应该是这样,但是没有Promise依然无法使用then方法

function sleep(sec){
    
    
 return new Promise((resolve,reject)=>{
    
    
  setTimeout(()=>resolve(),sec*1000)
 })

在setTimeout触发之前,sleep函数会处于pending状态;但是reject任然没有派上用场,所以在这里增加了一个特性,超过十秒的话就reject掉;

/* 想象中的sleep */
sleep(5).then(()=>{
    
    })
sleep(11).then(()=>{
    
    }).catch(e=>console.log(e)) // Error:睡太久了八?

结合以上修改就是:

function sleep(sec){
    
    
 return new Promise((resolve,reject)=>{
    
    
  if(sec > 10) reject(new Error('睡太久了八!'));
  setTimeout(()=>resolve(),sec*1000)
 })
}
sleep(11).catch(e=>console.log(e)) // Error: 睡太久了八!

结束

本文是在自己学习vue时遇到promise这个知识点时做的一个小记录;

猜你喜欢

转载自blog.csdn.net/qq_40240053/article/details/108765515