Promise 的含义

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

Promise对象有以下两个特点。

(1)对象的状态不受外界影响Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

Promise也有一些缺点:

  1. 无法取消Promise,一旦新建它就会立即执行,无法中途取消。
  2. 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
  3. 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

为什么要用promise

1. 指定回调函数的方式更加灵活: 
    旧的: 必须在启动异步任务前指定
    promise: 启动异步任务 => 返回promie对象 => 给promise对象绑定回调函数(甚至可以在异步任务结束后指定)

const p = new Promise((resolve, reject) => {
console.log('执行 executor同步函数')
let time = Date.now();
setTimeout(() => {
if (time % 2 === 0) {
resolve(time)
} else {
reject(time)
}
}, 1000) }) setTimeout(() => {
p.then(value => {
console.log('value', value)
}, reason => {
console.log('reason', reason)
})
}, 3000)
 2. 支持链式调用, 可以解决回调地狱问题
    什么是回调地狱: 回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调函数执行的条件
    回调地狱的缺点: 不便于阅读 / 不便于异常处理
    解决方案:promise链式调用
    终极解决方案:async/await Promise API
1. Promise构造函数: Promise (excutor) {}
excutor 执行器函数: 同步执行 (resolve, reject) => {}
resolve函数: 内部定义成功时我们调用的函数 value => {}
reject函数: 内部定义失败时我们调用的函数 reason => {}
说明: excutor会在Promise内部立即同步回调,异步操作在执行器中执行
定义:new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>; 2. Promise.prototype.then方法: (onResolved, onRejected) => {}
onResolved函数: 成功的回调函数 (value) => {}
onRejected函数: 失败的回调函数 (reason) => {}
说明: 指定用于得到成功value的成功回调和用于得到失败reason的失败回调
返回一个新的promise对象
then接口定义:then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>; 3. Promise.prototype.catch方法: (onRejected) => {}
onRejected函数: 失败的回调函数 (reason) => {}
说明: then()的语法糖, 相当于: then(undefined, onRejected)
catch接口定义:catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult>; 4. Promise.resolve方法: (value) => {}
value: 成功的数据或promise对象
说明: 返回一个成功/失败的promise对象 resolve<T>(value: T | PromiseLike<T>): Promise<T>; 5. Promise.reject方法: (reason) => {}
reason: 失败的原因
说明: 返回一个失败的promise对象 reject<T = never>(reason?: any): Promise<T>; 6. Promise.all方法: (promises) => {}
promises: 包含n个promise的数组
说明: 返回一个新的promise, 只有所有的promise都成功才成功, 只要有一个失败了就直接失败
all<T>(values: readonly (T | PromiseLike<T>)[]): Promise<T[]>; 7. Promise.race方法: (promises) => {}
promises: 包含n个promise的数组
说明: 返回一个新的promise, 第一个完成的promise的结果状态就是最终的结果状态
race<T>(values: readonly T[]): Promise<T extends PromiseLike<infer U> ? U : T>;
使用的常见问题
  1. 如何改变promise的状态?
    1. resolve(value): 如果当前是pending就会变为resolved
    2.  reject(reason): 如果当前是pending就会变为rejected
    3. 抛出异常: 如果当前是pending就会变为rejected
  2. 一个promise指定多个成功/失败回调函数, 都会调用吗?
    1. 当promise改变为对应状态时都会调用
  3. 改变promise状态和指定回调函数谁先谁后?
    (1)都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
    (2)如何先改状态再指定回调?
        ①在执行器中直接调用resolve()/reject()
        ②延迟更长时间才调用then()
    (3)什么时候才能得到数据?
        ①如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
        ②如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据
  4. promise.then()返回的新promise的结果状态由什么决定?
      (1)简单表达: 由then()指定的回调函数执行的结果决定
      (2)详细表达:
          ①如果抛出异常, 新promise变为rejected, reason为抛出的异常
          ②如果返回的是非promise的任意值, 新promise变为resolved, value为返回的值
          ③如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果
  5. promise如何串连多个操作任务?

       (1)promise的then()返回一个新的promise, 可以开成then()的链式调用
      (2)通过then的链式调用串连多个同步/异步任务
  6. promise异常传透?

     (1)当使用promise的then链式调用时, 可以在最后指定失败的回调,
     (2)前面任何操作出了异常, 都会传到最后失败的回调中处理
  7.  
    中断promise链?
    (1)当使用promise的then链式调用时, 在中间中断, 不再调用后面的回调函数
    (2)办法: 在回调函数中返回一个pending状态的promise对象      return new Promise(()=>{})
 
