你真的知道『Promise的存在意义吗』?

807 阅读3分钟

这是我参与8月更文挑战的第17天,活动详情查看8月更文挑战

前言

我们应该踏踏实实地把 Promise 是什么,它存在的意义是什么,它为什么这样设计,搞明白以后,我们再去学更深的,比如 Promise 的原理,或者从应用层面上,我们应该掌握的 Promise 的使用技巧。今天我们就来聊聊 Promise 的存在意义。可以看下下面两个问题,你是否知道:

  • 为什么 Promise 的构造函数是同步执行,包括里面的执行器?
  • 为什么 Promise.then 这样的东西一定是异步的,为什么不能是同步的?

使用 AJAX 实现异步程序

假设有 data.json,存储一些数据

[
  {
    "id": 1,
    "name": "zhangsan"
  },
  {
    "id": 2,
    "name": "lisi"
  },
  {
    "id": 3,
    "name": "wangwu"
  }
]

index.js 去通过 ajax 获取到数据,并做相关处理:

$.ajax({
  url: 'http://localhost:3000/data.json',
  success(data) {
    console.log(getNames(data));
  }
});

console.log('追梦玩家');

function getNames(data) {
  return data.map(function(item) {
    return item.name;
  })
}

上面代码输出结果,因为 ajax 是异步的,所以先打印 "追梦玩家"。

image.png

逻辑从 AJAX 内部抽离出来

在上面的代码的基础上,进行改写,实现 console.log(getNames(data)); 从 AJAX 内部抽离出来

我们先来尝试一下:

var data = $.ajax({
  url: 'http://localhost:3000/data.json',
  async: false
});

console.log(getNames(data.responseJSON));

console.log('追梦玩家');

function getNames(data) {
  return data.map(function(item) {
    return item.name;
  })
}

上面的代码,通过设置 async: false,让代码变成同步关系,我们就成功的把这个逻辑分离的事情做完呢?实际上没有。

它们俩原本是异步程序,但是由于你设置了 async: false,形成了阻塞,说白了,就是上面那个 ajax 程序,跟下面的每一个语句都形成了同步关系。

这显然是不符合我们的需求的,虽然说我们已经将 getNames 这个逻辑,从 AJAX 内部抽离出来,但是实际上让 console.log('追梦玩家'); 被 ajax 程序给阻塞掉,形成一个同步的关系。那我们使用最原始的 ajax,解决不了这个问题,这才有了 Promise 的诞生。

Promise 异步问题同步化解决方案

我们使用 Promise,来解决使用 ajax,设置 async: false,后续程序全部阻塞掉的这个问题。

我们改造下代码

// 同步
const p = new Promise((resolve, reject) => {
  $.ajax({
    url: 'http://localhost:3000/data.json',
    success(data) {
      resolve(data);
    }
  });
})

// 异步
p.then((res) => {
  console.log(getNames(res));
})

console.log('追梦玩家');

function getNames(data) {
  return data.map(function(item) {
    return item.name;
  })
}

执行 Promise 构造函数,是同步的,但是里面的代码,异步请求数据,等成功获取到数据,resolve 之后,p.then 才会去执行。

其实 p.then 不能去阻塞下面程序的运行,也就是说 p.then 这个东西,跟下面的程序代码,一定是要是异步的关系,这样的话,才能解决我上面的问题。

所以现在我们来看看,Promise 的存在意义是用来解决回调地狱的吗?其实它只是顺便给你解决了回调地狱的问题。

Promise 的存在意义,其实是异步问题同步化解决方案,这个要怎么理解呢?

AJAX 是异步的,通过包裹了 Promise,可以通过 Promise.then 来获取异步程序的结果,并且不阻塞 Promise 以外的程序,跟 Promise 不相关的任何程序,保持异步关系。

现在解决回调地狱,真的是用 Promise 是最好的解决方案吗?最佳方式是使用 async/await 的方式,它可以让我们以同步代码的书写方式去写异步代码,这是es6的语法。

参考

文中如有错误,欢迎在评论区指正,如果这篇文章帮助到了你或者喜欢,欢迎点赞和关注。