你的承诺我永远不懂?什么是js里的promise

Promise对象,ES6新增的一个全新特性,那么它代表什么意思呢?我们今天就好好研究一下。

1:背景介绍

首先看下它的基本概念,先看一下MDN里给的定义:Promise 对象用于表示一个异步操作的最终状态(完成或失败),以及其返回的值。

有点绕是不是,其实主要用于异步计算,表示一个现在将来或者永远不可能用到的值。

2.知识剖析

promise如果按用途来解释的话
1:主要用于异步计算
2:主要用于异步操作队列化,按照期望的顺序执行,返回预期的结果
3:可以在对象之间传递和操作promise,帮助我们处理队列

而什么又是异步操作呢?先来看看语法

异步操作的常见语法

document.getElementById("start").addEventlistener("click",start,false)

function start(){}

或者jQuery

$(".start").on("click",start)

我们也可以简单地理解为:可以改变程序正常执行顺序的操作就可以看成是异步操作。当浏览器觉得你这个操作很耗时的时候,它就把你从队伍里拿出来。我们来看下浏览器的处理过程。

1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。

2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。

3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。

(4)主线程不断重复上面的第三步。

好像没什么神奇的对不对?那么来看一下同步操作,

比如你去了一个饭店,想点菜,让服务员给你拿个菜单服务员说好的,等这桌吃完了我服务完这一桌就给你拿你是不是很生气,很想骂她,我只是拿个菜单而已

这就是同步操作的缺点,如果有一个非常耗时的操作,那么后面的进程都无法进行了

所以"异步模式"非常重要。在浏览器端,耗时很长的操作都应该异步执行,避免浏览器失去响应,最好的例子就是Ajax操作。

好了,言归正传,那么我们为什么需要promise呢?

先来看一个常见的jQuery ajax请求实例

 $.ajax({
        success:function(res1){


            //------请求B 开始----
            $.ajax({
                success:function(res2){


                    //----请求C 开始---
                    $.ajax({
                        success:function(res3){
                        }
                    });
                    //---请求C 结束---


                }    
            });
            //------请求B 结束-----


        }
    });
    //------请求A 结束---------

上面的案例,假设请求C需要依赖请求B返回的数据,所以,C只能放在B的success函数内;B需要依赖A请求得到的数据作为参数,所以,B只能放在A的success函数内;也就是:请求A包含着请求B,请求B又包含了请求C。 就这样,请求顺序为:请求A -> 请求B -> 请求C,最后你也能顺利的完成了任务。

但是这样有什么缺点呢?

但是这样写,会有一些缺点:

1. 如果存在多个请求操作层层依赖的话,那么以上的嵌套就有可能不止三层那么少了,加上每一层还会有复杂的业务逻辑处理,代码可读性也越来越差,不直观,调试起来也不方便。如果多人开发的时候没有足够的沟通协商,大家的代码风格不一致的话,更是雪上加霜,给后面的维护带来极大的不便。

2. 如果请求C的需要依赖A和B的结果,但是请求A和B缺互相独立,没有依赖关系,以上的实现方式,就使得B必须得到A请求完成后才可以执行,无疑是消耗了更多的等待时间。

来看一个帅气的回调地狱:

 

既然使用这种回调函数层层嵌套(又称:回调地狱)的形式存在缺点,ES6想了办法治它,所以就有了Promise的出现了。 那么我们就知道了:Promise对象能使我们更合理、更规范地进行处理异步操作。

我们先来看看语法:

Promise对象是全局对象,你也可以理解为一个类,创建Promise实例的时候,要有那个new关键字。参数是一个匿名函数,其中有两个参数:resolve和reject,两个函数均为方法。resolve方法用于处理异步操作成功后业务;reject方法用于操作异步操作失败后的业务。

let pro = new Promise(function(resolve,reject){
       var timeOut = Math.random() * 2;

    if(timeOut < 1){
        //调用操作成功方法
        
resolve( '操作成功');
        //状态:pending->fulfilled
    
}else{
        //调用操作异常方法
        
reject( '操作异常');
        //状态:pending->rejected
    
}
});

//用then处理操作成功,catch处理操作异常
pro.then(function (res) {

    //操作成功的处理程序
    
console.log('这个时候可以取到resolve方法里返回的数据'+res)

}).catch(function (error) {

    //操作失败的处理程序
    
console.log("这个时候可以取到reject方法里返回的数据" +error)

});

Promise对象有三种状态: pending:刚刚创建一个Promise实例的时候,表示初始状态; fulfilled:resolve方法调用的时候,表示操作成功; rejected:reject方法调用的时候,表示操作失败; 状态只能从 初始化 -> 成功 或者 初始化 -> 失败,不能逆向转换,也不能在成功fulfilled 和失败rejected之间转换。