自定义Promise
// 自定义Promise
// ES5匿名函数自调用实现模块化
(function (window) {
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected' // 参数为executor函数
function Promise(executor) {
const that = this
// 三个属性
that.status = PENDING //Promise对象状态属性,初始状态为 pending
that.data = 'undefined' // 用于存储结果数据
that.callbacks = [] //保存待执行的回调函数 ,数据结构:{onResolved(){},onRejected(){}} function resolve(value) {
// RESOLVED 状态只能改变一次
if (that.status !== PENDING) {
return
}
that.status = RESOLVED
that.data = value
//执行异步回调函数 onResolved
if (that.callbacks.length > 0) {
setTimeout(() => { // 放入队列中执行所有成功的回调
that.callbacks.forEach(callbackObj => {
callbackObj.onResolved(value)
})
})
}
} function reject(seaon) {
if (that.status !== PENDING) {
return
}
that.status = REJECTED
that.data = seaon
//执行异步回调函数 onRejected
if (that.callbacks.length > 0) {
setTimeout(() => { // 放入队列中执行所有失败的回调
that.callbacks.forEach(callbackObj => {
callbackObj.onRejected(seaon)
})
})
}
} try { //执行器函数立即执行
executor(resolve, reject)
} catch (e) {
reject(e)
}
} //Promise原型对象 then ,两个回掉函数 成功 onResolved ,失败onRejected
//返回一个新的Promise对象
Promise.prototype.then = function (onResolved, onRejected) {
onResolved = typeof onResolved === 'function' ? onResolved : value => value // 向后传递成功的value
// 指定默认的失败的回调(实现错误/异常传透的关键点)
onRejected = typeof onRejected === 'function' ? onRejected : reason => {
throw reason
} // 抽后传递失败的reason
const that = this
return new Promise((resolve, reject) => { //调用指定回调函数处理, 根据执行结果, 改变return的promise的状态
function handle(callback) {
// 调用成功的回调函数 onResolved
//1.如果抛出异常,return的promise就 会失败,reason就 是error
//2.如果回调函数返回不是promise, return的promise就 会成功,value就是返回的值
//3.如果回调函数返回是promise, return的promise结 果就是这个promise的结果
try {
const result = callback(that.data);
if (result instanceof Promise) {
result.then(value => resolve(value), reason => reject(reason))
} else {
resolve(result)
}
} catch (e) {
reject(e)
}
} // 当前状态还是pending状态, 将回调函数保存起来
if (that.status === PENDING) {
that.callbacks.push({
onResolved(value) {
handle(onResolved)
},
onRejected(reason) {
handle(onRejected)
}
})
} else if (that.status === RESOLVED) {
setTimeout(() => {
handle(onResolved)
})
} else {
setTimeout(() => {
//调用失败的回调函数 onRejected
handle(onRejected)
})
}
})
} //Promise原型对象 catch ,参数为失败的回掉函数 onRejected
//返回一个新的Promise对象
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected)
} // Promise函数对象的 resolve 方法
//返回一个新的Promise对象,Promise.resolve()中可以传入Promise
Promise.resolve = function (value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(resolve, reject)
} else {
resolve(value)
}
})
} // Promise函数对象的 reject 方法
//返回一个新的Promise对象 Promise.reject中不能再传入Promise
Promise.reject = function (reason) {
return new Promise((resolve, reject) => {
reject(reason)
})
} // Promise函数对象的 all 方法,接受一个promise类型的数组
// 返回一个新的Promise对象
Promise.all = function (promises) {
// 保证返回的值得结果的顺序和传进来的时候一致
// 只有全部都成功长才返回成功
const values = new Array(promises.length) // 指定数组的初始长度
let successCount = 0
return new Promise((resolve, reject) => {
promises.forEach((p, index) => { // 由于p有可能不是一个Promise
Promise.resolve(p).then(
value => {
successCount++
values[index] = value
if (successCount === promises.length) {
resolve(values)
}
},
// 如果失败
reason => {
reject(reason)
})
})
}) }
// Promise函数对象的 race 方法,接受一个promise类型的数组
// 返回一个新的Promise对象
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
promises.forEach(p => {
Promise.resolve(p).then(
value => {
resolve(value)
}, reason => {
reject(reason)
})
})
}) } // 把Promise暴露出去
window.Promise = Promise
})(window)

使用Class定义

