Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >打开Promise的正确姿势

打开Promise的正确姿势

作者头像
用户1097444
发布于 2022-06-29 09:04:23
发布于 2022-06-29 09:04:23
79700
代码可运行
举报
运行总次数:0
代码可运行

引言

最近实践中需要用到大量的异步回调风格代码的编写,作者最近处于同步编程风格转为异步编程风格的状态。同时第一时间遇到了下面提到的代码,第一直觉就是该代码肯定有问题!但是问题在哪里有讲不出来,感觉非常蛋疼与疑惑。先上当时遇到的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 删除,先检查是否存在,存在再执行真正的删除动作
function del() {
    // 查找
    return find().then(function(resultOfFind) {
        // 如果没找到,直接返回
        if (!resultOfFind) {
            return false;
        }
        // 执行真正做删除操作的方法
        return reallyDelete();
    }, function(err) {
        //  处理错误情况
        handle(err)
    })
}

function deleteItem(req, res) {
    // 删除
    del().then(function(resultOfDelete) {
        // 判断是没找到或者是真正做删除操作的结果,进行处理
        //  ...
        res(resultOfDelete)
    }, function(err) {
        // 处理错误情况
        // ...
        res(err)
    })
}

上面代码做的事情很简单: 1、删除前检查是否存在; 2、存在则执行删除操作 / 不存在则直接返回; 3、使用删除的结果 / 处理删除产生的错误,返回响应;

你看出来哪里可能出现问题了吗?

OK,这里容作者买一个小小的关子。同学们如果有疑问,那就继续往下阅读吧。 看出问题的大神们也请不吝指教。 让作者为你带来打开Promise的正确姿势,让你使用Promise的时候用的更爽,后人接手你的代码看的更爽,也避免出现莫名其妙的问题而无法对问题进行定位的情况。

目录

1、 Promise基础介绍 2、 Promise与金字塔问题 3、 Promise与循环 4、 resolve(value) VS resolve(promise) 5、 then返回的promise实例 6、 Promise与错误处理 7、 Promise状态透传

1. Promise基础介绍

Promise是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6将其写进了语言标准,统一了用法,原生提供了Promise对象。 本文所描述的Promise指Promises/A+规范定义的Promise,可参考Promise/A+,一个可靠的可共同协作的JavaScript Promise开放标准

1.1 常见的用法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var promise = new Promise(function(resolve, reject) {
    // ... some code
    if ( /* 异步操作成功 */ ) {
        resolve(value);
    } else {
        reject(error);
    }
});

promise.then(function(value) {
    // success 
}, function(error) {
    // failure 
});

简单来说: 1、Promise构造方法接受一个方法作为参数,该方法传入两个参数,resolve和reject。 2、resolve用来将Promise对象的状态置为成功,并将异步操作结果value作为参数传给成功回调函数。 3、reject用来将Promise对象的状态置为失败,并将异步操作错误error作为参数传给失败回调函数。 4、then方法绑定两个回调函数,第一个用来处理Promise成功状态,第二个用来处理Promise失败状态。

1.2 Promise 状态

Promise对象有三种状态:

  • Pending(进行中)
  • Fulfilled(已完成,又称为Resolved)
  • Rejectd(已失败)

如上图所示,Promise对象有两个特点: 1、对象状态只由异步操作结果决定。resolve方法会使Promise对象由pendding状态变为fulfilled状态;reject方法或者异常会使得Promise对象由pendding状态变为rejected状态。Promise状态变化只有上图这两条路径。 2、对象状态一旦改变,任何时候都能得到这个结果。即状态一旦进入fulfilled或者rejected,promise便不再出现状态变化,同时我们再添加回调会立即得到结果。这点跟事件不一样,事件是发生后再绑定监听,就监听不到了。

举个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var promise = new Promise(function(resolve, reject) {
    resolve('value'); //1
    // reject('error'); //2
    // throw Error('exception'); //3
    // return 'return' //4
});