promise的优点就是链式调用,我们可以在 then 方法中继续写 Promise 对象并返回,然后继续调用 then 来进行回调操作。

3:常见问题

promise怎么用呢?

4:解决方案

来看这段代码

function test(resolve, reject) {
    var timeOut = Math.random() * 2;
    console.log('set timeout to: ' + timeOut + ' seconds.');
    setTimeout(function () {
        if (timeOut < 1) {
            console.log('call resolve()...');
            resolve('200 OK');
        }
        else {
            console.log('call reject()...');
            reject('timeout in ' + timeOut + ' seconds.');
        }
    }, timeOut * 1000);
}

var p1 = new Promise(test);

p1.then(requestA)
    .then(requestB)
    .then(requestC)
    .catch(requestErr);

function requestA(result) {
    console.log('成功:' + result);
    return "成功了。下一个是B";
}
function requestB(res){
        console.log("上一步的结果:"+res);
        console.log('请求B成功');
        return '请求C,下一个就是你了';

}
function requestC(res){
        console.log("上一步的结果:"+res);
        console.log('请求C成功');

}
function requestErr(result){
        console.log("失败:"+result);
}

案例中,先是创建一个实例,还声明了4个函数,其中三个是分别代表着请求A,请求B,请求C;有了then方法,三个请求操作再也不用层层嵌套了。我们使用then方法,按照调用顺序,很直观地完成了三个操作的绑定,并且,如果请求B依赖于请求A的结果,那么,可以在请求A的程序用使用return语句把需要的数据作为参数,传递给下一个请求,案例中我们就是使用return实现传递参数给下一步操作的。

 

5:编码实战

function cook(){
    console.log('开始做饭。');
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout
(function(){
            console.log('做饭完毕!');
            resolve('鸡蛋炒饭');
        }, 1000);
    });
    return p;
}

//吃饭
function eat(data){
    console.log('开始吃饭:' + data);
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout
(function(){
            console.log('吃饭完毕!');
            resolve('一块碗和一双筷子');
        }, 2000);
    });
    return p;
}
function wash(data){
    console.log('开始洗碗:' + data);
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout
(function(){
            console.log('洗碗完毕!');
            resolve('干净的碗筷');
        }, 2000);
    });
    return p;
}
function end(data){
    console.log(data);
}
cook()
    .then(eat)
    .then(wash)
    .then(end);


// 做饭
function cook(){
    console.log('开始做饭。');
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout
(function(){
            console.log('做饭失败!');
            reject('烧焦的米饭');
        }, 1000);
    });
    return p;
}


cook().catch(function(data){
    console.log(data+"好好吃")
});
console.log(new Date());

let pro1 = new Promise(function(resolve){
    setTimeout(function () {
        resolve('实例1操作成功');
    },5000);
});

6:扩展思考

什么是回调地狱?

由于回调函数是异步的,在上面的代码中每一层的回调函数都需要依赖上一层的回调执行完,所以形成了层层嵌套的关系最终形成类似上面的回调地狱,但代码以此种形式展现时无疑是不利于我们阅读与维护的,此时就要想办法改进这种代码形式。

7:参考文献

MDN Promise

看这一篇就够了!浅谈ES6的Promise对象

8:更多讨论

1:什么是promise all()?

Promise.all( )方法:接受一个数组作为参数,数组的元素是Promise实例对象,当参数中的实例对象的状态都为fulfilled时,Promise.all( )才会有返回。

console.log(new Date());

let pro1 = new Promise(function(resolve){
    setTimeout(function () {
        resolve('实例1操作成功');
    },5000);
});

//创建实例pro2
let pro2 = new Promise(function(resolve){
    setTimeout(function () {
        resolve('实例2操作成功');
    },1000);
});


Promise.all([pro1,pro2]).then(function(result){
    console.log(result);
    console.log(new Date());
});

console.log(new Date());

2:什么是promise race?

Promise.race()方法:它的参数要求跟Promise.all( )方法一样,不同的是,它参数中的promise实例,只要有一个状态发生变化(不管是成功fulfilled还是异常rejected),它就会有返回,其他实例中再发生变化,它也不管了。

3:promise有什么缺点?

因为有一部分老浏览器不支持ES6,所以会有兼容性问题,要谨慎使用

 

 


