事件循环和任务队列
在 ES6 中,有一个新的概念建立在事件循环队列之上,叫作任务队列(job queue)。这个
概念给大家带来的最大影响可能是 Promise 的异步特性(参见第 3 章).
事件循环队列类似于一个游乐园游戏:玩过了一个游戏之后,你需要重新到队尾排队才能 再玩一次。而任务队列类似于玩过了游戏之后,插队接着继续玩.
回调导致的信任问题
关于回调
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| function useless(callback){ return callback(); } useless(()=>{console.log("callback")}); (function fnA(){ console.log("fnA"); })()
document.body.addEvetListener("mousemove",function(){ })
const fs = require('fs'); fs.readFile('./title.json',(err,data)=>{ if(err) throw err; })
|
交付第三方工具后控制反转
有时候 ajax(..)(也 就是你交付回调 continuation 的第三方)不是你编写的代码,也不在你的直接控制下。多 数情况下,它是某个第三方提供的工具。我们把这称为控制反转(inversion of control),也就是把自己程序一部分的执行控制交给某 个第三方。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| ajax('..',function(..){ });
analytics.trackPurchase(purchaseData, function(){ chargeCreditCard(); displayThankyouPage(); });
|
分析公司的开发者开发了一些实验性的代码,在某种情况下,会在五秒钟内每秒重试一次传入的回调函数,然后才会因超时而失败。
异步开发的难题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
|
setTimeout(function() { console.log('I execute first.'); setTimeout(function() { console.log('I execute next.'); setTimeout(function() { console.log('I execute last.'); }, 100); }, 500); }, 1000);
var fs = require('fs'); var completedTasks = 0; var tasks = []; var wordCounts = {}; var filesDir = './text'; function checkIfComplete() { completedTasks++; if (completedTasks == tasks.length) { for (var index in wordCounts) { console.log(index +': ' + wordCounts[index]); } } } function countWordsInText(text) { var words = text .toString() .toLowerCase() .split(/\W+/) .sort(); for (var index in words) { var word = words[index]; if (word) { wordCounts[word] = (wordCounts[word]) ? wordCounts[word] + 1 : 1; } } } fs.readdir(filesDir, function(err, files) { if (err) throw err; for(var index in files) { var task = (function(file) { return function() { fs.readFile(file, function(err, text) { if (err) throw err; countWordsInText(text); checkIfComplete(); }); } })(filesDir + '/' + files[index]); tasks.push(task); } for(var task in tasks) { tasks[task](); } });
|
Promise
- 特点
- promise异步是基于微任务的 ->回调太晚(等待时间太长)
- promise一旦决议,就永远保持这个状态
- 实用
- 链式回调 ->串行控制
- promise.race ->可以用来处理一直未决议的状况
- promise.all ->并行控制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| const promise = new Promise((resolve, reject) => { resolve("Hattori"); setTimeout(()=> reject("Yoshi"), 500); }); promise.then(val => alert("Success: " + val)) .catch(e => alert("Error: " + e));
upload() { return new Promise(resolve => { Taro.uploadFile({ url: 'https://kstack.test.muxixyz.com/api/v1/upload/image/', filePath: this.state.avatar, name: 'image', formData: { }, header: { token: Taro.getStorageSync('token') }, success(res) { if (res.data) { resolve(JSON.parse(res.data).data.url); } } }); }); } onSubmit() { if (this.state.username == '') { Taro.atMessage({ message: '标题不能为空', type: 'warning' }); return; } this.upload() .then(url => { Fetch( 'api/v1/user/info/', { username: this.state.username, avatar: url }, 'POST' ).then(ress => { if (ress.message == 'OK') Taro.showToast({ title: '修改成功', icon: 'success' }); }); }) .catch(err => { console.error(err); Taro.showToast({ title: '修改失败,请稍后重试', icon: 'fail' }); }); }
|
thenable
具有then()函数的对象,都是promise吗?不是。普通then()与promise产生的then的区别
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| var p = { then: function(cb,errb){ cb(42); errb("evil laugh"); } }; p.then( function fulfilled(val){ console.log(val); }, function rejected(err){ console.log(err); } )
|
Promise与生成器结合
生成器函数是一个崭新的函数类型,它和标准的普通函数完全不同。生成器函数能生成一组值的序列,但是每组值的生产都是基于每次请求,并不同于标准函数那样立即生成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| function *IdGenerator(){ let id = 0; while(true){ yield ++id; } } const idIterator = IdGenerator(); const ninja1 = { id: idIterator.next().value }; assert(ninja1.id === 1, "First ninja has id 1");
function getJSON(url){ return new Promise((resolve, reject) =>{ const request = new XMLHttpRequest(); request.open("GET", url); request.send(); request.onload = function() { try{ if(this.status === 200){ resolve(JSON.parse(this.response)) } } catch(e){ reject(e.message) } } }) } async(function*() { try { const ninjas = yield getJSON("data/ninjas.json"); const missions = yield getJSON(ninjas[0].missionsUrl); } catch(e) { } });
(async function () { try { const ninjas = await getJSON("data/ninjas.json"); const missions = await getJSON(missions[0].missionsUrl); console.log(missions); } catch(e) { console.log("Error: ", e); } })()
|
使用生成器与promise结合,串行化异步操作似乎比promise.then().then()
这种链式回调更美观,可是我没有看到实质上不得不用asnyc,await
的原因。之后再看看……