promise.then(function(value) {
    console.log('fulfilled', value)
}, function(error) {
    console.log('rejected', error)
});
// 上面的代码中1-4处代码的调用分别输出:
// fulfilled value  
// rejected error  
// rejected Error: exception(…)  
// [没有输出]

// 测试状态变更后才绑定事件
// setTimeout(function() {
//     promise.then(function(value) {
//         console.log('fulfilled1', value)
//     })
// }, 1000)

当然也可以参考Promise/A+里面的定义:

2.1.Promise状态   promise状态为pending, fulfilled和rejected中的其中一种。   2.1.1.当promise状态为pending时:     2.1.1.1.promise的状态可以转换为fulfilled或rejected。   2.1.2.当promise状态为fulfilled时:     2.1.2.1.无法转换为其他状态。     2.1.2.2.必须有一个不可改变的值作为onFulfilled事件处理函数的入参   2.1.3.当promsie状态为rejected时:     2.1.3.1.无法转换为其他状态。     2.1.3.2.必须有一个不可改变的值作为onRejected事件处理函数的入参

2. Promise与金字塔问题

金字塔问题指的是我们的程序中如果出现大量的回调任务需要顺序执行时,可能会出现这些代码慢慢向右侧屏幕延伸的问题。通常我们多次异步操作需要依赖上一次异步操作的结果时,我们会这样写。举个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
getUserAdmin().then(function(result) {
    if ( /*管理员*/ ) {
        getProjectsWithAdmin().then(function(result) {
            /*根据项目id,获取模块列表*/
            getModules(result.ids).then(function(result) {
                /*根据模块id,获取接口列表*/
                getInterfaces(result.ids).then(function(result) {
                    // ...
                })
            })
        })
    } else {
        //...
    }
})

上面的例子数据有项目-模块-接口这样的层次关系。为了获取接口列表,每一次操作都需要依赖上一个异步操作的结果。你会发现使用顺序调用的逻辑这样写使得代码层次嵌套过深,逻辑不清晰,很难进行阅读。如果我们像使用回调一样使用Promise,虽然结果是正确的,但是这完全没有利用到Promise的优势。

我们应该像下面这样写:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
getUserAdmin().then(function(reult) {
    if ( /*管理员*/ ) {
        return getProjectsWithAdmin();
    } else {
        return getProjectsWithUser();
    }
}).then(function(result) {
    /*获取project id列表*/
    return getModules(result.ids);
}).then(function(result) {
    /*获取project id列表*/
    return getInterfaces(result.ids)
}).then(function(result) {
    // ...
})

如果你再将这些操作封装到一个命名函数中,你就会得到下面这样的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
getUserAdmin()
    .then(getProjects)
    .then(getModules)
    .then(getInterfaces)
    .then(procResult)

是不是觉得赏心悦目,作者第一次看到这样的代码时简直惊为天人,这简直是在写诗好吗?

这种写法被称为 composing promises ,是 promises 的强大能力之一。这样写可以带来好处:

  • 清晰的代码结构。
  • 避免始料不及的错误。进行快速的问题定位,避免难以调试更甚至于失败了而没有任何反馈。

关于第二点,会在下面错误处理中进行说明。

3. Promise与循环

上面讲到了异步操作的顺序执行,那如果我们需要同时执行一组异步操作呢? 举个例子,我们需要删除指定项目ID下的所有子模块。有的同学可能会这样写:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
getModules(projectID).then(function(modules) {
    modules.forEach(function(module) {
        removeModule(module.moduleID);
    })
    // A
}).then(function(result) {
    // ...
})

这里存在一个问题,就是A位置并不会等待所有的removeModule方法结束,而是直接返回undefined,这意味着后面的方法即不会等待删除动作结束也无法获得删除动作的结果,所以你没办法保证删除动作已经完成。 关于在then方法绑定的回调函数中的返回值,我们会在第五节中进行讨论。

