0

JavaScript Promise 链

 1 year ago
source link: https://www.myfreax.com/promise-chaining/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
JavaScript Promise 链

JavaScript Promise 链

在本教程中,您将了解 JavaScript Promise 链,该模式链接 Promise 并按顺序执行异步操作。

JavaScript Promise 链简介

有时,您想执行两个或多个异步的操作,其中下一个操作从上一步的结果开始。例如:

首先,创建一个在 3 秒获得数字 10 的 Promise:

let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(10);
    }, 3 * 100);
});
请注意,这里使用 setTimeout() 函数模拟异步操作。

然后,调用 promise 的 then() 方法:

p.then((result) => {
    console.log(result);
    return result * 2;
});

一旦 promise 得到解决,传递给 then() 方法的回调就会执行。在回调中,我们显示promise 的结果并返回一个乘以二 result*2 的值。

因为 then() 方法返回一个 Promise 与一个值,所以您可以像这样在返回 Promise 时调用 then() 方法:

let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(10);
    }, 3 * 100);
});

p.then((result) => {
    console.log(result);
    return result * 2;
}).then((result) => {
    console.log(result);
    return result * 3;
});

在此示例中,第一个 then() 方法中的返回值被传递给第二个 then() 方法。您可以连续调用 then() 方法多次,如下所示:

let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(10);
    }, 3 * 100);
});

p.then((result) => {
    console.log(result); // 10
    return result * 2;
}).then((result) => {
    console.log(result); // 20
    return result * 3;
}).then((result) => {
    console.log(result); // 60
    return result * 4;
});

我们这样调用 then() 方法的方式通常被称为 Promise 链。

下图说明 Promise 链:

JavaScript-Promise-Chaining.webp

Promise 多个处理程序

当您对一个 Promise 多次调用 then() 方法时,这不是 Promise 链。例如:

let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(10);
    }, 3 * 100);
});

p.then((result) => {
    console.log(result); // 10
    return result * 2;
})

p.then((result) => {
    console.log(result); // 10
    return result * 3;
})

p.then((result) => {
    console.log(result); // 10
    return result * 4;
});

在这个例子中,我们有一个 Promise 的多个处理程序。这些处理程序没有任何关系。此外,它们独立执行,不会像上面的 Promise 链那样将结果从一个传递到另一个。

下图说明具有多个处理程序的 Promise:

实际上,您很少会为一个 promise 使用多个处理程序。

返回 Promise

当您在 then() 方法中返回一个值时,then() 方法会返回一个 Promise  并立即将返回值解析为新值。

此外,您可以在 then() 方法中返回一个新的 Promise,如下所示:

let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(10);
    }, 3 * 100);
});

p.then((result) => {
    console.log(result);
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(result * 2);
        }, 3 * 1000);
    });
}).then((result) => {
    console.log(result);
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(result * 3);
        }, 3 * 1000);
    });
}).then(result => console.log(result));

此示例每 3 秒显示 10、20 和 60。此代码模式允许您按顺序执行一些任务。

下面修改上面的例子:

function generateNumber(num) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(num);
    }, 3 * 1000);
  });
}

generateNumber(10)
  .then((result) => {
    console.log(result);
    return generateNumber(result * 2);
  })
  .then((result) => {
    console.log(result);
    return generateNumber(result * 3);
  })
  .then((result) => console.log(result));

Promise 链接语法

有时,您有多个要按顺序执行异步任务。此外,还需要将上一步的结果传递给下一步。在这种情况下,您可以使用以下语法:

step1()
    .then(result => step2(result))
    .then(result => step3(result))
    ...

如果需要先运行上一个任务而不传递结果给下一个任务,则可以使用以下语法:

step1()
    .then(step2)
    .then(step3)
    ...

假设你想按顺序执行以下异步操作:

  • 首先,从数据库中获取用户。
  • 其次,获取所选用户的服务。
  • 最后,从用户的服务中计算服务成本。

以下函数说明三个异步操作:

function getUser(userId) {
    return new Promise((resolve, reject) => {
        console.log('Get the user from the database.');
        setTimeout(() => {
            resolve({
                userId: userId,
                username: 'admin'
            });
        }, 1000);
    })
}

function getServices(user) {
    return new Promise((resolve, reject) => {
        console.log(`Get the services of ${user.username} from the API.`);
        setTimeout(() => {
            resolve(['Email', 'VPN', 'CDN']);
        }, 3 * 1000);
    });
}

function getServiceCost(services) {
    return new Promise((resolve, reject) => {
        console.log(`Calculate the service cost of ${services}.`);
        setTimeout(() => {
            resolve(services.length * 100);
        }, 2 * 1000);
    });
}

以下使用 promise 来进行顺序运行任务:

getUser(100)
    .then(getServices)
    .then(getServiceCost)
    .then(console.log);
Get the user from the database.
Get the services of admin from the API.
Calculate the service cost of Email,VPN,CDN.
300
请注意,ES2017 引入 async/await 可帮助您编写比使用 promise 链技术更清晰的代码。

在本教程中,您了解了按顺序执行多个异步任务的 promise 链。

微信公众号

支付宝打赏

myfreax 淘宝打赏

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK