JavaScript Promise API

JavaScript Promise API很棒,但是可以通过asyncawait变得惊人!

尽管同步代码更易于跟踪和调试,但异步通常在性能和灵活性方面更好。 当您一次触发多个请求,然后在每个请求准备就绪时处理它们时,为什么要“暂缓演出”呢? 承诺正成为JavaScript世界的重要组成部分,许多新的API都以promise理念实现。 让我们来看看Promise,API及其用法!

在野外的应许

当XMLHttpRequest API是异步,但使用承诺API。 但是,现在有一些本机API使用Promise:

  • 电池API
  • 提取API (XHR的替代品)
  • ServiceWorker API(即将发布帖子!)

承诺只会变得更加普遍,因此所有前端开发人员都必须习惯它们,这一点很重要。 还值得注意的是,Node.js是Promises的另一个平台(显然,Promise是核心语言功能)。

测试Promise可能比您想象的要容易,因为setTimeout可以用作异步“任务”!

基本承诺用法

new Promise()构造函数应仅用于旧式异步任务,例如setTimeoutXMLHttpRequest用法。 使用new关键字创建一个新的Promise,并且promise为所提供的回调提供resolvereject功能:

var p = new Promise(function(resolve, reject) {
	
	// Do an async task async task and then...

	if(/* good condition */) {
		resolve('Success!');
	}
	else {
		reject('Failure!');
	}
});

p.then(function(result) { 
	/* do something with the result */
}).catch(function() {
	/* error :( */
}).finally(function() {
   /* executes regardless or success for failure */ 
});

开发人员可以根据他们给定任务的结果,在回调的主体中手动调用“ resolve或“ reject 一个现实的例子是将XMLHttpRequest转换为基于promise的任务:

// From Jake Archibald's Promises and Back:
// http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promisifying-xmlhttprequest

function get(url) {
  // Return a new promise.
  return new Promise(function(resolve, reject) {
    // Do the usual XHR stuff
    var req = new XMLHttpRequest();
    req.open('GET', url);

    req.onload = function() {
      // This is called even on 404 etc
      // so check the status
      if (req.status == 200) {
        // Resolve the promise with the response text
        resolve(req.response);
      }
      else {
        // Otherwise reject with the status text
        // which will hopefully be a meaningful error
        reject(Error(req.statusText));
      }
    };

    // Handle network errors
    req.onerror = function() {
      reject(Error("Network Error"));
    };

    // Make the request
    req.send();
  });
}

// Use it!
get('story.json').then(function(response) {
  console.log("Success!", response);
}, function(error) {
  console.error("Failed!", error);
});

有时候,你并不需要完成的承诺中异步任务-如果它可能是一个异步将采取行动,然而,返回承诺将最好的,让您可以随时在承诺未来数给定函数的出。 在这种情况下,您可以简单地调用Promise.resolve()Promise.reject()而不使用new关键字。 例如:

var userCache = {};

function getUserDetail(username) {
  // In both cases, cached or not, a promise will be returned

  if (userCache[username]) {
  	// Return a promise without the "new" keyword
    return Promise.resolve(userCache[username]);
  }

  // Use the fetch API to get the information
  // fetch returns a promise
  return fetch('users/' + username + '.json')
    .then(function(result) {
      userCache[username] = result;
      return result;
    })
    .catch(function() {
      throw new Error('Could not find user: ' + username);
    });
}

由于总是返回承诺,因此您可以始终使用thencatch方法获取其返回值!

然后

所有的Promise实例都有一个then方法,该方法允许您对Promise做出React。 然后,第一个then方法回调将接收resolve()调用赋予它的结果:

new Promise(function(resolve, reject) {
	// A mock async action using setTimeout
	setTimeout(function() { resolve(10); }, 3000);
})
.then(function(result) {
	console.log(result);
});

// From the console:
// 10

解决承诺后,将触发then回调。 您还可以链接then方法回调:

new Promise(function(resolve, reject) { 
	// A mock async action using setTimeout
	setTimeout(function() { resolve(10); }, 3000);
})
.then(function(num) { console.log('first then: ', num); return num * 2; })
.then(function(num) { console.log('second then: ', num); return num * 2; })
.then(function(num) { console.log('last then: ', num);});