那我们怎么保证所有异步操作都成功了呢?

Promise提供了一个很方便的方法叫做Promise.all。我们可以这样做:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
getModules(projectID).then(function(modules) {
    var tasks = [];
    modules.forEach(function(module) {
        tasks.push(removeModule(module.moduleID));
    })
    return Promise.all(tasks);// 注意这里一定要有return
}).then(function(result) {
    // ...
})

Promise.all方法用于将多个Promise实例,包装成一个新的Promise实例。 Promise.all方法接受一个数组作为参数,数组里的元素都是Promise对象的实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为Promise实例,再进一步处理。(Promise.all方法的参数可以不是数组,但必须具有Iterator接口,且返回的每个成员都是Promise实例。)

  • 当该数组里的所有Promise实例都进入Fulfilled状态,Promise.all返回的实例才会变成Fulfilled状态。并将Promise实例数组的所有返回值组成一个数组,传递给Promise.all返回实例的回调函数。
  • 当该数组里的某个Promise实例都进入Rejected状态,Promise.all返回的实例会立即变成Rejected状态。并将第一个rejected的实例返回值传递给Promise.all返回实例的回调函数。

Promise.race方法跟Promise.all方法差不多。唯一的区别在于该方法返回的Promise实例并不会等待所有Proimse都跑完,而是只要有一个Promise实例改变状态,它就跟着改变状态。并使用第一个改变状态实例的返回值作为返回值。

当然前述的代码还可以更优雅一点:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
getModules(projectID).then(function(modules) {
    return Promise.all(modules.map(module) { // 注意这里一定要有return
        return removeModule(module.moduleID);
    });
}).then(function(result) {
    // ...
})

4. resolve(value) VS resolve(promise)

我们会在异步操作成功时调用resolve函数,其作用是将Promise对象的状态从Pending变为Resolved,并将异步操作的结果,作为参数传递给Pending状态的回调函数。

而我们传入resolve的值实际上并不一定出现在Fulfilled状态的回调函数中,为什么呢?

我们来先看一个使用resolve传递操作结果的例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var d = new Date();

var promise = new Promise(function(resolve, reject) {
    // 一秒后进入resolve,并传递值
    setTimeout(resolve, 1000, 'resolve from promise');
});

// 绑定回调函数
promise.then(
    result => console.log('result:', result, new Date() - d),
    error => console.log('error:', error)
)
// result: resolve from promise 1002

大约过了一秒左右,我们可以看到在fulfilled状态的回调方法中,我们打印出了上面注释中的内容。我们能够通过resolve方法传递操作的结果,然后在回调方法中使用这些结果。

如果我们在resolve中传入一个Promise实例呢?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var d=new Date();

// 创建一个promise实例,该实例在2秒后进入fulfilled状态
var promise1 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 2000, 'resolve from promise 1');
});

// 创建一个promise实例,该实例在1秒后进入fulfilled状态
var promise2 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 1000, promise1); // resolve(promise1)
});

promise2.then(
    result => console.log('result:', result,new Date()-d),
    error => console.log('error:', error)
)

上面的例子中,你可能觉得再经过一秒左右后会打印出promise1实例。实际上上面的代码最后打印出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
result: resolve from promise 1 2002

OK,我们看一下Promise/A+是怎么说的: [[Resolve]](promise, x)

2.3.2.如果x是一个promise实例, 则以x的状态作为promise的状态   2.3.2.1.如果x的状态为pending, 那么promise的状态也为pending, 直到x的状态变化而变化。   2.3.2.2.如果x的状态为fulfilled, promise的状态也为fulfilled, 并且以x的不可变值作为promise的不可变值。   2.3.2.3.如果x的状态为rejected, promise的状态也为rejected, 并且以x的不可变原因作为promise的不可变原因。 2.3.4.如果x不是对象或函数,则将promise状态转换为fulfilled并且以x作为promise的不可变值。

