1. Promise是什么

1.1 promise 的理解

1. 抽象表达:

  Promise 是 JS 中进行异步编程的新的解决方案(旧的是纯回调形式)

2. 具体表达:

 (1)从语法上说:Promise 是一个构造函数

 (2)从功能上说:promise 对象用来封装一个异步操作并可以获取其结果

1.2 promise 的状态和状态改变

三种状态:

  1. pending: 初始状态,既不是成功,也不是失败状态。

  2. fulfilled: 意味着操作成功完成。

  3. rejected: 意味着操作失败。

pending:等待状态,比如正在进行网络请求,或者定时器没有到时间。

fulfill:满足状态,当我们主动回调了resolve时,就处于该状态,并且会回调.then()

reject:拒绝状态,当我们主动回调了reject时,就处于该状态,并且会回调.then()或者.catch()

两种状态改变:

  1. pending 变为 fulfilled

  2. pending 变为 rejected

当我们 new Promise 的时候,此时的 Promise对象是 pending 状态,它可能会变为 fulfilled 状态并传递一个值给相应的状态处理方法,也可能变为 rejected 状态并传递失败信息。当其中任一种情况出现时,Promise 对象的 then 方法绑定的处理方法(handlers )就会被调用(then方法包含两个参数:onfulfilled 和 onrejected,它们都是 Function 类型。当 Promise 状态为 fulfilled 时,调用 then 的 onfulfilled 方法,当 Promise 状态为 rejected 时,调用 then 的 onrejected 方法, 所以在异步操作的完成和绑定处理方法之间不存在竞争)。

因为 Promise.prototype.then 和 Promise.prototype.catch 方法返回的是 promise 对象, 所以它们可以被链式调用。

1.3 promise 的基本流程

1.4 promise 的基本使用

//1.创建一个新的promise对象
const p = new Promise((resolve, reject) => { //执行器函数是同步回调!
console.log('执行 executor') //立刻执行
//2.执行异步操作
setTimeout(() => {
const time = Date.now()
//3.1 成功,调用resolve(value)
if( time % 2 === 0 ){
resolve('成功的数据,time=' + time)
} else {
//3.2 失败,调用reject(reason)
reject('失败的数据,time=' + time)
}
}, 1000)
})
console.log('new Promise()之后') //先输出 '执行 exceutor' p.then(
value => { // onfulfilled函数,自动接收成功的value
console.log('成功的回调', value)
},
reason => { // onrejected函数,自动接收失败的reason
console.log('失败的回调', reason)
}
)

2. 为什么要使用 Promise

(1) 指定回调方式更加灵活

     旧的:必须在启动异步任务前指定
     promise:启动异步任务——返回promise对象——给promise对象绑定回调函数(甚至可以在异步函数结束之后指定)

(2)支持链式调用, 解决回调地狱


  function successCallback(result) {

    console.log('声音文件创建成功' + result)

}

function failureCallback(error) {
console.log('声音文件创建失败' + error)
} /* 1.1 纯回调函数 */
//启动任务(audioSettings)前必须指定回调函数(callback)
createAudioFileAsync(audioSettings, successCallback, failureCallback) /* 1.2 promise */
//可在启动任务(audioSettings)后指定回调函数(callback)
const promise = createAudioFileAsync(audioSettings)
setTimeout(() => {
promise.then(successCallback, failureCallback)
}, 1000) /* 2.1 回调地狱 */
//回调函数的嵌套
doSomething(function (result) { //第一个函数function就是sucessCallback
doSomethingElse(result, function (newResult) {
doThirdThing(newResult, function (finalResult) {
console.log('Got the final result' + finalResult)
}, failureCallback)
}, failureCallback)
}, failureCallback) /* 2.2 链式调用 */
doSomething().then(function (result) { //result是doSomething函数成功执行的返回值
return doSomethingElse(result) //执行器函数,同步回调
})
.then(function (newResult) { //newResult是doSomethingElse成功执行的返回值
return doThirdThing(newResult)
})
.then(function (finalResult) {
console.log('Got the final result' + finalResult)
})
.catch(failureCallback) //统一的错误处理 /* 2.3 async/await : 回调地狱的终极解决方案 */
//相比于promise 去掉了回调函数
async function request() {
try {
const result = await doSomething()
const newResult = await doSomethingElse(result)
const finalResult = await doThirdThing(newResult)
console.log('Got the final result' + finalResult)
} catch (error) {
failureCallback(error)
}
}

3. 如何使用 Promise

3.1 语法(API)

(1)基本语法

new Promise( function(resolve, reject) {...} /* executor */  );

executor是带有 resolve 和 reject 两个参数的函数 。Promise构造函数执行时立即调用 executor 函数, resolve 和 reject 两个函数作为参数传递给executor(executor 函数在Promise构造函数返回所建promise实例对象前被调用)。resolve 和 reject 函数被调用时,分别将promise的状态改为 fulfilled(完成)或 rejected(失败)。executor 内部通常会执行一些异步操作,一旦异步操作执行完毕(可能成功/失败),要么调用resolve函数来将promise状态改成fulfilled,要么调用reject 函数将promise的状态改为rejected。如果在executor函数中抛出一个错误,那么该promise 状态为rejected。executor函数的返回值被忽略。

(2)方法

(3)Promise 原型

(4)代码展示

new Promise( (resolve, reject) => {
  setTimeout( () => {
    resolve('成功') //resolve就像是一个传递数据的运输机
  }, 1000 )
})
.then(
  value => {
    console.log('onResolved()1', value)
  }
)
.catch(
  reason => {
    console.log('onRejected()1', reason)
  }
) const p1 = new Promise((resolve, reject) => {
  resolve(1)
})
const p2 = Promise.resolve(2)
const p3 = Promise.reject(3)
// p1.then( value => {console.log(value)} )
// p2.then( value => {console.log(value)} )
// p3.catch( reason => {console.log(reason)} ) //const pAll = Promise.all([p1,p2,p3])
const pAll = Promise.all([p1,p2])
pAll.then(
  values => {
    console.log('all onResolved()', values)
  },
  reason => {
    console.log('all onRejected()', reason)
  }
) const pRace = Promise.race([p1,p2,p3])
pRace.then(
  value => {
    console.log('race onResolved()', value)
  },
  reason => {
    console.log('race onResolved()', reason)
  }
)

有关更多 promise 的原理和 then,catch,all,race的用法请参考 https://blog.csdn.net/qq_34645412/article/details/81170576https://segmentfault.com/a/1190000007463101#articleHeader2https://www.jianshu.com/p/001d22a44f85

3.2 Promise 的几个关键问题

1. 如何改变promise的状态?

(1) resolve(value): 如果当前是pending就会变为fulfilled

(2) reject(reason): 如果当前是pending就会变为rejected

(3) 抛出异常: 如果当前是pending就会变为rejected

2. 一个promise指定多个成功/失败回调函数, 都会调用吗?

    当promise改变为对应状态时都会调用
 const p = new Promise((resolve, reject) => {
//resolve('Promise状态会被标记为fulfilled')
// reject('Promise状态会被标记为rejected')
throw new Error('Promise状态会被标记为rejected')
}); p.then(
value => {
console.log('value1', value)
},
reason => {
console.log('reason1', reason) // reason1 Error: Promise状态会被标记为rejected
}
)
p.then(
value => {
console.log('value2', value)
},
reason => {
console.log('reason2', reason) // reason2 Error: Promise状态会被标记为rejected
}
)

3. 改变promise状态和指定回调函数谁先谁后?

    (1) 都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
    (2) 如何先改状态再指定回调?
      ①在执行器中直接调用resolve()/reject()
      ②延迟更长时间才调用then()
    (3) 什么时候才能得到数据?
      ①如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
      ②如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1) //后改变状态(同时指定数据),异步执行回调函数
}, 1000)
}).then( //先指定回调函数,保存当前指定的回调函数
value => {},
reason => {
console.log('reason', reason)
}
) new Promise((resolve, reject) => {
resolve(1) //先改变状态(同时指定数据)
}).then( //后指定回调函数,异步执行回调函数
value => {
console.log('value', value)
},
reason => {
console.log('reason', reason)
}
)
console.log('-----') //先输出----, 再输出value 1,因为回调函数是异步执行,会被放入到队列中待执行