// 自定义Promise
// ES5匿名函数自调用实现模块化
(function (window) {
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected' class Promise {
// 参数为executor函数
constructor(executor) {
const that = this
// 三个属性
that.status = PENDING //Promise对象状态属性,初始状态为 pending
that.data = 'undefined' // 用于存储结果数据
that.callbacks = [] //保存待执行的回调函数 ,数据结构:{onResolved(){},onRejected(){}} function resolve(value) {
// RESOLVED 状态只能改变一次
if (that.status !== PENDING) {
return
}
that.status = RESOLVED
that.data = value
//执行异步回调函数 onResolved
if (that.callbacks.length > 0) {
setTimeout(() => { // 放入队列中执行所有成功的回调
that.callbacks.forEach(callbackObj => {
callbackObj.onResolved(value)
})
})
}
} function reject(seaon) {
if (that.status !== PENDING) {
return
}
that.status = REJECTED
that.data = seaon
//执行异步回调函数 onRejected
if (that.callbacks.length > 0) {
setTimeout(() => { // 放入队列中执行所有失败的回调
that.callbacks.forEach(callbackObj => {
callbackObj.onRejected(seaon)
})
})
}
} try { //执行器函数立即执行
executor(resolve, reject)
} catch (e) {
reject(e)
}
} //Promise原型对象 then ,两个回掉函数 成功 onResolved ,失败onRejected
//返回一个新的Promise对象
then(onResolved, onRejected) {
onResolved = typeof onResolved === 'function' ? onResolved : value => value // 向后传递成功的value
// 指定默认的失败的回调(实现错误/异常传透的关键点)
onRejected = typeof onRejected === 'function' ? onRejected : reason => {
throw reason
} // 抽后传递失败的reason
const that = this
return new Promise((resolve, reject) => { //调用指定回调函数处理, 根据执行结果, 改变return的promise的状态
function handle(callback) {
// 调用成功的回调函数 onResolved
//1.如果抛出异常,return的promise就 会失败,reason就 是error
//2.如果回调函数返回不是promise, return的promise就 会成功,value就是返回的值
//3.如果回调函数返回是promise, return的promise结 果就是这个promise的结果
try {
const result = callback(that.data);
if (result instanceof Promise) {
result.then(value => resolve(value), reason => reject(reason))
} else {
resolve(result)
}
} catch (e) {
reject(e)
}
} // 当前状态还是pending状态, 将回调函数保存起来
if (that.status === PENDING) {
that.callbacks.push({
onResolved(value) {
handle(onResolved)
},
onRejected(reason) {
handle(onRejected)
}
})
} else if (that.status === RESOLVED) {
setTimeout(() => {
handle(onResolved)
})
} else {
setTimeout(() => {
//调用失败的回调函数 onRejected
handle(onRejected)
})
}
})
} //Promise原型对象 catch ,参数为失败的回掉函数 onRejected
//返回一个新的Promise对象
catch(onRejected) {
return this.then(undefined, onRejected)
} // Promise函数对象的 resolve 方法
//返回一个新的Promise对象,Promise.resolve()中可以传入Promise
static resolve = function (value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(resolve, reject)
} else {
resolve(value)
}
})
} // Promise函数对象的 reject 方法
//返回一个新的Promise对象 Promise.reject中不能再传入Promise static reject = function (reason) {
return new Promise((resolve, reject) => {
reject(reason)
})
} // Promise函数对象的 all 方法,接受一个promise类型的数组
// 返回一个新的Promise对象
static all = function (promises) {
// 保证返回的值得结果的顺序和传进来的时候一致
// 只有全部都成功长才返回成功
const values = new Array(promises.length) // 指定数组的初始长度
let successCount = 0
return new Promise((resolve, reject) => {
promises.forEach((p, index) => { // 由于p有可能不是一个Promise
Promise.resolve(p).then(
value => {
successCount++
values[index] = value
if (successCount === promises.length) {
resolve(values)
}
},
// 如果失败
reason => {
reject(reason)
})
})
}) } // Promise函数对象的 race 方法,接受一个promise类型的数组
// 返回一个新的Promise对象
static race = function (promises) {
return new Promise((resolve, reject) => {
promises.forEach(p => {
Promise.resolve(p).then(
value => {
resolve(value)
}, reason => {
reject(reason)
})
})
}) }
} // 把Promise暴露出去
window.Promise = Promise
})(window)

来自:https://www.bilibili.com/video/BV1MJ41197Eu?from=search&seid=1177747046204864464

