理解Promise (4)
then 方法必须 返回一个新的promise
promise2 = promise1.then(onFulfilled, onRejected);
新的Promise 必须返回传递两个方法 onFulfilled, onRejected
If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
onFulfilled, onRejected 其中的某个都要返回 一个value
if either onFulfilled
or onRejected
returns a value x
, run the Promise Resolution Procedure [[Resolve]](promise2, x)
如果onfulled或onrejected返回值x,请运行承诺解决过程[[解决]](promise2,x)。
let x = onfulfilled(this.value);
// x是普通值还是promise 如果是普通值 直接调用promise2的resolve
// 如果是promise 那应该让x这个promise执行 x.then
resolvePromise(promise2,x,resolve,reject);
这段代码是 resolvePromise 承诺解决过程
resolvePromise 这个函数里面 有Promise 这个参数,所以我们要拿到这个值 但是我们直接打印出来这个值 是 underfind 所以我们要用 promise2
这样,我们做到这里的时候 then 方法的大概结构就出来了
then(onfulfilled,onrejected){
let promise2;
promise2 = new Promise((resolve,reject)=>{
if(this.status === 'fulfilled'){
setTimeout(()=>{
try{
let x = onfulfilled(this.value);
// x是普通值还是promise 如果是普通值 直接调用promise2的resolve
// 如果是promise 那应该让x这个promise执行 x.then
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
},);
}
if(this.status === 'rejected'){
setTimeout(()=>{
try{
let x = onrejected(this.reason);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
},)
}
if(this.status === 'pending'){
this.resolveCallbacks.push(()=>{
setTimeout(()=>{
try{
let x = onfulfilled(this.value);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
},)
});
this.rejectCallbacks.push(()=>{
setTimeout(()=>{
try{
let x = onrejected(this.reason);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
},)
})
}
});
return promise2 }
接下来我们来处理 The Promise Resolution Procedure 的问题
If promise
and x
refer to the same object, reject promise
with a TypeError
as the reason.
let resolvePromise = (promise2,x,resolve,reject) => {
if(promise2 === x){
return reject(new TypeError('循环引用'))
}
}
if x
is an object or function,
if(typeof x === 'function' || (typeof x === 'object' && x !== null)){ }
Let then
be x.then
let then = x.then; // 如果取then方法出错 那就用错误拒绝promise2
- f/when
resolvePromise
is called with a valuey
, run[[Resolve]](promise, y)
. - If/when
rejectPromise
is called with a reasonr
, rejectpromise
withr
. - If both
resolvePromise
andrejectPromise
are called, or multiple calls to the same argument are made, the first call takes precedence, and any further calls are ignored.
if(typeof then === 'function'){ // 我就认为他是一个promise
then.call(x,y=>{ // 让当前的promise执行 ,不用多次取then方法了
// y 有可能还是一个promise , 继续调用resolvePromise方法,直到解析出一个常量为止,最终把常量传递下去
if(called) return; // 放置此方法多次被调用
called = true;
resolvePromise(promise2,y,resolve,reject);
},r=>{
if(called) return;
called = true;
reject(r); // 让当前的promise变成失败态即可
})
}else{
// x就是一个普通的对象 并没有then方法
resolve(x);
}
全部的代码:
let resolvePromise = (promise2,x,resolve,reject) => {
// 判断x的类型 来处理promise2是成功还是失败
// 所有的promise都遵循这个规范,不同的人写的promise可能会混用
// 尽可能考虑的周全 要考虑别人promise可能出错的情况
if(promise2 === x){
return reject(new TypeError('循环引用'))
}
// 判断x是不是一个promise ,这个x 可能不是自己的promise 所以为了安全 需要在进行校验,放置调一起用成功和失败
if(typeof x === 'function' || (typeof x === 'object' && x !== null)){
// 尝试取当前x的then方法, 这个then方法可能别人定义的时候 用的Object.defineProperty
let called;
try{
let then = x.then; // 如果取then方法出错 那就用错误拒绝promise2
if(typeof then === 'function'){ // 我就认为他是一个promise
then.call(x,y=>{ // 让当前的promise执行 ,不用多次取then方法了
// y 有可能还是一个promise , 继续调用resolvePromise方法,直到解析出一个常量为止,最终把常量传递下去
if(called) return; // 放置此方法多次被调用
called = true;
resolvePromise(promise2,y,resolve,reject);
},r=>{
if(called) return;
called = true;
reject(r); // 让当前的promise变成失败态即可
})
}else{
// x就是一个普通的对象 并没有then方法
resolve(x);
}
}catch(e){
if(called) return;
called = true;
reject(e);
}
}else{
// x肯定一个常量
resolve(x);
}
} class Promise{
constructor(executor){
this.status = 'pending';
this.value;
this.reason;
this.resolveCallbacks = []; // 当then是pending 我希望吧成功的方法都放到数组中
this.rejectCallbacks = [];
let resolve = (value)=>{
if(this.status == 'pending'){
this.status = 'fulfilled';
this.value = value;
this.resolveCallbacks.forEach(fn=>fn()); // 发布
}
}
let reject = (reason)=>{
if(this.status === 'pending'){
this.status = 'rejected';
this.reason = reason;
this.rejectCallbacks.forEach(fn=>fn())
}
}
try{
executor(resolve,reject);
}catch(e){
reject(e);
}
}
then(onfulfilled,onrejected){
let promise2;
promise2 = new Promise((resolve,reject)=>{
if(this.status === 'fulfilled'){
setTimeout(()=>{
try{
let x = onfulfilled(this.value);
// x是普通值还是promise 如果是普通值 直接调用promise2的resolve
// 如果是promise 那应该让x这个promise执行 x.then
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
},);
}
if(this.status === 'rejected'){
setTimeout(()=>{
try{
let x = onrejected(this.reason);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
},)
}
if(this.status === 'pending'){
this.resolveCallbacks.push(()=>{
setTimeout(()=>{
try{
let x = onfulfilled(this.value);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
},)
});
this.rejectCallbacks.push(()=>{
setTimeout(()=>{
try{
let x = onrejected(this.reason);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
},)
})
}
});
return promise2 }
}
module.exports = Promise;
理解Promise (4)的更多相关文章
- 大白话讲解Promise(二)理解Promise规范
上一篇我们讲解了ES6中Promise的用法,但是知道了用法还远远不够,作为一名专业的前端工程师,还必须通晓原理.所以,为了补全我们关于Promise的知识树,有必要理解Promise/A+规范,理解 ...
- 彻底理解Promise对象——用es5语法实现一个自己的Promise(上篇)
本文同步自我的个人博客: http://mly-zju.github.io/ 众所周知javascript语言的一大特色就是异步,这既是它的优点,同时在某些情况下也带来了一些的问题.最大的问题之一,就 ...
- 理解Promise的三种姿势
译者按: 对于Promise,也许你会用了,却并不理解:也许你理解了,却只可意会不可言传.这篇博客将从3个简单的视角理解Promise,应该对你有所帮助. 原文: Three ways of unde ...
- 理解Promise的3种姿势
译者按: 对于Promise,也许你会用了,却并不理解:也许你理解了,却只可意会不可言传.这篇博客将从3个简单的视角理解Promise,应该对你有所帮助. 原文: Three ways of unde ...
- 分步理解 Promise 的实现
一个 Promise 的运用: var firstPromise = new Promise(function(resolve,reject){ setTimeout(function(){ var ...
- 理解promise 02
1:promise是什么? 就是(链式)包装的回调函数. 2:语法 new Promise( function(resolve, reject) {...} /* executor */ ); exe ...
- 160701、理解 Promise 的工作原理
Javascript 采用回调函数(callback)来处理异步编程.从同步编程到异步回调编程有一个适应的过程,但是如果出现多层回调嵌套,也就是我们常说的厄运的回调金字塔(Pyramid of Doo ...
- 160623、理解 Promise 的工作原理
Javascript 采用回调函数(callback)来处理异步编程.从同步编程到异步回调编程有一个适应的过程,但是如果出现多层回调嵌套,也就是我们常说的厄运的回调金字塔(Pyramid of Doo ...
- 理解Promise简单实现的背后原理
在写javascript时我们往往离不开异步操作,过去我们往往通过回调函数多层嵌套来解决后一个异步操作依赖前一个异步操作,然后为了解决回调地域的痛点,出现了一些解决方案比如事件订阅/发布的.事件监听的 ...
- 理解promise 01
原文地址: http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html 用Javascript的小伙伴们,是时候承认了,关于 ...
随机推荐
- synchronized 同步
1.synchronized关键字的作用域有二种: 1)是某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果一个对象有 ...
- 【转】结构化日志类库 ---- Serilog库
源地址:https://www.cnblogs.com/mq0036/p/8479956.html 解决异常: Invalid cast from 'System.String' to 'Serilo ...
- SpringBoot项目的前端+thymeleaf模板引擎
SpringBoot项目创建之后,后台的框架是SpringMVC.但前端的resource和template目录都是空的.这个时候需要创建前台页面. 习惯上,我们会创建JSP,但是,SpringBoo ...
- Oracle10g 64位 在Windows 2008 Server R2 中的安装 DBconsole无法启动
致谢!本文参考http://www.cnblogs.com/leiOOlei/archive/2013/08/19/3268239.html 背景: 操作系统Windows 2008 Server R ...
- leetcode-mid-array-49 Group Anagrams
mycode 95.35% 思路:构建字典 class Solution(object): def groupAnagrams(self, strs): """ :ty ...
- 十二、python字符串方法汇总
'''1. index():检测字符串str1中是否包含字符串str2 语法:str1.index(str2,beg,end) str:指定检索的字符串:beg开始的索引,默认为0:end结束的索引, ...
- fedora如何使用themes主题?
DBus: 是一个 local 的IPC 进程间通信机制 如果是(一对一) 多对多的通信, 则DBUS 后台充当了一个路由器的角色. ibus: 是包含: python gtk dbus的 scim- ...
- LeetCode 47——全排列 II
1. 题目 2. 解答 在 LeetCode 46--全排列 中我们已经知道,全排列其实就是先确定某一个位置的元素,然后余下就是一个子问题.在那个问题中,数据没有重复,所以数据中的任意元素都可以放在最 ...
- nginx代理前端项目
参考:https://segmentfault.com/a/1190000013980557 https://segmentfault.com/a/1190000013267839 注意 1.只能有 ...
- 浅谈vue$router 和 $route的区别
最近在学习vue的单页面应用开发,需要vue全家桶,其中用到了VueRouter,在路由的设置和跳转中遇到了两个对象$router 和 $route ,有些傻傻分不清,后来自己结合网上的博客和自己本地 ...