4. promise.then()返回的新promise的结果状态由什么决定?

    (1) 简单表达: 由then()指定的回调函数执行的结果决定
    (2) 详细表达:
      ① 如果抛出异常,则新promise变为rejected, reason为抛出的异常,抛出什么,reason就是什么
      ② 如果返回的是非promise的任意值,则新promise变为fulfilled, value为返回的值,当没有return语句的时候value为undefined
      ③ 如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果
new Promise((resolve, reject) => {
// resolve(1)
reject(1)
}).then(
value => {
console.log('onResolved1()', value)
// return 2
// return Promise.resolve(3)
// return Promise.reject(4)
throw 5
},
reason => {
console.log('onRejected1()', reason)
// return 2
// return Promise.resolve(3)
// return Promise.reject(4)
throw 5
}
).then(
value => {
console.log('onResolved2()', value)
},
reason => {
console.log('onRejected2()', reason)
}
)

5. promise 如何串联多个操作任务?

new Promise((resolve, reject) => {
setTimeout(() => {
resolve('aaa')
}, 1000)
}).then(res => { // 由于只传递了一个参数res 所以可以省略括号
console.log(res, '第一次处理');
// res = res + '111' 这样比较混乱
return new Promise((resolve) => { // 当我们只需要用resolve的时候可以省略reject
resolve(res + '111') // 我们这个时候不需要网络请求 而是自己处理
}).then(res => {
console.log(res, '第二次处理');
return new Promise((resolve, reject) => {
// resolve(res + '222')
reject('error message')
}).then(res => {
console.log(res, '第三次处理');
}).catch(err => {
console.log(err)
})
})
}) // 由于第二次和第三次处理都没有使用异步处理(setTimeout) 所以我们可以简写 return
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('aaa')
}, 1000)
}).then(res => {
console.log(res, '第一次处理');
return Promise.resolve(res + '111')
}).then(res => {
console.log(res, '第二次处理');
// return Promise.resolve(res + '222')
// return Promise.reject(res + '222')
throw 'error message'
}).then(res => {
console.log(res, '第三次处理');
}).catch(res => {
console.log('error message');
}) // 再次简写 直接 return res + '111' 省略 Promise.resolve
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('aaa')
}, 1000)
}).then(res => {
console.log(res, '第一次处理');
return res + '111'
}).then(res => {
console.log(res, '第二次处理');
return res + '222'
}).then(res => {
console.log(res, '第三次处理');
})

6. promise异常传透?

    (1) 当使用 promise 的 then 链式调用时, 可以在最后指定失败的回调,
    (2) 前面任何操作出了异常, 都会传到最后失败的回调中处理
new Promise((resolve, reject) => {
//resolve(1)
reject(1)
}).then(
value => {
console.log('onResolved1()', value)
return 2
},
// 内部默认会将错误逐级传递直至最后的catch
// reason => Promise.reject(reason)
// reason => {
// throw reason
// }
).then(
value => {
console.log('onResolved2()', value)
return 3
}
).then(
value => {
console.log('onResolved3()', value)
}
).catch(reason => {
console.log('onRejected1()', reason)
})

7. 中断promise链?

    (1) 当使用promise的then链式调用时, 在中间中断, 不再调用后面的回调函数
    (2) 办法: 在回调函数中返回一个pending状态的promise对象
new Promise((resolve, reject) => {
reject(1)
}).then(
value => {
console.log('onResolved1()', value)
return 2
}
).then(
value => {
console.log('onResolved2()', value)
return 3
}
).then(
value => {
console.log('onResolved3()', value)
}
).catch(reason => {
console.log('onRejected1()', reason)
return new Promise(() => {}) //返回一个pending的promise 中断promise链,后面代码不会再执行
}).then(
value => {
console.log('onResolved4()', value)
},
reason => {
console.log('onRejected4()', reason)
}
)