简单来说呢,就是因为promise2中调用了resolve(promise1),此时promise1的状态会传递给promise2,或者说promise1的状态决定了promise2的状态。所以当promise1进入fulfilled状态,promise2的状态也变为fulfilled,同时将promise1自己的不可变值作为promise2的不可变值,所以promise2的回调函数打印出了上述结果。promise1进入rejected状态的结果,同学们可以自己试一试。

而当我们resolve(value)的时候就遵循Promise/A+中的2.3.4条规范,将value传递给了fulfilled状态的回调函数。

另外,通过这里例子我们也可以发现。运行时间是2秒而不是3秒。也就是说Promise新建后就会立即执行

ps:resolve方法传入的实参不限于值类型或者Promise实例。更多内容请参考Promise/A+

5. then返回的promise实例

then方法返回的是一个新的Promise实例 then方法返回的是一个新的Promise实例 then方法返回的是一个新的Promise实例 重要的事情要说三遍。这也是我们能够使用第二节中的链式写法的最重要原因。举个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var d = new Date();

var promise = new Promise(function(resolve, reject) {
    setTimeout(resolve, 1000, 'resolve from promise');
});


var promise2 = promise.then(function(result) {
    console.log(result);
});
//promise.then() 返回的是一个新的Promise实例
promise.tag = '1';
console.log(promise)
console.log(promise2)
// 打印结果:
// Promise {tag: "1", [[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
// Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
// resolve from promise

当然你可以在同一个Promise实例中多次调用.then绑定回调方法,当该Promise实例状态变化时,将按调用.then的顺序执行回调方法。

那在.then绑定的回调方法onFulfilled和onRejected中,不同的返回值对后续链式有什么影响呢?

回调方法返回 值
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var d = new Date();

var promise1 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 1000, 'resolve from promise1');
    // setTimeout(reject, 1000, 'reject from promise1');
});

var promise2 = promise1.then(function(result) {
    console.log('promise1.then(resolve):', result);
    return result;
}, function(error) {
    console.log('promise1.then(reject):', error);
    return error;
});

promise2.then(
    result => console.log('result:', result, new Date() - d),
    error => console.log('error:', error, new Date() - d)
)

// promise1.then(resolve): resolve from promise1
// result: resolve from promise1 1012

通过运行上面的例子,我们会发现promise的状态无论是fulfilled或者rejected,其绑定的.then方法返回的Promise实例(即promise2)都只会执行它的onFulfilled回调方法。

回调方法返回 promise实例
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var d = new Date();

var promise1 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 1000, 'resolve from promise1');
});

var promise2 = promise1.then(function(result) {
    console.log('promise1.then(resolve):', result);
    return new Promise(function(resolve, reject) {
        setTimeout(resolve, 2000, 'from new promise');
    });
})
promise2.then(
    result => console.log('result:', result, new Date() - d),
    error => console.log('error:', error, new Date() - d)
)
// promise1.then(resolve): resolve from promise1
// result: from new promise 3021

上面的例子中,promise1的回调方法onFulfilled返回的是一个新的promise实例,该实例在2秒后进入fulfilled状态。 运行该例子,我们会发现最后promise2的回调方法近三秒钟后才执行。也就是promise1和promise2的总共运行时间,为什么呢? 同时第二行打印的内容来自于promise2回调方法中返回的新Promise实例,这就是怎么一个过程呢?

Promise/A+规定

2.2.7. then方法必须返回一个promise实例 promise2 = promise1.then(onFulfilled, onRejected);   2.2.7.1. 如果 onFulfilledonRejected 函数返回值为x,那么执行Promise处理过程 [[Resolve]](promise2, x)。   2.2.7.2. 如果 onFulfilledonRejected 函数抛出异常e,那么promise2将执行 reject(e)