// From the console:
// first then:  10
// second then:  20
// last then:  40

每个then接收前的结果, then的返回值。

如果一个承诺已经解决,但then再次被调用时,回调将立即触发。 如果承诺被拒绝和你打电话then拒绝后,回调不会被调用。

抓住

当承诺被拒绝时,执行catch回调:

new Promise(function(resolve, reject) {
	// A mock async action using setTimeout
	setTimeout(function() { reject('Done!'); }, 3000);
})
.then(function(e) { console.log('done', e); })
.catch(function(e) { console.log('catch: ', e); });

// From the console:
// 'catch: Done!'

您提供给reject方法的取决于您自己。 常见的模式是将Error发送给catch

reject(Error('Data could not be found'));

最后

无论成功与否,都会调用新引入的finally回调:

(new Promise((resolve, reject) => { reject("Nope"); }))
    .then(() => { console.log("success") })
    .catch(() => { console.log("fail") })
    .finally(res => { console.log("finally") });

// >> fail
// >> finally

Promise.all

考虑一下JavaScript加载器:有时候您会触发多个异步交互,但只想在所有异步交互完成后才进行响应-这就是Promise.all进入的地方Promise.all方法采用一组promises并触发一次回调他们都解决了:

Promise.all([promise1, promise2]).then(function(results) {
	// Both promises resolved
})
.catch(function(error) {
	// One or more promises was rejected
});

考虑Promise.all一种完美方法是一次触发多个AJAX(通过fetch )请求:

var request1 = fetch('/users.json');
var request2 = fetch('/articles.json');

Promise.all([request1, request2]).then(function(results) {
	// Both promises done!
});

您可以结合使用fetch和Battery API之类的API,因为它们都返回承诺:

Promise.all([fetch('/users.json'), navigator.getBattery()]).then(function(results) {
	// Both promises done!
});

当然,处理拒绝是很难的。 如果任何承诺被拒绝,则第一个拒绝的catch触发:

var req1 = new Promise(function(resolve, reject) { 
	// A mock async action using setTimeout
	setTimeout(function() { resolve('First!'); }, 4000);
});
var req2 = new Promise(function(resolve, reject) { 
	// A mock async action using setTimeout
	setTimeout(function() { reject('Second!'); }, 3000);
});
Promise.all([req1, req2]).then(function(results) {
	console.log('Then: ', results);
}).catch(function(err) {
	console.log('Catch: ', err);
});

// From the console:
// Catch: Second!

随着越来越多的API向Promise.all将超级有用。

Promise.race

Promise.race是一个有趣的函数Promise.race无需等待所有诺言被解决或拒绝, Promise.race在阵列中的任何诺言被解决或拒绝后Promise.race触发:

var req1 = new Promise(function(resolve, reject) { 
	// A mock async action using setTimeout
	setTimeout(function() { resolve('First!'); }, 8000);
});
var req2 = new Promise(function(resolve, reject) { 
	// A mock async action using setTimeout
	setTimeout(function() { resolve('Second!'); }, 3000);
});
Promise.race([req1, req2]).then(function(one) {
	console.log('Then: ', one);
}).catch(function(one, two) {
	console.log('Catch: ', one);
});

// From the console:
// Then: Second!

用例可能会触发对主要来源和次要来源的请求(如果主要来源或次要来源不可用)。

习惯承诺

在过去的几年中(或者,如果您是Dojo Toolkit用户,则是过去的十年),承诺一直是一个热门话题,并且它们已经从JavaScript框架模式变成了语言的主要内容。 假设您将看到大多数新JavaScript API正在使用基于承诺的模式来实现,这可能是明智的……

...那真是太好了! 开发人员可以避免回调地狱,并且可以像其他任何变量一样传递异步交互。 承诺需要一些时间来适应这些工具(本地),现在是时候学习它们了!

翻译自: https://davidwalsh.name/promises

你可能感兴趣的:(js,javascript,ajax,vue,callback)