<think>好的,用户现在问的是“JS中的Promise是什么”,我需要先回顾之前的对话。用户之前问了关于iterator.next的使用,特别是生成器函数和迭代器的控制流程。现在转向Promise,可能需要了解异步处理的另一种机制。 首先,用户可能已经了解生成器和迭代器在处理异步操作中的应用,比如通过yield和next来管理流程。现在他们想知道Promise,这是更常见的异步解决方案,可能想比较两者,或者补充知识。 用户身份可能是刚接触JavaScript的开发者,或者有一定基础但想深入理解异步处理的不同方法。他们可能在实际项目中遇到了回调地狱,想用Promise来优化代码结构,或者学习现代JS特性如async/await的基础。 需要解释Promise的基本概念,核心特点,状态变化,以及如何使用then、catch、finally。可能还要提到链式调用、错误处理,以及与回调函数的对比优势。同时,结合之前的生成器示例,或许可以简要提及async/await和生成器的关系,但重点应在Promise本身。 要确保回答结构清晰,分点说明,有示例代码帮助理解。可能需要覆盖创建Promise、使用then处理成功和失败,catch捕获错误,链式调用的流程,以及常用的静态方法如Promise.all。最后总结适用场景,强调Promise在异步编程中的重要性,以及如何与async/await结合使用。 检查是否有常见的误区需要澄清,比如Promise的执行时机(微任务队列),状态不可逆等。确保示例准确,比如链式调用中值的传递,错误冒泡处理等。可能用户之前接触过回调地狱,所以需要突出Promise如何解决可读性和维护性问题。 最后,保持回答简洁易懂,避免过于技术化的术语,但也要准确。可能需要对比生成器和Promise在处理异步时的不同,但根据用户当前问题,重点还是Promise本身。确保覆盖用户潜在的需求,比如如何将回调转换为Promise,或者处理多个异步任务。</think>### JavaScript 中的 Promise 是什么? **Promise** 是 JavaScript 中处理异步操作的核心对象,用于表示一个异步操作的最终完成(或失败)及其结果值。它解决了传统回调函数(Callback Hell)的嵌套问题,提供了更清晰、可链式调用的异步代码管理方式。 --- ### 核心概念 1. **状态**:Promise 有三种不可逆状态: - **Pending(等待中)**:初始状态,尚未完成或拒绝。 - **Fulfilled(已完成)**:异步操作成功完成,返回结果值。 - **Rejected(已拒绝)**:异步操作失败,返回错误原因。 2. **链式调用**:通过 `.then()` 和 `.catch()` 方法链式处理异步结果,避免回调嵌套。 --- ### 基本用法 #### 1. 创建 Promise ```javascript const promise = new Promise((resolve, reject) => { // 异步操作(如网络请求、定时器等) setTimeout(() => { const success = true; if (success) { resolve("操作成功!"); // 状态变为 Fulfilled } else { reject("操作失败!"); // 状态变为 Rejected } }, 1000); }); ``` #### 2. 处理结果 ```javascript promise .then((result) => { console.log(result); // "操作成功!"(当 resolve 被调用时) }) .catch((error) => { console.error(error); // "操作失败!"(当 reject 被调用时) }); ``` --- ### 关键特性 1. **链式调用**: ```javascript doAsyncTask() .then((result) => processResult(result)) .then((processed) => saveData(processed)) .catch((error) => handleError(error)); ``` - 每个 `.then()` 返回一个新 Promise,可继续链式调用。 - 若链中某一步抛出错误,会直接跳转到最近的 `.catch()`。 2. **错误冒泡**: ```javascript promise .then(step1) .then(step2) .catch((error) => { // 捕获链中任意步骤的错误 }); ``` 3. **静态方法**: - **`Promise.all([promises])`**:所有 Promise 成功时返回结果数组,任一失败立即拒绝。 - **`Promise.race([promises])`**:返回第一个完成(成功或失败)的 Promise 结果。 - **`Promise.resolve(value)`**:直接返回一个已完成的 Promise。 - **`Promise.reject(error)`**:直接返回一个已拒绝的 Promise。 --- ### 示例:网络请求封装 ```javascript function fetchData(url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open("GET", url); xhr.onload = () => { if (xhr.status === 200) { resolve(xhr.response); } else { reject(new Error("请求失败")); } }; xhr.onerror = () => reject(new Error("网络错误")); xhr.send(); }); } // 使用 fetchData("https://api.example.com/data") .then((data) => console.log(data)) .catch((error) => console.error(error)); ``` --- ### 与 async/await 结合 Promise 是 `async/await` 语法的基础,后者是 Promise 的语法糖: ```javascript async function loadData() { try { const data = await fetchData("https://api.example.com/data"); console.log(data); } catch (error) { console.error(error); } } ``` --- ### 总结 - **Promise 是什么**:异步操作的容器,支持链式调用和集中错误处理。 - **解决的问题**:回调地狱、异步代码可读性差、错误难以追踪。 - **适用场景**:网络请求、文件读写、定时任务等异步操作。 - **现代替代方案**:`async/await`(底层仍基于 Promise)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值