查看其中2.2.7.1的规定,我们会发现在onFulfilled或者onRejected中,无论是return值或者return Promise实例,实际上都是去调用[[Resolve]](promise2, x)

当我们在promise1的回调方法中返回x的时候,相当于调用promise2.resolve(x)

所以结合本文第四节的内容,我们可以就知道 : x为值的时候,promise2直接进入fulfilled状态,无论promise1的状态是fulfilled或者是rejected,并把x传给onFulfilled回调方法; x为promise实例的时候,x的状态决定了promise2的状态

回调方法没有返回语句

如果promise1的回调方法中没有返回语句,那promise2的回调方法中会打印什么内容呢?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var d = new Date();

var promise1 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 1000, 'resolve from promise1');
});

var promise2 = promise1.then(function(result) {
    console.log('promise1.then(resolve):', result);
})

promise2.then(
    result => console.log('result:', result, new Date() - d),
    error => console.log('error:', error, new Date() - d)
)
// promise1.then(resolve): resolve from promise1
// result: undefined 1009

当js函数中没有返回值的时候,相当于是return undefined。也就是说相当调用了promise2.resolve(x),而这里的x为undefined,所以我们在promise2的回调方法中打印出了undefined。

所以这里作者给的建议是:在回调方法中一定要有return语句,放弃在回调方法中使用return,相当于放弃获取在该回调方法中的所有操作结果

6. Promise与错误处理

.then(onFulfilled,onRejected) .then传入的第二个回调方法在Promise实例状态变为rejected的时候会被调用,通常用于处理异步操作失败的情况。 让我们再来瞄一眼本文开头的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 删除,先检查是否存在,存在再执行真正的删除动作
function del() {
    // 查找
    return find().then(function(resultOfFind) {
        // 如果没找到,直接返回
        if (!resultOfFind) {
            return false;
        }
        // 执行真正做删除操作的方法
        return reallyDelete();
    }, function(err) {
        //  处理错误情况 —— A
        handle(err)
    })
}

function deleteItem(req, res) {
    // 删除
    del().then(function(resultOfDelete) {
        // 判断是没找到或者是真正做删除操作的结果,进行处理
        //  ...
        res(resultOfDelete)
    }, function(err) {
        // 处理错误情况 ——B
        // ...
        res(err)
    })
}

经过上面前五节的讲解,想必你一定可以找出问题: A位置:如果find方法返回的promise实例如果进入rejected状态,经过handle的处理后,没有明确的将错误返回,或者将该promise实例置为rejected状态。这种情况在第五节已经提过了,这里del方法返回的promise实例直接就是fulfilled状态,而且传入的回调参数为undefined,也就是说这边的resultOfDelete为undefined。这可能导致后续的回调函数没办法正常的工作,而且对这种异常情况完全没有做处理。

B位置:通过对A位置的分析,相比你也发现B位置的错误处理实际上并不能很好的处理到promise实例的异常。

那么我们应该怎么做呢? 首先在A位置,如果你需要在这里对异常或者rejected状态做操作,例如记录系统日志。请考虑后续是否可能会用到del的操作结果,如果存在这种情况(例如我们这里的用法),那么一定要将该状态暴露到下一个promise中。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function del() {
    // 查找
    return find().then(function(resultOfFind) {
        // ...
    }, function(err) {
        handle(err);
        return Promise.reject(err); // 这里不要遗漏return关键字
    })
}

但是这样又可能出现对同一个错误多次处理的情况。 作者这里推荐使用.catch方法。

.catch

Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 下面两种写法是等价的
somePromise.catch(function(err) {
    //...
})
somePromise.then(null, function(err) {
    //...
})

但是下面两段代码是不等价的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 1
somePromise.then(function() {
    return someOtherPromise();
}, function(err) {
    //...
})
// 2
somePromise.then(function() {
    return someOtherPromise();
}).catch(function(err) {
    //...
})

