个性化阅读
专注于IT技术分析

JavaScript承诺简介

本文概述

承诺是一种最终产生价值的方法。可以将其视为getter函数的异步对应项。你可以通过一个简单的示例了解其工作原理:

promise.then(function(value){
    // Do something with value
});

JavaScript仅在可以进行Ajax调用的意义上是异步的。该代码将停止执​​行, 直到调用返回(成功或其他)为止, 此时回调将同步运行。此时将不会再运行其他代码。

多亏了Promises API, 开发人员能够避免很多回调(仅接受回调或传递回调并不意味着它是异步的)来处理异步交互, 现在可以将其作为任何其他变量来处理。

承诺可以代替异步使用回调, 并且它们提供了一些好处。随着越来越多的库和框架将它们作为处理异步性的主要方法, 它们开始获得发展。自2013年以来, 现代浏览器都原生支持这些承诺。

我为什么要使用诺言

这些承诺将帮助你使所有复杂的异步代码更易于处理, 理解和维护。

承诺与回调聚合无关。那是一个简单的工具。承诺的内容要深得多, 即在同步功能和异步功能之间提供直接对应。

javascript的Promises代表了JavaScript编程的下一个伟大范例, 但是要理解为什么它们如此伟大绝非易事, 请继续阅读。

创造你的第一个诺言

为了理解这个概念, 我们将介绍使用Javascript Promise的最简单方法。

Promise构造函数采用一个参数, 即带有两个参数的回调(函数), 即resolve和reject。现在, 在回调内部, 你需要异步执行所有想要执行的操作, 最后, 如果一切正常, 则调用resolve函数, 否则, 将调用reject(error)函数。

根据以下代码段创建你的第一个承诺:

var myFirstPromise = new Promise(function(resolve, reject){

    // Do an asynchronous task here like a fetch or an ajax call
    // Whatever you want
    // then resolve it or reject it

    var accepted = true;
    
    // add some condition to know which to send (success or error)
    if(accepted){
        resolve("Send this value");
    }else{
        reject("Send this error");
    }
});

myFirstPromise.then(function(successData){
    // Outputs : "Send this value"
    console.info(successData);
}).catch(function(errData){
    // Outputs : "Send this error"
    console.error(errData);
});

所有的Promise实例都有一个then方法, 该方法允许你在实现Promise时做一些事情。 then方法回调将接收由resolve执行提供的结果。

你可以在promise上附加多个然后回调。然后, 每个附加的回调将按照分配它们的顺序连续执行。

唯一的区别是, 在第一个之后, 接收到的每个附加值将是前一个返回的值, 即:

var anyPromise = new Promise(function(resolve, reject){
    resolve("Send this value");
});

anyPromise.then(function(successData){
    // Outputs : "Send this value"
    console.info(successData);
    return "But now, the following then receives this string";
}).then(function(data){
    // Outputs "But now, the ...."
    console.log(data);
    return 1000;
}).then(function(data){
    // Outputs 1000
    console.log(data);
});

当承诺被拒绝执行拒绝时, 将执行catch回调。你甚至可以代替使用catch回调, 而为then函数提供第二个参数。

myFirstPromise.then(function(data) {
    console.log(data);
}, function(err) {
    console.error(err);
});

注意

仅触发1个错误回调, 该函数作为then函数的第二个参数或catch回调, 不会触发两次。

承诺解决与承诺拒绝

有时, 由于不同的原因, 你不需要重复异步任务, 即ajax调用, 它检索某些内容并将其存储在内存中。那就是决心和拒绝开始起作用的时候。

使用这些方法可返回承诺的结果, 而无需使用整个构造函数(实现或拒绝)。

var cacheUserAge = {};

function getUserAge(id){

    // if user id is in the object
    // do not fetch the result from the server
    // return the local result instead
    if(cacheUserAge[id]){
        return Promise.resolve(cacheUserAge[id]);
    }

    // use Promise.reject to trigger the catch callback

    return fetch('api/userage/' + id + '.json')
    .then(function(data) {
        // save it in the object
        cacheUserAge[id] = data;
        // return the value to the next then callback
        return result;
    }).catch(function() {
        throw new Error('Could not get age: ' + id);
    });
}


// Then use it
var userId = 15;

getUserAge(userId).then(function(age){
    alert(age);
});

注意

提取api返回一个promise。

一次兑现多项承诺

Promise API允许你使用Promise.all方法一次解决多个Promise。

Promise.all接受一系列的诺言, 并创建一个诺言, 当所有诺言成功完成时, 诺言就会实现。你将获得与你传递的诺言相同顺序的结果(无论诺言完成了什么)。

var firstPromise = new Promise(function(resolve, reject){
    resolve("First value");
});

var otherPromise = new Promise(function(resolve, reject){
    resolve("Other value");
});

var toFulfill = [firstPromise, otherPromise];

// Outputs ["First value", "Other value"]
Promise.all(toFulfill).then(function(arrOfResults){
    console.info(arrOfResults);
});

注意

将catch回调添加到Promise.all语句中以捕获错误。如果数组中的任何给定的Promise失败, 则不会触发而是捕获回调。

无极种族

是的, 诺言之间的真正竞争。此函数与Promise.all相反, 因为它仅返回已实现的第一个Promise的结果(或拒绝), 其他则将被忽略。

注意:

如果你知道此功能在生产中有多大用处, 请在评论框中分享。

var p1 = new Promise(function(resolve, reject) { 
	setTimeout(function() { resolve('p1!'); }, 5000);
});

var p2 = new Promise(function(resolve, reject) {
	setTimeout(function() { resolve('p2!'); }, 10000);
});

// Let's run
Promise.race([p1, p2]).then(function(winner) {
    // Outputs p1!
	console.log('The winner is: ', winner);
}).catch(function(one, two) {
	console.log('Catch: ', one);
});

跨浏览器支持

自Chrome 32, Opera 19, Firefox 29, Safari 8和Microsoft Edge以来, Promise API就可用了, 默认情况下会启用Promise。

Polyfill

如前所述, API的介绍并未涵盖过时的浏览器, 但有许多可用的polyfill实现。你可以在此处看到最佳承诺的polyfill的前5名。大多数polyfill涵盖了API的所有可能方案, 但是IE9中存在一个限制, 可以使用不同的语法轻松解决该限制。

catch是IE <9中的保留字, 表示promise.catch(func)会引发语法错误。要解决此问题, 可以使用字符串访问属性, 如以下示例所示:

promise['catch'](function(err) {
  // ...
});

// Or just use the second paramer of then instead of using catch
promise.then(undefined, function(err) {
  // ...
});

注意

大多数常见的缩小器已经提供了这种技术, 从而使生成的代码对于旧的浏览器和生产而言都是安全的。但是, 为防止任何可能的不兼容性, 请使用then函数的第二个参数, 而不要使用catch。

开发人员可以使用承诺的许多实现。例如, jQuery的Deferred, Microsoft的WinJS.Promise, when.js, q和dojo.Deferred。但是, 请注意你使用的不是所有标准, 因为jQuery的实现不能像大多数其他实现那样完全满足Promises / A规范。

现在就开始使用诺言, 玩得开心!

赞(0)
未经允许不得转载:srcmini » JavaScript承诺简介

评论 抢沙发

评论前必须登录!