美文网首页
JavaScript的异步线程

JavaScript的异步线程

作者: DramaScript | 来源:发表于2019-01-04 21:39 被阅读11次

异步网络请求

在JavaScript中如何请求服务器,并且异步的回调呢?那就是用AJAX。

'use strict';
function success(text) {
    var textarea = document.getElementById('test-response-text');
    textarea.value = text;
}

function fail(code) {
    var textarea = document.getElementById('test-response-text');
    textarea.value = 'Error code: ' + code;
}

var request;
if (window.XMLHttpRequest) {
    request = new XMLHttpRequest();// 高版本用这个
} else {
    request = new ActiveXObject('Microsoft.XMLHTTP');// 低版本用这个
}

request.onreadystatechange = function () { // 状态发生变化时,函数被回调
    if (request.readyState === 4) { // 成功完成
        // 判断响应结果:
        if (request.status === 200) {
            // 成功,通过responseText拿到响应的文本:
            return success(request.responseText);
        } else {
            // 失败,根据响应码判断失败原因:
            return fail(request.status);
        }
    } else {
        // HTTP请求还在继续...
    }
}

// 发送请求:
request.open('GET', '/api/categories');
request.send();

alert('请求已发送,请等待响应...');
跨域安全限制

默认情况下,JavaScript在发送AJAX请求时,URL的域名必须和当前页面完全一致,完全一致的意思是,域名要相同(www.example.comexample.com不同),协议要相同(http和https不同),端口号要相同(默认是:80端口,它和:8080就不同)。有的浏览器口子松一点,允许端口不同,大多数浏览器都会严格遵守这个限制。
那是不是用JavaScript无法请求外域(就是其他网站)的URL了呢?方法还是有的,大概有这么几种:

  • 通过Flash插件发送HTTP请求,这种方式可以绕过浏览器的安全限制,但必须安装Flash,并且跟Flash交互。不过Flash用起来麻烦,而且现在用得也越来越少了。
  • 通过在同源域名下架设一个代理服务器来转发,JavaScript负责把请求发送到代理服务器:
  • 第三种方式称为JSONP,它有个限制,只能用GET请求,并且要求返回JavaScript。这种方式跨域实际上是利用了浏览器允许跨域引用JavaScript资源
  • 如果浏览器支持HTML5,那么就可以一劳永逸地使用新的跨域策略:CORS了
Promise

比如我们执行一个网络请求:

request.onreadystatechange = function () {
    if (request.readyState === 4) {
        if (request.status === 200) {
            return success(request.responseText);
        } else {
            return fail(request.status);
        }
    }
}

那么如果写成这样:

var ajax = ajaxGet('http://...');
ajax.ifSuccess(success)
    .ifFail(fail);

这种链式写法的好处在于,先统一执行AJAX逻辑,不关心如何处理结果,然后,根据结果是成功还是失败,在将来的某个时候调用success函数或fail函数。古人云:“君子一诺千金”,这种“承诺将来会执行”的对象在JavaScript中称为Promise对象。下面一个Promise的使用示例:

// 生成一个0-2之间的随机数,如果小于1,则等待一段时间后返回成功,否则返回失败
function test(resolve, reject) {
    var timeOut = Math.random() * 2;
    log('set timeout to: ' + timeOut + ' seconds.');
    setTimeout(function () {
        if (timeOut < 1) {
            log('call resolve()...');
            resolve('200 OK');
        }
        else {
            log('call reject()...');
            reject('timeout in ' + timeOut + ' seconds.');
        }
    }, timeOut * 1000);
}

// 变量p1是一个Promise对象,它负责执行test函数。由于test函数在内部是异步执行的,当test函数执行成功时,我们告诉Promise对象:
var p1 = new Promise(test);
var p2 = p1.then(function (result) {
    console.log('成功:' + result);
});
// 当test函数执行失败时,我们告诉Promise对象:
var p3 = p2.catch(function (reason) {
    console.log('失败:' + reason);
});

Promise还可以做更多的事情,比如,有若干个异步任务,需要先做任务1,如果成功后再做任务2,任何任务失败则不再继续并执行错误处理函数。下面的例子演示了如何串行执行一系列需要异步计算获得结果的任务:

'use strict';

var logging = document.getElementById('test-promise2-log');
while (logging.children.length > 1) {
    logging.removeChild(logging.children[logging.children.length - 1]);
}

function log(s) {
    var p = document.createElement('p');
    p.innerHTML = s;
    logging.appendChild(p);
}

// 0.5秒后返回input*input的计算结果:
function multiply(input) {
    return new Promise(function (resolve, reject) {
        log('calculating ' + input + ' x ' + input + '...');
        setTimeout(resolve, 500, input * input);
    });
}

// 0.5秒后返回input+input的计算结果:
function add(input) {
    return new Promise(function (resolve, reject) {
        log('calculating ' + input + ' + ' + input + '...');
        setTimeout(resolve, 500, input + input);
    });
}

var p = new Promise(function (resolve, reject) {
    log('start new Promise...');
    resolve(123);
});

p.then(multiply)
 .then(add)
 .then(multiply)
 .then(add)
 .then(function (result) {
    log('Got value: ' + result);
});

除了串行执行若干异步任务外,Promise还可以并行执行异步任务。

var p1 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 600, 'P2');
});
// 同时执行p1和p2,并在它们都完成后执行then:
Promise.all([p1, p2]).then(function (results) {
    console.log(results); // 获得一个Array: ['P1', 'P2']
});

有些时候,多个异步任务是为了容错。比如,同时向两个URL读取用户的个人信息,只需要获得先返回的结果即可。这种情况下,用Promise.race()实现

var p1 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 600, 'P2');
});
Promise.race([p1, p2]).then(function (result) {
    console.log(result); // 'P1'
});

相关文章

  • 同步与异步、事件循环与消息队列、微任务与宏任务

    JavaScript 是单线程、异步、非阻塞、解释型脚本语言。 单线程与多线程 单线程语言:JavaScript ...

  • Javascript 小解读

    Javascript 概念 Javascript 是单线程、非阻塞、异步的解释型脚本语言。 Javascript ...

  • Express异步

    1、前言 在 Javascript 的世界里,异步(由于JavaScript的单线程运行,所以JavaScript...

  • JavaScript(ES6) - Async

    异步编程对JavaScript语言太重要。Javascript语言的执行环境是“单线程”的,如果没有异步编程,根本...

  • JavaScript执行机制

    概述 为什么javascript是单线程的?为什么需要存在异步任务?JavaScript怎么处理异步任务的?宏任务...

  • 对JS异步编程的探究

    在探究“异步“的时候,我们总会联想到多线程实现异步,那么为什么JavaScript非要弄成单线程,还要实现异步呢?...

  • 异步/回调

    单线程的JavaScript 说起异步,就要先说说JavaScript运行机制。我们知道,JavaScript是单...

  • js任务管理和promise

    任务管理 JavaScript是单线程。JavaScript在处理异步操作时,利用的是事件循环机制。 主线程中的任...

  • ES6(7)之Async和await

    先谈JavaScript的异步处理 JavaScript是一门单线程的编程语言,如果不设计异步处理的机制,很容易因...

  • JavaScript异步问题Generator 函数

    异步问题的产生 JavaScript只有一个线程,要实现复杂的功能异步编程尤为重要JavaScript 语言实现异...

网友评论

      本文标题:JavaScript的异步线程

      本文链接:https://www.haomeiwen.com/subject/iqmafqtx.html