为什么呢?举一个例子你可能就明白了:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
somePromise.then(function() {
    throw new Error('oh no');
}, function(err) {
    //...
})
somePromise.then(function() {
    throw new Error('oh no');
}).catch(function(err) {
    //...
})

你会发现上一种写法你没办法处理onFulfilled回调函数抛出的异常,而第二种是可以处理这种情况的异常的。所以作者推荐大家都是用catch来处理失败情况,而不是then的第二个参数。你可以在你的promise最后都加上一个catch,以处理你可能没有察觉到的错误情况。 当然有些情况下我们不得不使用then的第二个参数,这时候你就需要注意是否存在别人调用这个方法的可能,并做好错误处理。 所以文章开头出现的问题可以这样解决:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//删除,先检查是否存在,存在再执行真正的删除动作
function del() {
    // 查找
    return find().then(function(resultOfFind) {
        // 如果没找到,直接返回
        if (!resultOfFind) {
            return false;
        }
        // 执行真正做删除操作的方法
        return reallyDelete();
    })
}

function deleteItem(req, res) {
    // 删除
    del().then(function(resultOfDelete) {
        // 判断是没找到或者是真正做删除操作的结果,进行处理
        //  ...
        res(resultOfDelete)
    }).catch(function(err) {
        // 处理错误情况
        // ...
        res(err)
    })
}

7.Promise状态透传

在看上一节内容的时候你可能会有疑问,为什么之前没有设置回调函数对rejected状态进行处理,后面可以使用catch直接捕获之前的结果呢? 我们来先看个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var d = new Date();

var promise1 = new Promise(function(resolve, reject) {
    setTimeout(reject, 1000, 'reject from promise1');
});

var promise2 = promise1.then(result => {
    console.log('promise1.then(resolve):', result);
});

promise2.then(
    result => console.log('result:', result, new Date() - d),
    error => console.log('error:', error, new Date() - d)
);

//error: reject from promise1 1004

是的,正如我们所想,promise2的onRjected回调方法正确的处理了来自promise的rejected状态。

来看Promise/A+是怎么说的:

2.2.7. then方法必须返回一个promise实例 promise2 = promise1.then(onFulfilled, onRejected);   2.2.7.3. 如果 promise1的 onFulfilled 不是函数,那么promise1的不可变值将传递到promise2并作为promise2的不可变值。   2.2.7.4. 如果 promise1的 onRejected不是函数,那么promise1的不可变原因将传递到promise2并作为promise2的不可变原因,并作为promise2的 onRejected 的入参。

这就是Promise的状态透传特点,如果当前的promise实例没有绑定回调函数,或者绑定的不是函数,那么当前实例就会把其状态以及不可变值或者不可变原因传递给当前实例调用.then方法返回的新promise实例。 在上述例子中就表现为,promise1把它的不可变原因以及rejected状态传递给了promise2,所以promise2的onRejected回调方法就把promise1中reject的内容打印出来了。 这也是为什么我们在第六节提到可以使用最后的catch捕获之前没有进行处理的rejected状态的原因了。

最后

本文从项目中遇到的代码出发,结合Promise/A+规范,对Promise使用过程中容易出现疑和问题的点进行了剖析与验证。 请大家记住两点:

  • 回调方法中一定要使用return语句,避免调用者丢失其处理状态与结果。
  • 在promise实例的最后使用catch方法,用来做整体的异常捕获与处理。

参考资料

Promise/A+ promise对象 关于promises,你理解了多少?

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2016-08-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯IMWeb前端团队 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
JS中Promise理解与应用
Promise是ES6一个新的特性,本身是个对象用于表示一个异步操作的最终完成 (或失败), 及其结果值。创建一个Promise对象:
Light413
2020/04/08
1.2K0
JS中Promise理解与应用
如何写出一个惊艳面试官的 Promise【近 1W字】 前言源码1.Promise2.Generator3.async 和 await4.Pro
1.高级 WEB 面试会让你手写一个Promise,Generator 的 PolyFill(一段代码); 2.在写之前我们简单回顾下他们的作用; 3.手写模块见PolyFill.
火狼1
2020/05/09
7100
如何写出一个惊艳面试官的 Promise【近 1W字】
                            前言源码1.Promise2.Generator3.async 和 await4.Pro