promise的理解和使用的更多相关文章

  1. 「每日一题」面试官问你对Promise的理解?可能是需要你能手动实现各个特性

    关注「松宝写代码」,精选好文,每日一题 加入我们一起学习,day day up 作者:saucxs | songEagle 来源:原创 一.前言 2020.12.23日刚立的flag,每日一题,题目类 ...

  2. promise的理解和应用

    老铁们,我又满血复活了,今天我准备来吹一波我对promise,如有错吴请直接指出,明白了吗?话不多说开始吧 首先我们需要知道啥叫promise,我问了问大佬,他说这个东西是 异步操作的同步代码(but ...

  3. 谈谈你对Promise的理解

    一.Promise是什么? 理解 抽象表达: Promise 是一门新的技术(ES6 规范) Promise 是 JS 中进行异步编程的新解决方案(备注:旧方案是单纯使用回调函数) 具体表达: 从语法 ...

  4. promise的理解

    为什么会有promise,他的作用是什么? promise主要是为了解决js中多个异步回调难以维护和控制的问题. 什么是promise? 从图中,我们可以看出,Promise是一个函数,这个函数上有在 ...

  5. 对Promise的理解?

    ES6原生提供了promise对象 所谓Promise,就是一个对象,用来传递异步操作的消息.它代表了某个未来才会知道结果的事件(通过是一个异步操作),并且这个事件提供统一的API,可供进一步处理 P ...

  6. 一点对Promise的理解与总结

    全手打原创,转载请标明出处:https://www.cnblogs.com/dreamsqin/p/10959411.html,多谢,=.=~ axios用多了就开始疑惑它里面到底是个啥,虽然总被告知 ...

  7. 谈谈我对Promise的理解

    一.Promise是什么? Promise是最早由社区提出和实现的一种解决异步编程的方案,比其他传统的解决方案(回调函数和事件)更合理和更强大. ES6 将其写进了语言标准,统一了用法,原生提供了Pr ...

  8. 简单理解ECMAScript2015中的Promise

    ECMAScript6中新增了Promise对象, 所谓Promise对象,即代表着一个还未完成,但将来某时会完成的操作(通常是异步操作).使用Promise对象,我们就可以避免陷入函数层层嵌套的‘回 ...

  9. 深入理解promise

    如今promise大行其道,关于异步方面的几乎都有它的影子,新的fetch api返回的是promise对象,generator中的yield后面一般也会跟promise对象,async的await后 ...

随机推荐

  1. python数据分析工具——Pandas、StatsModels、Scikit-Learn

    Pandas Pandas是 Python下最强大的数据分析和探索工具.它包含高级的数据结构和精巧的工具,使得在 Python中处理数据非常快速和简单. Pandas构建在 Numpy之上,它使得以 ...

  2. php最快捷的插入数据,3000万仅需5秒

    <?phpheader('content-type:text/html;charset=utf-8');//采集数据$url="http://www.keepclub.com/club ...

  3. Vant Weapp小程序蹲坑之使用card组件显示价格

    问题 在基于mpvue+Vant Weapp组件库实战过程中,问题越来越多.网络上所谓的"坑"总结,仅仅不过是其开发中所遭所遇之"坑"而已--估计后面的&quo ...

  4. A Tile Painting(循环节)

    Ujan has been lazy lately, but now has decided to bring his yard to good shape. First, he decided to ...

  5. P1518 两只塔姆沃斯牛 The Tamworth Two(简单的搜索题)

    题目描述 两只牛逃跑到了森林里.农夫John开始用他的专家技术追捕这两头牛.你的任务是模拟他们的行为(牛和John). 追击在10x10的平面网格内进行.一个格子可以是: 一个障碍物, 两头牛(它们总 ...

  6. Java自动装箱与缓存

    自动装箱与缓存 现象 有以下代码: 1 public class Main { 2 public static void main(String[] args) { 3 Integer i1 = 12 ...

  7. 一个简单的wed服务器SHTTPD(4)————SHTTPD支持CGI的实现

    //start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...

  8. 关于SQL Server中存储过程在C#中调用的简单示例

    目录 0. 简介 1. 语法细节 2. 示例1:模拟转账 3. 示例2:测试返回DataTable 4. 源代码下载 shanzm-2020年5月3日 23:23:44 0. 简介 [定义]:存储过程 ...

  9. C# 基础知识系列- 14 IO篇 流的使用

    0. 前言 继续之前的C# IO流,在前几篇小短片中我们大概看了下C# 的基础IO也对文件.目录和路径的操作有了一定的了解.这一篇开始,给大家演示一下流的各种操作.以文件流为例,一起来看看如何操作吧. ...

  10. java的Timer定时器任务

    在项目开发中,经常会遇到需要实现一些定时操作的任务,写过很多遍了,然而每次写的时候,总是会对一些细节有所遗忘,后来想想可能是没有总结的缘故,所以今天小编就打算总结一下可能会被遗忘的小点: 1. pub ...