Promise对象 异步编程的更多相关文章

  1. Promise和异步编程

    前面的话 JS有很多强大的功能,其中一个是它可以轻松地搞定异步编程.作为一门为Web而生的语言,它从一开始就需要能够响应异步的用户交互,如点击和按键操作等.Node.js用回调函数代替了事件,使异步编 ...

  2. 《深入理解ES6》笔记—— Promise与异步编程(11)

    为什么要异步编程 我们在写前端代码时,经常会对dom做事件处理操作,比如点击.激活焦点.失去焦点等:再比如我们用ajax请求数据,使用回调函数获取返回值.这些都属于异步编程. 也许你已经大概知道Jav ...

  3. Promise对异步编程的贡献以及基本API了解

    异步: 核心: 现在运行的部分和将来运行的部分之间的关系 常用方案: 从现在到将来的等待,通常使用一个回调函数在结果返回时得到结果 控制台(因为console族是由宿主环境即游览器实现的)可能会使用异 ...

  4. 异步编程——promise

    异步编程--promise 定义 Promise是异步编程的一个解决方案,相比传统的解决方法--回调函数,使用Promise更为合理和强大,避免了回调函数之间的层层嵌套,也使得代码结构更为清晰,便于维 ...

  5. 学习Promise异步编程

    JavaScript引擎建立在单线程事件循环的概念上.单线程( Single-threaded )意味着同一时刻只能执行一段代码.所以引擎无须留意那些"可能"运行的代码.代码会被放 ...

  6. ES6深入学习记录(二)promise对象相关

    1.Promise的含义 Promise是异步编程的一种解决方案,比传统的解决方案--回调函数和事件更合理和强大.ES6将其写进了语言标准,统一了用法,原生提供了promise对象. 所谓Promis ...

  7. JavaScript异步编程的主要解决方案—对不起,我和你不在同一个频率上

    众所周知(这也忒夸张了吧?),Javascript通过事件驱动机制,在单线程模型下,以异步的形式来实现非阻塞的IO操作.这种模式使得JavaScript在处理事务时非常高效,但这带来了很多问题,比如异 ...

  8. 异步编程:When.js快速上手

    前些天我在团内做了一个关于AngularJS的分享.由于AngularJS大量使用Promise,所以我把基于Promise的异步编程也一并介绍了下.很多东西都是一带而过,这里再记录下. Angula ...

  9. ES6 之 let和const命令 Symbol Promise对象

    ECMAScript 6入门 ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了. (2016年6月,发布了小幅修订的<ECMASc ...

随机推荐

  1. caffe的python接口学习(4)mnist实例手写数字识别

    以下主要是摘抄denny博文的内容,更多内容大家去看原作者吧 一 数据准备 准备训练集和测试集图片的列表清单; 二 导入caffe库,设定文件路径 # -*- coding: utf-8 -*- im ...

  2. fatal error C1189: #error : This file requires _WIN32_WINNT to be #defined at least to 0x0403. Value 0x0501 or higher is recommended.

    说了原因,下面是修改方法,就是在stdafx.h文件中修改相关的定义,修改完后的效果应该如下: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #ifndef WINVER ...

  3. Spring-AliasRegistry

    使用Spring 的时候我们可以很容易的为某个bean 配置一个或多个别名 <bean id="app:dataSource" class="..."&g ...

  4. models.py连接mysql

    安装pymysql: other setting---project Interpreter---+pymysql 更改数据库 在项目名的同名文件下的settings.py中DATABASES,改成 ...

  5. 前端走进机器学习生态,在 Node.js 中使用 Python

    这次给大家带来一个好东西,它的主要用途就是能让大家在 Node.js 中使用 Python 的接口和函数.可能你看到这里会好奇,会疑惑,会不解,我 Node.js 大法那么好,干嘛要用 Python ...

  6. a标签绑定点击事件失败

    如图 然后对a标签绑定点击事件  无效 换成span标签可以

  7. Raft论文《 In Search of an Understandable Consensus Algorithm (Extended Version) 》研读

    Raft 论文研读 说明:本文为论文 < In Search of an Understandable Consensus Algorithm (Extended Version) > 的 ...

  8. 好看css搜索框样式_分享8款纯CSS搜索框

    最简单实用的CSS3搜索框样式,纯CSS效果无需任何javascript,其中部分搜索框在点击的时候有动画特效,搜索框的应用也是比较普通的,效果如下: 设计网站大全https://www.wode00 ...

  9. 整理一下CSS最容易躺枪的二十规则,大家能躺中几条?

    整理一下CSS最容易躺枪的二十规则,大家能躺中几条? 转载:API中文网 一.float:left/right 或者 position: absolute 后还写上 display:block? 二. ...

  10. bootstrap悬停下拉菜单显示

    使用Bootstrap导航条组件时,如果你的导航条带有下拉菜单,那么这个带下拉菜单的导航在点击时只会浮出下拉菜单,它本身的href属性会失效,也就是失去了超链接功能,这并不是我想要的,我希望导航条的链 ...