带你写出符合Promise/A+规范Promise的源码
Promise是前端面试中的高频问题,如果你能根据PromiseA+的规范,写出符合规范的源码,那么我想,对于面试中的Promise相关的问题,都能够给出比较完美的答案。
刘小夕
2020/07/29
8740
带你写出符合Promise/A+规范Promise的源码
【MDN学习】JavaScript 之 Promise
简单来说,可以一次接收多个 Promise,只会返回一个 Promise 实例,但是 Promise 是有两种返回情况的
Gorit
2022/03/15
9450
手写一个Promise/A+,完美通过官方872个测试用例
前段时间我用两篇文章深入讲解了异步的概念和Event Loop的底层原理,然后还讲了一种自己实现异步的发布订阅模式:
蒋鹏飞
2020/10/15
7500
手写一个Promise/A+,完美通过官方872个测试用例
JS原生引用类型解析7-Promise类型
ES6引入了一个全新的对象Promise,用于表示一个异步操作的最终状态(完成或失败),以及其返回的值。Promise最直接的好处就是链式调用,另外在错误捕获上也很方便。用同步的写法解决异步问题,代码直观,易于理解维护,解决了回调地狱的问题。关于Promise的详细讲解和更多用例我会开专门文章讨论。这里我们主要看一下Promise及其原型的属性和方法。
love丁酥酥
2018/08/27
1.4K0
Javascript之我也来手写一下Promise
  Promise太重要了,可以说是改变了JavaScript开发体验重要内容之一。而Promise也可以说是现代Javascript中极为重要的核心概念,所以理解Promise/A+规范,理解Promise的实现,手写Promise就显得格外重要。如果要聊Promise就要从回调函数聊到回调地狱,再聊到同步异步,最终聊到Promise、async await。但是我们这篇文章,目的是手写Promise,这些前置知识如果大家不了解的话,希望可以去补充一下。那你可能会说了,我他妈不懂你在说啥,我就是想手写Promise,不行么?大佬~~那肯定是没问题的。好了,废话不多说,咱们开始吧。
zaking
2022/09/09
8430
手写Promise完整介绍
Promise是一种用于处理异步操作的机制,它可以将异步操作的结果以同步的方式进行处理和返回。在JavaScript中,Promise是一种内置对象,但我们也可以手动实现一个Promise类来更好地理解其原理和工作方式。
can4hou6joeng4
2023/11/16
4480
前端异步技术之Promise
由于是参(抄)考(袭)前辈的polyfill,自己编码测试时出现了两处错误,ES6 Promise 规范的2.3.1和2.3.4
Jack Chen
2019/03/06
5080
JS:你真的会用 Promise 吗?
试想一下,有 3 个异步请求,第二个需要依赖第一个请求的返回结果,第三个需要依赖第二个请求的返回结果,一般怎么做?
WEBJ2EE
2019/07/19
2.6K0
JS:你真的会用 Promise 吗?
实现Promise的原型方法--前端面试能力提升
静态方法:resolve、reject、race、all、allSettled、any
helloworld1024
2022/09/30
6560
手写系列-这一次,彻底搞懂 Promise
想要实现 Promise,必须先了解 Promise 是什么,以及 Promise 有哪些功能。
游魂
2023/10/17
2610
手写系列-这一次,彻底搞懂 Promise
扒一扒PROMISE的原理,大家不要怕!
在前端的日常工作中,回调函数(callback)应该是见怪不怪了,但是当回调函数遇上了异步(async),这就令人发指了。那么异步是什么意思呢,简单地说就是不等你执行完,就先执行下方的代码了。
小美娜娜
2019/04/04
6320
从0到1实现Promise
Promise大家一定都不陌生了,JavaScript异步流程从最初的Callback,到Promise,到Generator,再到目前使用最多的Async/Await(如果对于这些不熟悉的可以参考我另一篇文章《JavaScript异步编程》),这不仅仅是技术实现的发展,更是思想上对于如何控制异步的递进。Promise作为后续方案的基础,是重中之重,也是面试时候最常被问到的。
leocoder
2022/04/08
9521
从0到1实现Promise
【面试题解】详解 Promise A Plus ,从规范角度看 Promise
你可能经常使用 Promise?但你知道你使用的 Promise 是怎么来的么?你知道 Promise 遵循什么规范吗?
一尾流莺
2022/12/10
3180
初识Promise
Promise是异步编程的一种优雅的解决方案。它相比于回调和事件交互,更加合理和强大。它改善了深度回调的问题。 回调里面还有回调,层级较深的,代码看起来特别凌乱。而通过事件交互会多做一些工作,比如发送事件,监听事件,事件回调等操作。而Promise能够获取异步操作的结果,这样的话,方便进一步处理接下来的逻辑。
Umbrella1024
2021/03/23
5340
从0到1实现Promise前言正文结束
Promise大家一定都不陌生了,JavaScript异步流程从最初的Callback,到Promise,到Generator,再到目前使用最多的Async/Await(如果对于这些不熟悉的可以参考我另一篇文章《JavaScript异步编程》),这不仅仅是技术实现的发展,更是思想上对于如何控制异步的递进。Promise作为后续方案的基础,是重中之重,也是面试时候最常被问到的。
leocoder
2018/10/31
1K0
JavaScript的异步编程之Promise
一种更优的异步编程统一 方法,如果直接使用传统的回调函数去完成复杂操作就会形成回调深渊
开水泡饭
2022/12/26
6670
JavaScript的异步编程之Promise
JavaScript Promise
  我们都知道 JavaScript 是一种同步编程语言,上一行出错就会影响下一行的执行,但是我们需要数据的时候总不能每次都等上一行执行完成,这时就可以使用回调函数让它像异步编程语言一样工作。   像 NodeJS 就是采用异步回调的方式来处理需要等待的事件,使得代码会继续往下执行不用在某个地方等待着。但是也有一个不好的地方,当我们有很多回调的时候,比如这个回调执行完需要去执行下个回调,然后接着再执行下个回调,这样就会造成层层嵌套,代码不清晰,很容易进入“回调监狱”。。。   所以 ES6 新出的 Promise 对象以及 ES7 的 async、await 都可以解决这个问题。   Promise 是用来处理异步操作的,可以让我们写异步调用的时候写起来更加优雅,更加美观便于阅读。Promise 为承诺的意思,意思是使用 Promise 之后他肯定会给我们答复,无论成功或者失败都会给我们一个答复,所以我们就不用担心他跑了哈哈。   Promise 有三种状态:pending(未决定),resolved(完成fulfilled),rejected(失败)。只有异步返回时才可以改变其状态,因此我们收到的 Promise 过程状态一般只有两种:pending->fulfilled 或者 pending->rejected。
老猫-Leo
2023/12/11
2640
JavaScript Promise
图解JavaScript——代码实现【2】(重点是Promise、Async、发布/订阅原理实现)
本节主要阐述六种异步方案:回调函数、事件监听、发布/订阅、Promise、Generator和Async。其中重点是发布/订阅、Promise、Async的原理实现,通过对这几点的了解,希望我们前端切
前端迷
2020/10/26
7530
图解JavaScript——代码实现【2】(重点是Promise、Async、发布/订阅原理实现)
推荐阅读
相关推荐
JS中Promise理解与应用
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文