ES6中的Promise深入解析

promise主要是为了解决回调带来的疯狂行为, Promise 风暴已经开始席卷JavaScript 世 界。

实际上,绝大多数 JavaScript/DOM 平台新增的异步 API 都是基于 Promise 构建的。


一. 异步编程的背景

JavaScript 的引擎建立在单线程事件轮询(single-threaded event loop)概念之上。

单线程意味着一段时间内只能执行一段代码,与 Java 和 C++ 这些允许多段代码同时执行的多线程语言形成了鲜明对比。

JavaScript 引擎在相同的时间内只能执行一段代码.

当代码由 JavaScript 引擎执行完毕后,引擎通过 event loop 找到并执行队列中的下一个任务。

event loop 是 JavaScript 引擎内部的线程用来监控代码的执行情况和管理任务队列。

需要牢记的是既然它是个队列,那么任务就会由开始到最后的顺序依次执行。


二. Promise出来之前的两种异步编程方式

  1. 事件模型

不够灵活.

  1. 回调模式

回调地狱


三. promise基础

一个 Promise 就是一个代表了异步操作最终完成或者失败的对象。

可以把Promise理解成对将来的一个”承诺”. 这个承诺不管将来如何一定会有一个结果:要么兑现承诺, 要么不兑现. 不管结果是什么, 都会对被承诺者一个交代.

我们通常有两种方式来获取到一个Promise对象:

  1. 使用Promise构造函数来创建Promise对象

  2. 调用其他的一些api返回一个Promise对象.(其实是这些api内部创建并返回了Promise对象)

我们先用第一种方式来深入的理解下promise.


promise 的生命周期(The Promise Lifecycle)

  1. 每个 promise 的生命周期一开始都会处于短暂的挂起(pending)状态,表示异步操作仍未完成,即挂起的 promise 被认定是未定的(unsettled)。

  2. 一旦异步操作完成,promise 就被认为是已定(settled)的并处于以下的两种状态之一:

    • fulfilled(resolved): promise 的异步操作已完成。
    • rejected: promise 的异步操作未完成,原因可能是发生了错误或其它理由。

创建Promise对象并添加异步任务

使用构造函数Promise来创建Promise对象.

需要接收一个执行函数(executor), 这个函数内包含了初始化Promise的一些代码.
该执行函数接收 resolve 和 reject 两个参数(其实是两个函数)。
- resolve 函数会在执行函数成功运行后发出信号表示该 promise 已经可用,
- reject 函数代表改执行函数运行失败。

/*
对setTimeout 用promise作封装

创建出来一个未定的promise

注意:
1. 创建Promise对象的时候, 执行函数的内的代码会立即执行.
2. 当 resolve() 和 reject() 在执行函数内部被调用后,
为了处理这个 promise,一个任务会被放置到任务队列中。
该种行为被称为任务调度(job scheduling)
*/

var count = 1;
let promise = new Promise(function (resolve, reject){
if(count == 1){
resolve("成功了");
}else{
reject("失败了");
}
});

/*添加异步任务
* then需要两个函数:
* 函数1:异步操作成功之后的回调函数
* 函数2:异步操作失败之后的回调函数
* */
promise.then(function (value){
console.log(value);
}, function (value){
console.log(value)
});

注意:

  • Promise的意思是承诺,保证. 他带来了哪些保证呢?

  • 在JavaScript事件队列的当前运行完成之前,回调函数永远不会被调用。

  • 通过 .then 形式添加的回调函数,甚至都在异步操作完成之后才被添加的函数,都会被调用
  • 通过多次调用 .then,可以添加多个回调函数,它们会按照插入顺序并且独立运行。

四. Promise链式调用

一个常见的需求就是连续执行两个或者多个异步操作,这种情况下,每一个后来的操作都在前面的操作执行成功之后,带着上一步操作所返回的结果开始执行。

我们可以通过创造一个promise chain来完成这种需求。

这也是Promise的神奇之处.

是因为: 每次调用then方法会返回一个全新的Promise对象:


promise.then(function (value){
console.log(value);
}, function (value){
console.log(value)
}).then(function (){
console.log("哈哈哈")
})

在链中传递数据


promise.then(function (value){
console.log(value);
return value + "1"; // 给后面的异步任务传递数据
}, function (value){
console.log(value)
}).then(function (value){
console.log("哈哈哈", value)
})

五. 捕获错误

通过前面的学习我们已经知道, then的第二个参数是用来处理错误.

其实我们可以省略这个参数不处理错误.

省略第二个参数:

promise.then(function (value){
console.log(value);
return value + "1";
})

也可以使用catch来专门来处理错误:


promise.then(function (value){
console.log(value);
}).catch(function (value){
console.log(value);
})

// 与下面完全等价:
promise.then(function (value){
console.log(value);
}, function (value){
console.log(value);
console.log(a);
})

注意:

  • catch也会返回一个新的promise对象

六. 关于then返回的promise

好好体会

then方法总是返回一个新的Promise,而它的行为与then中的回调函数的返回值有关:

  • 如果then中的回调函数返回一个值,那么then返回的Promise将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。

  • 如果then中的回调函数抛出一个错误,那么then返回的Promise将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值。

  • 如果 then 中的回调函数返回的是一个 promise A, 那么then返回的promise B的状态始终会与 promise A 保持一致. 并且回调函数的参数值也始终相同.

  • promise A的回调函数的参数也始终与 promise B的回调函数的参数保持一致.

使用promise封装ajax

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章